<template>
  <div>
    <v-data-table :headers="datatableHeaders" :items="orders" item-value="id"
                  :show-select="false" :show-expand="true" v-model="selected" select-strategy="single"
                  :row-props="rowPropsHandler" :hover="true"
    >
      <template v-slot:item.startTime="{ value }">{{ timestampString(value) }}</template>
      <template v-slot:item.input="{ item }">
        <span v-if="item.order.amountIsInput">
          <span v-if="item.state > OrderState.Signing">
            <suspense>
              <pulse :touch="item.filledIn">
                <token-amount :chain-id="item.chainId" :addr="item.order.tokenIn" :amount="item.filledIn" :raw="true"/>
              </pulse>
            </suspense>
            /
          </span>
          <suspense>
            <token-amount :chain-id="item.chainId" :addr="item.order.tokenIn" :amount="item.order.amount" :raw="true"/>
          </suspense>
        </span>
        <span v-else>
          <suspense>
            <pulse :touch="item.filledIn">
              <token-amount :chain-id="item.chainId" :addr="item.order.tokenIn" :amount="item.filledIn" :raw="true"/>
            </pulse>
          </suspense>
        </span>
        <suspense>
          <token-symbol :addr="item.order.tokenIn"/>
        </suspense>
      </template>
      <template v-slot:item.output="{ item }">
        <span v-if="!item.order.amountIsInput">
          <span v-if="item.state > OrderState.Signing">
            <suspense>
              <pulse :touch="item.filledOut">
                <token-amount :chain-id="item.chainId" :addr="item.order.tokenOut" :amount="item.filledOut" :raw="true"/>
              </pulse>
            </suspense>
            /
          </span>
          <suspense>
            <token-amount :chain-id="item.chainId" :addr="item.order.tokenOut" :amount="item.order.amount" :raw="true"/>
          </suspense>
        </span>
        <span v-else>
          <suspense>
            <pulse :touch="item.filledOut">
              <token-amount :chain-id="item.chainId" :addr="item.order.tokenOut" :amount="item.filledOut" :raw="true"/>
            </pulse>
          </suspense>
        </span>
        <suspense>
          <token-symbol :addr="item.order.tokenOut"/>
        </suspense>
      </template>
<!--
      <template v-slot:item.remaining="{ item }">
        <suspense>
          <token-amount :addr="item.amountToken" :amount="item.remaining"/>
        </suspense>
      </template>
      <template v-slot:item.filled="{ item }">
        <suspense>
          <token-amount :addr="item.amountToken" :amount="item.filled"/>
        </suspense>
      </template>
