<template class="d-flex align-content-center flex-column" style="height: 100%; width: 100%;">
    <builder-panel :order="order" :builder="builder" :build-tranches="buildTranches"
                 :adjust-shapes="adjustShapes" :delete-shapes="deleteShapes" name="DCA">
    <div class="d-flex flex-column" style="width: 100%;">
      <div class="d-flex flex-row mb-5">
        <div class="align-self-center mr-3">Start:</div>
        <absolute-time-entry v-model="startTime"/>
      </div>

      <div class="d-flex flex-row">
        <div>
          <v-text-field label="Split into" type="number" variant="outlined"
                        aria-valuemin="1" aria-valuemax="100" min="1" max="1000" step="1"
                        :hint="partsGasHint" :persistent-hint="true"
                        :color="color"
                        v-model="parts" v-auto-select class="parts mr-3">
            <template v-slot:append-inner>
              parts
            </template>
          </v-text-field>
        </div>

        <div class="mr-3">
          <order-amount :order="props.order" :multiplier="props.builder.tranches" :color="color" style="width: 20em"/>
        </div>

        <div>
          <v-text-field type="number" variant="outlined" :min="1" v-model="displayedInterval" class="interval"
                        :color="color"
                        :label="intervalIsTotal ? 'Total completion time' : 'Time between parts'" v-auto-select>
            <template v-slot:prepend-inner>
              <v-btn variant="outlined"
                     :text="intervalIsTotal ? 'All within' : 'Spaced apart by'" class="within mr-2"
                     style="width: 10em"
                     @click="intervalIsTotal=!intervalIsTotal"/>
            </template>
            <template v-slot:append-inner>
              <v-btn variant="outlined" :text="timeUnitsStr" style="width: 5em"
                     @click="toggleTimeUnits" class="time-units"/>
            </template>
          </v-text-field>
        </div>
      </div>
    </div>
    </builder-panel>
</template>

<script setup>
import {builderDefaults, useChartOrderStore} from "@/orderbuild.js";
import {allocationText, ShapeType} from "@/charts/shape.js";
import {sideColor, SingletonCoroutine, toPrecision, vAutoSelect} from "@/misc.js";
import {useStore} from "@/store/store.js";
import {computed, ref, watchEffect} from "vue";
import {createShape, deleteShapeId, dragging, widget} from "@/charts/chart.js";
import AbsoluteTimeEntry from "@/components/AbsoluteTimeEntry.vue";
import BuilderPanel from "@/components/chart/BuilderPanel.vue";
import {ohlcStart} from "@/charts/chart-misc.js";
import Color from "color";
import OrderAmount from "@/components/chart/OrderAmount.vue";
import {DEFAULT_SLIPPAGE, MAX_FRACTION, newTranche} from "@/blockchain/orderlib.js";
import {getFeeSchedule} from "@/fees.js";
import {NATIVE_TOKEN} from "@/common.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 color = computed(()=>computeDefaultColor())

const defaultTranches = 10

builderDefaults(props.builder, {
  startTime: s.clock, // todo relative 0
  endTime: s.clock + defaultTranches * co.intervalSecs,
  interval: co.intervalSecs,
  tranches: defaultTranches,
  percentage: 100/defaultTranches,
  // relative: true, // todo
  relative: false,
  slippage: DEFAULT_SLIPPAGE,
  color: color.value,
  valid: true,
})

function adjustShapes() {}

function buildTranches() {
  const warnings = []
  let interval = props.builder.interval
  let parts = props.builder.tranches
  if (interval < 60) {
    interval = 60
    parts = (props.builder.endTime - props.builder.startTime) / interval
    warnings.push(`DCA parts cannot be closer than one minute apart. Using ${parts} parts.`)
  }
  const rate = Math.ceil(MAX_FRACTION / parts)
  const endTime = Math.ceil(props.builder.endTime + 10*props.builder.tranches)
  const startTime = Math.floor(props.builder.startTime);
  const tranches = [newTranche({marketOrder:true,
    startTime, endTime, rateLimitFraction: rate, rateLimitPeriod: Math.floor(interval),
    slippage: props.builder.slippage})]
  return {tranches, warnings}
}

const parts = computed({
  get() { return props.builder.tranches },
  set(v) {
    v = Number(v)
    v = Math.max(1, Math.min(1000,v))
    props.builder.tranches = v
    props.builder.endTime = props.builder.startTime + props.builder.interval * v
    setPoints(null, true)
  }
})

const sched = ref(null)
const schedFetcher = new SingletonCoroutine(async (vault)=>sched.value = vault === null ? null : await getFeeSchedule(vault))

const partsGasHint = computed(()=>{
  if (sched.value === null) {
    schedFetcher.invoke(s.vault)
    return null
  }
  const ethFee = Number(sched.value.gasFee) * parts.value / 1e18;
  const mark = s.markPrice(NATIVE_TOKEN)
  if (mark)
    return '$' + Number(ethFee*mark).toFixed(2) + ' gas fee'
  else
    return toPrecision(ethFee) + ' ETH gas fee'
})

