<template>
  <!-- todo extract builder-panel --> <!-- :builder="builder" color-tag="limit" -->
    <row-bar :color="builder.color">
      <color-band :color="builder.color"/>
      <div style="min-width: 3em; font-size: larger" :style="colorStyle"
           class="align-self-start ml-2 pt-3">{{ rungs === 1 ? 'Limit' : 'Ladder' }}</div>
      <div>
        <v-text-field type="number" v-model="rungs"
                      density="compact" hide-details class="mx-1 my-2" variant="outlined"
                      label="Rungs"
                      :color="color" :base-color="color" min="1"
                      :disabled="!lineAPrice"
                      style="width: 4.5em;"
        />
      </div>
      <div>
        <div v-if="rungs>1">
          <v-text-field type="number" v-model="lineBPrice" min="0"
                        density="compact" hide-details class="mx-1 my-2" variant="outlined"
                        label="Price"
                        :color="color" :base-color="color"
                        style="flex: 6em"
          />
        </div>
        <v-text-field type="number" v-model="lineAPrice" min="0"
                      density="compact" hide-details class="mx-1 my-2" variant="outlined"
                      label="Price"
                      :color="color" :base-color="color"
                      style="flex: 6em"
        />
      </div>
      <div v-if="rungs>1" class="mx-2 d-flex align-center">
        <v-slider v-if="rungs>1" direction="vertical" min="-100" max="100" v-model="skew100" class="no-slider-bg ml-2 mr-4" hide-details/>
        <v-text-field type="number" v-model="skew100" min="-100" max="100"
                      density="compact" hide-details variant="outlined" label="Skew" step="10"
                      :color="color" :base-color="color">
          <template v-slot:prepend>
            <v-btn icon="mdi-scale-balance" variant="plain" @click="builder.skew=0; adjustShapes()" :color="color"/>
          </template>
        </v-text-field>
      </div>
      <div class="align-self-center">
        <v-menu>
          <template v-slot:activator="{ props }">
            <v-btn variant="plain" v-bind="props" icon="mdi-dots-vertical"/>
          </template>
          <v-list>
            <v-list-subheader :title="'Limit '+ (lineAPrice?lineAPrice.toPrecision(5):'')"/>
            <v-list-item title="Delete" key="withdraw" value="withdraw" prepend-icon="mdi-delete" color="red"
                         @click="deleteBuilder"/>
          </v-list>
        </v-menu>
      </div>
    </row-bar>

    <!--      <v-col>-->
    <!--        <v-btn v-if="!co.drawing" prepend-icon="mdi-ray-vertex" @click="draw" variant="tonal">Draw</v-btn>-->
    <!--        <v-btn v-if="co.drawing" prepend-icon="mdi-ray-vertex" @click="cancelDrawing" variant="tonal">Cancel Drawing</v-btn>-->
    <!--      </v-col>-->
</template>

<script setup>
import {computed, onBeforeUnmount, onMounted, watch} from "vue";
import {chart} from "@/charts/chart.js";
import {useChartOrderStore} from "@/orderbuild.js";
import Color from "color";
import {HLine} from "@/charts/shape.js";
import {builderDefaults, lightenColor2, lineColor} from "@/misc.js";
import {useTheme} from "vuetify";
import {useOrderStore} from "@/store/store.js";
import RowBar from "@/components/chart/RowBar.vue";
import ColorBand from "@/components/chart/ColorBand.vue";

const os = useOrderStore()
const co = useChartOrderStore()
const theme = useTheme().current
const props = defineProps(['order', 'builder'])
const emit = defineEmits(['update:builder'])

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

const defaultColor = computeDefaultColor()

// Fields must be defined in order to be reactive
builderDefaults(props, emit, {
  allocation: 1.0,
  start: null, // todo
  end: null, // todo
  priceA: null,
  priceB: null,
  rungs: 1,
  skew: 0,
  color: defaultColor,
})