-->
      <template v-slot:item.avg="{ item }">
        <suspense>
          <pair-price :base="item.order.tokenIn" :quote="item.order.tokenOut" :value="item.avg" :show-btn="true"/>
        </suspense>
      </template>
      <template v-slot:item.state="{ item }">
        <v-chip v-if="item.state===OrderState.Open" class="d-none d-lg-inline-flex" prepend-icon="mdi-dots-horizontal"
                color="green">Open
        </v-chip>
        <btn v-if="isOpen(item.state)" class="d-none d-sm-inline-flex" icon="mdi-cancel" color="red"
             @click="cancelOrder(vaultAddr,item.index)">Cancel
        </btn>
        <btn v-if="isOpen(item.state)" class="d-sm-none" variant="plain" icon="mdi-cancel" color="red"
             @click="cancelOrder(vaultAddr,item.index)"/>
        <v-chip v-if="item.state===OrderState.Canceled" prepend-icon="mdi-cancel" color="red">Canceled</v-chip>
        <v-chip v-if="item.state===OrderState.Filled" prepend-icon="mdi-check-circle-outline" color="green">Completed
        </v-chip>
        <v-chip v-if="item.state===OrderState.Expired" prepend-icon="mdi-progress-check" color="grey-darken-1">Partial
        </v-chip>
            <v-chip v-if="item.state===OrderState.Underfunded" prepend-icon="mdi-alert" color="warning">Underfunded
              <v-tooltip :text="`This order is underfunded. Add more ${item.inSymbol} to your vault.`" location="top" activator="parent"></v-tooltip>
            </v-chip>
        <v-chip v-if="item.state===OrderState.Error" prepend-icon="mdi-alert" color="error">Error</v-chip>
      </template>
      <template v-slot:expanded-row="{item}">
        <template v-for="(t, i) in item.order.tranches">
          <tr>
            <td class="text-right" colspan="2">
              <div>
                <div class="mx-3" v-if="t.marketOrder && t.rateLimitPeriod === 0">market order</div>
                <div class="mx-3" v-if="t.marketOrder && t.rateLimitPeriod !== 0">DCA {{Math.round(MAX_FRACTION/t.rateLimitFraction)}} parts</div>
                <line-price class="mx-3" v-if="!t.marketOrder"
                            :base="item.base" :quote="item.quote"
                            :b="t.minLine.intercept" :m="t.minLine.slope" :is-breakout="!item.minIsLimit"
                            :show-btn="true"/>
                <line-price class="mx-3" v-if="!t.marketOrder"
                            :base="item.base" :quote="item.quote"
                            :b="t.maxLine.intercept" :m="t.maxLine.slope" :is-breakout="item.minIsLimit"
                            :show-btn="true"/>
              </div>
              <div class="text-right" v-if="item.state===OrderState.Open">
                <div>{{ describeTrancheTime(item, i, true) }}</div>
                <div>{{ describeTrancheTime(item, i, false) }}</div>
              </div>
            </td>
            <td class="text-right">
              <suspense>
              <span v-if="item.state > OrderState.Signing">
                <pulse :touch="item.trancheStatus[i].filledIn">
                  <token-amount :chain-id="item.chainId" :addr="item.order.tokenIn"
                                :amount="item.trancheStatus[i].filledIn" :raw="item.order.amountIsInput"/>
                </pulse>
              </span>
              </suspense>
              <suspense>
              <span v-if="item.order.amountIsInput">
                /
                <token-amount :chain-id="item.chainId" :addr="item.amountToken"
                              :amount="item.order.amount*BigInt(t.fraction)/65535n"/>
              </span>
              </suspense>
            </td>
            <td class="text-right w-33">
              <suspense>
              <span v-if="item.state > OrderState.Signing">
                <pulse :touch="item.trancheStatus[i].filledOut">
                  <token-amount :chain-id="item.chainId" :addr="item.order.tokenOut"
                                :amount="item.trancheStatus[i].filledOut" :raw="!item.order.amountIsInput"/>
                </pulse>
              </span>
              </suspense>
              <suspense>
              <span v-if="!item.order.amountIsInput">
                /
                <token-amount :chain-id="item.chainId" :addr="item.amountToken"
                              :amount="item.order.amount*BigInt(t.fraction)/65535n"/>
              </span>
              </suspense>
            </td>
            <td class="text-right">
              <suspense>
                <pair-price :base="item.order.tokenIn" :quote="item.order.tokenOut" :value="item.trancheStatus[i].avg"
                            :show-btn="false"/>
              </suspense>
            </td>
            <td>{{ item.trancheStatus[i].status }}<!--todo:tranche status--></td>
          </tr>
          <tr>
          </tr>
        </template>
      </template>
    </v-data-table>
  </div>
</template>

<script setup>
import LinePrice from "@/components/LinePrice.vue";
import {useStore} from "@/store/store";
import {computed, defineAsyncComponent, onMounted, onUnmounted, ref, watch} from "vue";
import Btn from "@/components/Btn.vue"
import {cancelOrder, useWalletStore} from "@/blockchain/wallet.js";
import {DISTANT_FUTURE, isOpen, MAX_FRACTION, OrderState} from "@/blockchain/orderlib.js";
import Pulse from "@/components/Pulse.vue";
import {OrderShapes} from "@/charts/ordershapes.js";
import {useChartOrderStore} from "@/orderbuild.js";
import {lookupSymbol, tickerForOrder} from "@/charts/datafeed.js";
import {addSymbolChangedCallback, removeSymbolChangedCallback, setSymbol} from "@/charts/chart.js";
import {uniswapV3AveragePrice} from "@/blockchain/uniswap.js";
import {timestampString} from "@/misc.js";
import {metadataMap} from "@/version.js";