const intervalIsTotal = ref(false)
const displayedInterval = computed({
  get() {
    let result = props.builder.interval / timeUnits[timeUnitIndex.value][1]
    if (intervalIsTotal.value)
      // express as per-part intervals
      result *= props.builder.tranches
    return result
  },
  set(v) {
    v = Number(v)
    let newValue = v * timeUnits[timeUnitIndex.value][1];
    if (intervalIsTotal.value)
        newValue /= props.builder.tranches
    if (Math.abs(newValue - props.builder.interval) >= Number.EPSILON) {
      props.builder.interval = newValue
      props.builder.endTime = props.builder.startTime + newValue * props.builder.tranches
      setPoints(null, true)
    }
  }
})

const timeUnits = [['minutes', 60], ['hours', 3600], ['days', 86400]]
function defaultTimeUnit() {
  let i=1
  while( i < timeUnits.length && props.builder.interval >= timeUnits[i][1] )
    i++
  console.log('defaultTimeUnit', props.builder.interval, i-1)
  return i-1
}
const _timeUnitIndex = ref(defaultTimeUnit());
const timeUnitIndex = computed({
  get() {return _timeUnitIndex.value},
  set(v) {_timeUnitIndex.value = v % timeUnits.length}
})
const timeUnitsStr = computed(()=>timeUnits[timeUnitIndex.value][0])

function toggleTimeUnits() {
  timeUnitIndex.value += 1
}

const startTime = computed({
  get() { return props.builder.relative ? s.clock + props.builder.startTime : props.builder.startTime },
  set(v) {emitUpdate({startTime: v})}
})

const endTime = computed({
  get() { return startTime.value + props.builder.interval * props.builder.tranches },
  set(v) {
    emitUpdate({endTime: v, interval: Math.abs(v - startTime.value)})
  }
})


const barStart = computed(()=>ohlcStart(startTime.value, props.builder.interval))
const barEnd = computed(()=>ohlcStart(endTime.value, props.builder.interval))

function emitUpdatedPoints(a, b) {
  const updates = {}
  if (a.time !== barStart.value)
    updates.startTime = a.time
  // only set the end if it was moved relative to the start
  if (b.time - a.time === barEnd.value - barStart.value)
      // the end has moved exactly the same amount as the start. add a relative amount.
    updates.endTime = a.time + (endTime.value - startTime.value)
  else
    updates.endTime = b.time
  updates.interval = (b.time - a.time) / props.builder.tranches
  emitUpdate(updates)
}

function setPoints(points=null, shapeCorrectionNeeded=false) {
  if (points === null)
    points = [{time:props.builder.startTime}, {time:props.builder.endTime}]
  let [a, b] = points
  const period = co.intervalSecs;

  if (b.time < a.time) {
    [a, b] = [b, a]
    shapeCorrectionNeeded = true
  } else if (b.time === a.time) {
    b.time = a.time + period
    shapeCorrectionNeeded = true
  }

  const curBarStart = ohlcStart(s.clock, period);
  if (a.time < curBarStart) {
    const width = b.time - a.time;
    a.time = s.clock
    b.time = a.time + width
    shapeCorrectionNeeded = true
  }
  emitUpdatedPoints(a, b);
  if (shapeCorrectionNeeded) {
    const [sa, sb] = shape.getPoints()
    const aTime = ohlcStart(a.time, period);
    const bTime = ohlcStart(b.time, period);
    if (sa.time !== aTime || sb.time !== bTime) {
      const aa = {time: aTime}
      const bb = {time: bTime}
      shape.setPoints([aa, bb])
    }
  }
}

const callbacks = {
  onDrag(shapeId, shape, points) {
    let [a, b] = points
    if (b.time < a.time)
      [a, b] = [b, a]
    emitUpdatedPoints(a, b)
  },
  onPoints(shapeId, shape, points) {
    setPoints(points, shape);
  },
}

function emitUpdate(changes) {
  for (const [k, v] of Object.entries(changes))
    props.builder[k] = v
}

const text = computed(()=>{
  const o = props.order
  return allocationText(o.buy, 1, o.amount, co.selectedSymbol.base.s,
      o.amountIsTokenA ? null : co.selectedSymbol.quote.s, parts.value, '\n')
})

let shapeId = createShape(ShapeType.DateRange, [{time:barStart.value}, {time:barEnd.value}], {}, callbacks)
let shape = widget.activeChart().getShapeById(shapeId)
function setProperties() {
  const color = computeDefaultColor()
  shape.setProperties({
    extendTop: true,
    extendBottom: true,
    linecolor: color,
    backgroundColor: new Color(color).alpha(0.2).toString(),
    backgroundTransparency: 60,
    customText: {
      text: text.value,
      visible: true,
      color: color,
    },
  })
}
setProperties()

watchEffect(setProperties)

watchEffect(()=>{
  const curBarStart = ohlcStart(s.clock, co.intervalSecs);
  if (curBarStart > barStart.value && !dragging) { // check dragging late to ensure reactivity on bar start
    const delta = curBarStart - props.builder.startTime
    setPoints([{time: props.builder.startTime + delta}, {time: props.builder.endTime + delta}])
  }
})

function deleteShapes() {
  deleteShapeId(shapeId)
}

</script>

<style scoped lang="scss">
td.weight {
  padding-left: 1em;
  padding-right: 1em;
}
.parts {
  width: 10em;
}
.interval {
  width: 22em;
}
</style>