const skew100 = computed( {
  get() {return props.builder.skew*100},
  set(v) {props.builder.skew = v/100; adjustShapes()}
} )

// we keep two special control lines as the edge of the ranges and then deletable lines in-between

const lineAPrice = computed({
  get() { return props.builder.priceA },
  set(v) {
    props.builder.priceA = v===null ? v : Number(v)
    adjustShapes()
  }
})

const lineA = new HLine(
    {price:null,color:defaultColor},
    function (line) {props.builder.priceA = line.price; props.builder.color = line.color; adjustShapes()},
    deleteBuilder
)

const lineBPrice = computed({
  get() { return props.builder.priceB },
  set(v) {
    props.builder.priceB = v===null ? v : Number(v)
    adjustShapes()
  }
})

const lineB = new HLine(
    {price:null,color:props.builder.color.value},
    (line)=>{props.builder.priceB = line.price; props.builder.color = line.color; adjustShapes()},
    deleteBuilder
)

const adjustInteriorLine = (line) => {
  props.builder.color = line.color
  adjustShapes()
}

let interiorLines = []

function createInteriorLine(price, lineProps) {
  const line = new HLine({price: price, color: props.builder.color}, adjustInteriorLine, deleteBuilder, lineProps)
  line.onPoints = function (points) {
    const delta = points[0].price - this.model.price
    if (delta !== 0) {
      props.builder.priceA += delta
      props.builder.priceB += delta
      adjustShapes()
    }
  }
  interiorLines.push(line)
  line.create()
}


function removeInteriorLine() {
  if (interiorLines.length) {
    const line = interiorLines.pop()
    line.delete()
  }
}


const color = computed({
  get() {return props.builder.color},
  set(v) {
    const maxLightness = 60
    const c = new Color(v).hsl()
    props.builder.color = c.saturation <= maxLightness ? v : c.lightness(maxLightness).string()
  }
})
const faintColor = computed(() => lightenColor2(color.value))
const colorStyle = computed(() => {
  return {'color': color.value}
})


const start = computed({
  get() {return props.builder.start || 0},
  set(v) {props.builder.start=v; adjustShapes()},
})

const end = computed({
  get() {return props.builder.end || 0},
  set(v) {props.builder.end=v; adjustShapes()},
})

function computeRange() {
  let range = 0
  const series = chart.getSeries()
  const bars = series.data().bars();
  const final = Math.max(bars.size() - 10, 0)
  let count = 0
  for (let barIndex = bars.size() - 1; barIndex >= final; barIndex--) {
    count++
    const [_time, _open, high, low, _close, _volume, _ms] = bars.valueAt(barIndex)
    range += (high - low)
  }
  if (count > 0)
    range /= count
  else
    range = 1
  return range
}

const rungs = computed({
  get() {
    return props.builder.rungs
  },
  set(r) {
    r = Number(r)
    props.builder.rungs = r
    if ( r > 0 && props.builder.priceB === null ) {
      // convert single line to a range
      const range = computeRange()
      const mid = props.builder.priceA
      props.builder.priceA = mid - range/2
      props.builder.priceB = mid + range/2
    }
    else if ( r === 1 && props.builder.priceB !== null ) {
      // convert from a range to a single line
      props.builder.priceA = (props.builder.priceA + props.builder.priceB) / 2
      props.builder.priceB = null
    }
    adjustShapes()
  }
})


const prices = computed(()=>{
  let a = props.builder.priceA
  let b = props.builder.priceB


  const r = props.builder.rungs
  // console.log('prices for', a, b, r)
  if ( a===null || !r ) return []  // no data
  if (r===1) return [a]  // single line
  const spacing = (b-a)/(r-1)
  // console.log('spacing', a, b)
  const result = []
  for( let i=0; i<r; i++ )
    result.push(a+i*spacing)
  return result
})