const PairPrice = defineAsyncComponent(()=>import("@/components/PairPrice.vue"))
const TokenAmount = defineAsyncComponent(()=>import('./TokenAmount.vue'))
const TokenSymbol = defineAsyncComponent(()=>import('./TokenSymbol.vue'))

const s = useStore()
const co = useChartOrderStore()
const ws = useWalletStore()
const props = defineProps(['vault'])
const vaultAddr = computed(()=>props.vault?props.vault:s.vault)
const selected = ref([])

// Draw Shapes
watch(selected, async ()=>{
  const statusIndex = {}
  for (const order of orders.value)
    statusIndex[order.id] = order
  const selectedIndex = {}
  const chainId = s.chainId
  for (const id of selected.value) {
    selectedIndex[id] = true
    const status = statusIndex[id];
    if (!(id in orderShapes)) {
      const ticker = tickerForOrder(chainId, status.order)
      const symbol = lookupSymbol(ticker)
      if (co.selectedSymbol.ticker !== ticker) {
        // switch symbol
        deleteOrderShapes()
        await setSymbol(symbol)
      }
      orderShapes[id] = new OrderShapes(symbol, status)
    }
  }
  deleteOrderShapes(selectedIndex)
})

function deleteOrderShapes(keepSet={}) {
  // now delete old shapes
  const keys = [...Object.keys(orderShapes)]
  for (const id of keys) {
    if (!(id in keepSet)) {
      orderShapes[id].delete()
      delete orderShapes[id]
    }
  }
}

const orderShapes = {}

onUnmounted(()=>{
  for (const s of Object.values(orderShapes))
    s.delete()
})

const datatableHeaders = [
  {title: 'Date', align: 'start', key: 'startTime'},
  {title: 'Input', align: 'end', key: 'input'},
  {title: 'Output', align: 'end', key: 'output'},
  {title: 'Avg Price', align: 'end', key: 'avg'},
  {title: 'Status', align: 'end', key: 'state'},
  // {title: '', align: 'end', key: 'action'},
];

const rowPropsHandler = ({ item }) => ({
  class: selected.value.indexOf(item.id) !== -1 ? 'selected-row' : '',
  onClick: () => {
    if (selected.value.indexOf(item.id) === -1)
      selected.value = [item.id]
    else
      selected.value = []
  },
})

