<template>
  <rung-builder :name="name" :description="description"
                :order="order" :builder="builder" v-model="endpoints"
                :shape="DLine" :mode="0"
                :get-model-value="getModelValue" :set-model-value="setModelValue"
                :set-values="setLines" :set-weights="setWeights"
                :set-shapes="setShapes"
                :std-width="stdWidth" :build-tranches="buildTranches">
    <table v-if="!co.drawing">
      <tbody>
        <tr>
          <td>&nbsp;</td>
          <td colspan="3">
            <div class="d-flex align-center">
              <v-switch class="d-inline-flex" v-model="extendLeft" inline
                        :true-value="false" :false-value="true"
                        true-icon="mdi-circle-outline" false-icon="mdi-arrow-left"
              />
              <span class="mx-3">Extend</span>
              <v-switch class="d-inline-flex" v-model="extendRight" inline
                        false-icon="mdi-circle-outline" true-icon="mdi-arrow-right"
              />
            </div>
          </td>
        </tr>
        <tr>
          <td class="label" rowspan="2">Line A</td>
          <td>
            <absolute-time-entry v-model="time1A"/>
          </td>
          <td>
            <v-text-field type="number" v-model="price1A" min="0"
                          density="compact" hide-details variant="outlined"
                          class="mx-1 my-2 price"
                          :color="color"
                          label="Price"
            />
          </td>
          <td rowspan="2" class="weight"
              :style="'vertical-align: '+(price2A!==null?'bottom':'center')">
            {{ allocationTexts[weights.length-1] }}
          </td>
        </tr>
        <tr>
          <td>
            <absolute-time-entry v-model="time1B"/>
          </td>
          <td>
            <v-text-field type="number" v-model="price1B" min="0"
                          density="compact" hide-details variant="outlined"
                          class="mx-1 my-2 price"
                          :color="color"
                          label="Price"
            />
          </td>
        </tr>
        <tr v-for="i in innerIndexes" class="ml-5">
          <td class="text-right">&nbsp;</td>
          <td colspan="2" class="text-center">&mdash; Interior Line &mdash;</td>
          <td class="weight">{{ allocationTexts[i] }}</td>
        </tr>
        <tr v-if="weights.length>1">
          <td rowspan="2" class="label">Line B</td>
          <td>
            <absolute-time-entry v-model="time2A"/>
          </td>
          <td>
            <v-text-field type="number" v-model="price2A" min="0"
                          density="compact" hide-details variant="outlined"
                          class="mx-1 my-2 price"
                          :color="color"
                          label="Price"
            />
          </td>
          <td rowspan="2" class="weight" style="vertical-align: top">{{ allocationTexts[0] }}</td>
        </tr>
        <tr v-if="weights.length>1">
          <td>
            <absolute-time-entry v-model="time2B"/>
          </td>
          <td>
            <v-text-field type="number" v-model="price2B" min="0"
                          density="compact" hide-details variant="outlined"
                          class="mx-1 my-2 price"
                          :color="color"
                          label="Price"
            />
          </td>
        </tr>
      </tbody>
    </table>
    <one-time-hint name="click-chart" activator="#tv-widget" location="center"
                   :when="builder.lineA===null && !co.drew" text="Click the chart!"
                   :on-complete="()=>track('click-chart')"
    />
  </rung-builder>
</template>

<script setup>
import {applyLinePoints, builderDefaults, useChartOrderStore} from "@/orderbuild.js";
import {sideColor, toPrecisionOrNull} from "@/misc.js";
import {MAX_FRACTION, newTranche} from "@/blockchain/orderlib.js";
import RungBuilder from "@/components/chart/RungBuilder.vue";
import {computed, ref} from "vue";
import {allocationText, DLine} from "@/charts/shape.js";
import {vectorEquals, vectorInterpolate} from "@/vector.js";
import AbsoluteTimeEntry from "@/components/AbsoluteTimeEntry.vue";
import {useStore} from "@/store/store.js";
import OneTimeHint from "@/components/OneTimeHint.vue";
import {track} from "@/track.js";

const s = useStore()
const co = useChartOrderStore()
const props = defineProps(['order', 'builder'])
const emit = defineEmits(['update:builder'])

function computeDefaultColor() {
  const index = props.order.builders.indexOf(props.builder)
  return sideColor(props.order.buy, index)
}

const defaultColor = computeDefaultColor()
const color = computed(()=>props.builder.color ? props.builder.color : defaultColor)

// Fields must be defined in order to be reactive
builderDefaults(props.builder, {
  lineA: null, // [{time, price}, {time, price}]
  lineB: null,
  extendLeft: false,
  extendRight: true,
  rungs: 1,
  balance: 0,
  breakout: false,
  color: defaultColor,
  buy: true,
})