const weights = computed(() => {
  const r = props.builder.rungs
  const s = -props.builder.skew
  if (r === 1) return [1]
  const result = []
  if (s === 0) {
    for (let i = 0; i < r; i++)
      result.push(1 / r)
  } else if (s === 1) {
    result.push(1)
    for (let i = 1; i < r; i++)
      result.push(0)
  } else if (s === -1) {
    for (let i = 1; i < r; i++)
      result.push(0)
    result.push(1)
  } else {
    for (let i = 0; i < r; i++)
      result.push((1 - s * (2 * i / (r - 1) - 1)) / r)
  }
  return result
})


const colors = computed( ()=> {
  const color = props.builder.color !== null ? props.builder.color
      : props.buy ? theme.value.colors.success : theme.value.colors.error
  const c = new Color(color).rgb()
  const ws = weights.value;
  const max = Math.max(...ws)
  const ns = ws.map((w)=>w/max) // set largest weight to 100%
  const adj = ns.map((w)=>c.alpha(Math.pow(w,0.67))) // https://en.wikipedia.org/wiki/Stevens's_power_law
  return adj.map((a)=>a.string())
})


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


function allocationText(weight) {
  const alloc = props.builder.allocation
  if (alloc===null) return ''
  const w = weight * alloc
  // console.log('weight', weight, alloc, props.amount)
  const a = props.order.amount * w
  return `${(w*100).toFixed(1)}% = ${a.toLocaleString('fullwide')} ${amountSymbol.value}`
}


function adjustShapes() {
  // this is where all the lines are created or adjusted
  console.log('adjustShapes()')

  const limits = prices.value
  const colorStrings = colors.value
  // line properties
  const lps = weights.value.map((w)=>{return {text:allocationText(w), textcolor:color.value, showLabel: true}})  // todo make this label innate to HLine with allocation and amount set in the model
  if( limits.length === 0 ) {
    lineA.delete()
    lineB.delete()
    for( const line of interiorLines )
      line.delete()
    interiorLines = []
  }
  else if (limits.length === 1) {
    //
    // SINGLE LINE
    //
    if (!lineA.beingDragged())
      lineA.setModel({price:limits[0], color: colorStrings[0]}, lps[0])
    lineB.delete()
    if (interiorLines.length) {
      for( const line of interiorLines )
        line.delete()
      interiorLines = []
    }
  }
  else {
    //
    // PRICE RANGE
    //
    if (!lineA.beingDragged())
      lineA.setModel({price:limits[0], color: colorStrings[0]}, lps[0])
    if (!lineB.beingDragged()) {
      const last = colorStrings.length - 1
      lineB.setModel({price: limits[last], color: colorStrings[last]}, lps[last])
    }

    const numInterior = Math.max(0,limits.length-2);
    // trim excess interior lines
    while( interiorLines.length > numInterior )
      removeInteriorLine()

    // adjust the interior line prices and/or add lines
    for( let i=0; i<limits.length-2; i++ ) {
      const limit = limits[1+i]
      if (i === interiorLines.length)
        createInteriorLine(limit, lps[1+i])
      else if (!interiorLines[i].beingDragged())
        interiorLines[i].setModel({price:limit, color: colorStrings[1+i]}, lps[1+i])
    }
  }
  return ''
}


watch(props.order, adjustShapes)
// const autoAdjust = computed(adjustShapes)


function deleteShapes() {
  lineA.delete()
  lineB.delete()
  for (const line of interiorLines)
    line.delete()
  interiorLines = []
}


function deleteBuilder() {
  props.order.builders = props.order.builders.filter((b)=>b!==props.builder)
  deleteShapes()
}


if (!props.builder.priceA)
  lineA.createOrDraw(); // initiate drawing mode

onMounted(adjustShapes)
onBeforeUnmount(deleteShapes)

</script>

<style scoped lang="scss">
:deep(.v-slider.v-input--vertical > .v-input__control) {
  min-height: 5em !important;
}
:deep(.v-slider.no-slider-bg .v-slider-track__fill) {
  background-color: inherit !important;
}
</style>