const orders = computed(()=>{
  // example twap
  // status = [
  //   [ order
  //     "0x52412507302F6bAB17f56370b6a8F304CbB30Ce1", in token
  //     "0x63e187162a4c33A4D14465eA3859fFe423647710", out token
  //     [1, 500], route
  //     "100000000", amount
  //     "1000000", min amount
  //     false, amount is input
  //     false, output to owner
  //     18446744073709552000,  chain order
  //     [ tranches
  //       [21845,    fraction
  //       true,      start time relative
  //       true,      end time relative
  //       false,     min is barrier
  //       false,     max is barrier
  //       false,     market order
  //       0,         minIsRatio
  //       0,         maxIsRatio
  //       false,     _reserved7
  //       0,         rateLimitFraction
  //       0,         rateLimitPeriod
  //       0,         start time
  //       20,        end time
  //       [730643660, 0], [min intercept, slope]
  //       [0, 0],         [max intercept, slope]
  //       ],
  //     ]
  //   ],
  //   4,                state
  //   1701809053,       started at
  //   null,             oco group
  //   "0",              filled in
  //   "0",              filled out
  //   [...],            trancheStatus
  // ]
  const result = []

  // in-flight orders
  for (const pend of ws.pendingOrders) {
    console.log('pended order', pend)
    result.push({
      chainId: pend.chainId,
      id: pend.id,
      startTime: pend.placementTime,
      order: pend.order,
      filled: 0,
      state: pend.state,
      amountToken: pend.order.amountIsInput ? pend.order.tokenIn : pend.order.tokenOut
    })
  }

  // historical orders
  const vault = vaultAddr.value;
  if( vault in s.orders ) {
    for (const [index, status] of Object.entries(s.orders[vault]).reverse()) {
      // const st = {...status}
      // const o = {...st.order}
      const st = status
      const o = st.order
      st.order = o
      // console.log('order status', st)
      result.push(st)
      st.id = `${vault}|${index}`
      st.index = parseInt(index)
      // st.startTime = timestampString(st.startTime)
/*
      o.tranches = o.tranches.map((tranche)=>{
        const t = {...tranche}
        // t.startTime = t.startTimeIsRelative ? intervalString(t.startTime) : timestampString(t.startTime)
        // t.endTime = t.endTimeIsRelative ? intervalString(t.endTime) : timestampString(t.endTime)
        return t
      })
*/
      st.filled = o.amountIsInput ? st.filledIn : st.filledOut
      const fee = st.order.route.fee;
      if(st.filled === 0n)
        st.avg = null
      else
        st.avg = uniswapV3AveragePrice(status.filledIn, status.filledOut, fee)
      st.amountToken = o.amountIsInput ? o.tokenIn : o.tokenOut
      st.input = o.amountIsInput ? o.amount : 0
      st.output = !o.amountIsInput ? o.amount : 0
      st.remaining = o.amount - st.filled
      st.selectable = st.state===OrderState.Open
      for( const ts of st.trancheStatus ) {
        let filledIn = 0n
        let filledOut = 0n
        for( const f of ts.fills ) {
          filledIn += f.filledIn
          filledOut += f.filledOut
        }
        ts.filledIn = filledIn
        ts.filledOut = filledOut
        ts.filled = o.amountIsInput ? filledIn : filledOut
        ts.avg = uniswapV3AveragePrice(filledIn, filledOut, fee)
      }
    }
  }
  // elaborate
  for (const st of result) {
    let low, high;
    // console.log('elab', st.order)
    const o = st.order;
    const buy = o.tokenIn > o.tokenOut;
    if (buy) {
      low = o.tokenOut
      high = o.tokenIn
    }
    else {
      low = o.tokenIn
      high = o.tokenOut
    }
    st.base = o.inverted ? high : low;
    st.quote = o.inverted ? low : high;
    st.minIsLimit = buy === o.inverted // whether limit/breakout is flipped
    const found = metadataMap[st.chainId][o.tokenIn]
    st.inSymbol = found ? found.s : o.tokenIn
    // console.log('elaborated', st)
  }
  result.sort((a,b)=>b.startTime-a.startTime)
  // console.log('orders', result)
  for( const st of result ) {
    if( st.id in orderShapes )
      orderShapes[st.id].update(st)
  }
  return result
})

function describeTrancheTime(st, trancheIndex, isStart) {
  const t = st.order.tranches[trancheIndex]
  const ts = st.trancheStatus[trancheIndex]
  let result = ''
  if( t.minIsBarrier || t.maxIsBarrier )
    return 'barrier'
  const now = s.clock
  if( isStart && ts.activationTime > 0 ) {
    const start = t.startTimeIsRelative ? st.startTime + t.startTime : t.startTime
    result += now < start ? ts.activationTime < now ? 'Rate Limited ' : 'Activates ' : 'Activated '
    result += timestampString(ts.activationTime) + ' '
  }
  if( !isStart && t.endTime < 4294967295 ) {
    const ended = t.endTimeIsRelative ? st.startTime + t.endTime : t.endTime
    result += ended < now ? 'Ended ' : 'Ending '
    result += timestampString(ended)
  }
  return result
}

function symbolChanged() {
  selected.value = []
}

onMounted(()=>addSymbolChangedCallback(symbolChanged))
onUnmounted(()=>removeSymbolChangedCallback(symbolChanged))

</script>

<style scoped lang="scss">
// columns
.num {
  min-width: 1em;
}
.token {
  min-width: 3em;
  max-width: 5em;
}
.pair {
  min-width: 5em;
}
.amount {
  min-width: 3em;
  max-width: 6em;
  overflow-x: hidden;
  text-overflow: ellipsis;
}
.state {
  max-width: 8em;
}
.cancel {
}
</style>

<style lang="scss">
@use "src/styles/settings" as *;

tr.selected-row {
  background-color: #616161;
}
</style>