function buildTranches() {
  const order = props.order
  const builder = props.builder
  const tranches = []
  const warnings = []

  console.log('buildTranches', builder, order, _endpoints.value)
  const la = _endpoints.value[0] // use the flatline format which is a vector of length 4, useful for vectorInterpolate()
  const lb = _endpoints.value[1]
  const ws = weights.value
  const symbol = co.selectedSymbol
  for (let i = 0; i < ws.length; i++) {
    const w = ws[i]
    const t = newTranche({fraction: w * MAX_FRACTION})
    const line = ws.length === 1 ? la : vectorInterpolate(la, lb, i/(ws.length-1))
    const el = extendLeft.value
    const er = extendRight.value
    const reversed = line[0] > line[2]
    if (reversed ? !er : !el)
      t.startTime = reversed ? line[2] : line[0]
    if (reversed ? !el : !er)
      t.endTime = reversed ? line[0] : line[2]
    if (t.endTime <= s.clock)
      warnings.push(`Tranche already expired at ${new Date(t.endTime*1000)}`)

    // console.log('tranche start/end',
    //     t.startTime === DISTANT_PAST ? 'PAST' : t.startTime,
    //     t.endTime === DISTANT_FUTURE ? 'FUTURE' : t.endTime)
    applyLinePoints(t, symbol, order.buy, ...line, builder.breakout)
    tranches.push(t)
  }
  // if( flipped.value )
  //   tranches.reverse()
  return {tranches, warnings}
}


function flattenLine(l) {
  return l === null ? null : [l[0].time, l[0].price, l[1].time, l[1].price]
}


function buildLine(f) {
  // console.log('buildLine', f)
  return f === null ? null : [{time: Number(f[0]), price: Number(f[1])}, {time: Number(f[2]), price: Number(f[3])}]
}

const _endpoints = ref([flattenLine(props.builder.lineA), flattenLine(props.builder.lineB)])
const endpoints = computed({
  get() {
    return _endpoints.value
  },
  set(v) {
    let [a, b] = v
    a = buildLine(a)
    b = buildLine(b)
    update(a, b)
  }
})

const alignTimes = ref(true)

const time1A = computed({
  get() { return _endpoints.value[0] === null ? null : _endpoints.value[0][0] },
  set(v) {
    const flatline0 = _endpoints.value[0];
    update(
        [{time:v, price: flatline0[1]}, {time:flatline0[2], price: flatline0[3]}],
        _endpoints.value[1]
    )
  }
})

const price1A = computed({
  get() { return toPrecisionOrNull(_endpoints.value[0] === null ? null : _endpoints.value[0][1], 6) },
  set(v) {
    const flatline0 = _endpoints.value[0];
    update(
        [{time:flatline0[0], price: Number(v)}, {time:flatline0[2], price: flatline0[3]}],
        _endpoints.value[1]
    )
  }
})

const time1B = computed({
  get() { return _endpoints.value[0] === null ? null : _endpoints.value[0][2] },
  set(v) {
    const flatline0 = _endpoints.value[0];
    update(
        [{time:flatline0[0], price: flatline0[1]}, {time:v, price: flatline0[3]}],
        _endpoints.value[1]
    )
  }
})

const price1B = computed({
  get() { return toPrecisionOrNull(_endpoints.value[0] === null ? null : _endpoints.value[0][3], 6) },
  set(v) {
    const flatline0 = _endpoints.value[0];
    update(
        [{time:flatline0[0], price: flatline0[1]}, {time:flatline0[2], price: Number(v)}],
        _endpoints.value[1]
    )
  }
})

const time2A = computed({
  get() { return _endpoints.value[1] === null ? null : _endpoints.value[1][0] },
  set(v) {
    const flatline = _endpoints.value[1];
    update(
        _endpoints.value[0],
        [{time:v, price: flatline[1]}, {time:flatline[2], price: flatline[3]}],
    )
  }
})

const price2A = computed({
  get() { return toPrecisionOrNull(_endpoints.value[1] === null ? null : _endpoints.value[1][1], 6) },
  set(v) {
    const flatline = _endpoints.value[1];
    update(
        _endpoints.value[0],
        [{time:flatline[0], price: Number(v)}, {time:flatline[2], price: flatline[3]}],
    )
  }
})

const time2B = computed({
  get() { return _endpoints.value[1] === null ? null : _endpoints.value[1][2] },
  set(v) {
    const flatline = _endpoints.value[1];
    update(
        _endpoints.value[0],
        [{time:flatline[0], price: flatline[1]}, {time:v, price: flatline[3]}],
    )
  }
})

const price2B = computed({
  get() { return toPrecisionOrNull(_endpoints.value[1] === null ? null : _endpoints.value[1][3], 6) },
  set(v) {
    const flatline = _endpoints.value[1];
    update(
        _endpoints.value[0],
        [{time:flatline[0], price: flatline[1]}, {time:flatline[2], price: Number(v)}],
    )
  }
})

function update(a, b) { // a and b are lines of two points
  if (!vectorEquals(props.builder.lineA, a) || !vectorEquals(props.builder.lineB, b)) {
    _endpoints.value = [flattenLine(a), flattenLine(b)]
    props.builder.lineA = a
    props.builder.lineB = b
  }
}


let shapeA = null
let shapeB = null

function setShapes(a,b) {
  shapeA = a
  shapeB = b
}


const _extendLeft = ref(true)
const extendLeft = computed({
  get() {return _extendLeft.value},
  set(v) {
    if (v !== _extendLeft.value) {
      _extendLeft.value = v;
      const b = {...props.builder}
      b.extendLeft = v
      // shapeA.setModel({extendLeft: v})
      // shapeB.setModel({extendLeft: v})
      emit('update:builder', b)
    }
  }
})


const _extendRight = ref(true)
const extendRight = computed({
  get() {return _extendRight.value},
  set(v) {
    if (v !== _extendRight.value) {
      _extendRight.value = v;
      const b = {...props.builder}
      b.extendRight = v
      // shapeA.setModel({extendRight: v})
      // shapeB.setModel({extendRight: v})
      emit('update:builder', b)
    }
  }
})


const innerIndexes = computed(() => {
  const n = flatLines.value.length
  const result = []
  for (let i = 1; i < n - 1; i++)
    result.push(n - 1 - i)
  return result
})


// these are set by the RungBuilder
const flatLines = ref([])
const weights = ref([])

function setLines(ls) {
  flatLines.value = ls
}

function setWeights(ws) {
  weights.value = ws
}

const amountSymbol = computed(()=>props.order.amountIsTokenA ? co.selectedSymbol.base.s : co.selectedSymbol.quote.s )

const allocationTexts = computed(()=>weights.value.map((w)=>allocationText(props.order.buy, w, w * props.order.amount, co.selectedSymbol.base.s, amountSymbol.value)))

const stdWidth = computed(()=>[0, co.meanRange, 0, co.meanRange])


function getModelValue(model) {
  // model is the DLine shape's model object
  if (!model.pointA || !model.pointB)
    return null
  if (model.extendLeft !== _extendLeft.value)
    extendLeft.value = model.extendLeft
  if (model.extendRight !== _extendRight.value)
    extendRight.value = model.extendRight
  const result = flattenLine([model.pointA, model.pointB]);
  // console.log('getModelValue', {...model}, result)
  return result // this is the vector the RungBuilder will interpolate
}


function setModelValue(model, value) {
  // const oldModel = {...model};
  // console.log('setModelValue', oldModel, value)
  const oldLine = !model.pointA || !model.pointB ? null : [model.pointA, model.pointB]
  const line = buildLine(value)
  if (dirtyLine(oldLine, line)) {
    if (line===null) {
      model.pointA = null
      model.pointB = null
    }
    else {
      model.pointA = line[0]
      model.pointB = line[1]
    }
  }
  if (model.extendLeft !== _extendLeft.value)
    model.extendLeft = _extendLeft.value
  if (model.extendRight !== _extendRight.value)
    model.extendRight = _extendRight.value
  // console.log('setModelValue end', oldModel, value, model)
}


function dirtyLine(a, b) {
  const result = a === b ? false :
      a === null && b !== null || a !== null && b === null ||
      a[0].time !== b[0].time || a[0].price !== b[0].price || a[1].time !== b[1].time || a[1].price !== b[1].price
  // console.log('dirtyLine', result, a, b)
  return result
}

const name = computed(()=>props.builder.breakout?(props.order.buy?'Breakout':'Breakdown'):'Limit')

const description = computed(()=>{
  const buy = props.order.buy
  const above = buy === props.builder.breakout
  const plural = props.builder.rungs > 1 ? 's' : ''
  return (buy?'Buy ':'Sell ')+(above?'above':'below')+' the line'+(plural?'s':'')
})

</script>

<style scoped lang="scss">
td.weight {
  min-width: 5em;
  max-width: 20em;
  padding-left: 0.5em;
  padding-right: 0.5em;
  text-align: right;
}
td.label {
  $w: 4em;
  width: $w;
  min-width: $w;
  max-width: $w;
  text-align: right;
  padding-right: .5em;
}
.price {
  $w: 6em;
  //width: $w;
  min-width: $w;
  max-width: 10em;
}
</style>
