<script setup lang="ts">
import * as Plotly from 'plotly.js-dist-min'
import { Figure, FigureData } from '../grpc/figure'
import { FigureServiceClient } from '../grpc/figure.client'
import { GrpcWebFetchTransport } from '@protobuf-ts/grpcweb-transport'
import { host } from '../connect'
import { onMounted, ref } from 'vue'
import { onBeforeUnmount } from 'vue'
import { computed } from 'vue'

const { figure, paused = false } = defineProps<{ figure: Figure; paused?: boolean }>()
const cancel = ref<boolean>(false)

function reshape(data: number[], width: number) {
  if (data.length % width != 0) {
    throw new Error('Data length is not divisible by width')
  }
  const height = data.length / width
  const result: number[][] = new Array(height)
  for (let i = 0; i < height; i++) {
    result[i] = data.slice(i * width, (i + 1) * width)
  }
  return result
}

const data = ref<FigureData | null>(null)
const plotData = computed(() => {
  if (data.value) {
    switch (data.value.figure.oneofKind) {
      case 'line':
        return data.value.figure.line.lines.map((line) => ({
          x: line.x.length == 0 ? undefined : line.x,
          y: line.y,
          type: 'scatter' as const,
          name: line.label,
          color: line.color ? line.color : undefined,
        }))
      case 'heatmap':
        const xmin = data.value.figure.heatmap.xMin ?? 0
        const xmax = data.value.figure.heatmap.xMax ?? data.value.figure.heatmap.width
        const ymin = data.value.figure.heatmap.yMin ?? 0
        const ymax = data.value.figure.heatmap.yMax ?? data.value.figure.heatmap.height
        const x = Array(data.value.figure.heatmap.width)
          .fill(0)
          .map((_, i) => xmin + ((xmax - xmin) * i) / data.value.figure.heatmap.width)
        const y = Array(data.value.figure.heatmap.height)
          .fill(0)
          .map((_, i) => ymin + ((ymax - ymin) * i) / data.value.figure.heatmap.height)
        return [
          {
            z: reshape(data.value.figure.heatmap.data, data.value.figure.heatmap.width),
            x: x,
            y: y,
            type: 'heatmap' as const,
            colorscale: 'Blues',
            reversescale: true,
          },
        ]
      case 'histogram':
        const bin_start = data.value.figure.histogram.bins.slice(0, -1)
        const bin_end = data.value.figure.histogram.bins.slice(1)
        const bin_center = bin_start.map((start, i) => (start + bin_end[i]) / 2)
        const bin_width = bin_start.map((start, i) => bin_end[i] - start)
        console.log('Histogram data:', bin_center, bin_width)
        console.log(
          'Sizes:',
          bin_center.length,
          bin_width.length,
          data.value.figure.histogram.data.length,
        )
        return data.value.figure.histogram.data.map((series) => ({
          x: bin_center,
          y: series.data,
          width: bin_width,
          type: 'bar' as const,
        }))
    }
  }
  return []
})

const layout = {
  title: { text: figure.title },
  xaxis: { title: { text: figure.xLabel }, type: figure.logx ? 'log' : undefined },
  yaxis: { title: { text: figure.yLabel }, type: figure.logy ? 'log' : undefined },
  height: 700,
}

function updateGraph() {
  console.log('Updating graph with', plotData.value)
  Plotly.newPlot(figure.uuid, plotData.value, layout, { responsive: true })
}

onMounted(async () => {
  console.log('Mounted')

  updateGraph()

  const transport = new GrpcWebFetchTransport({ baseUrl: host })
  const figureService = new FigureServiceClient(transport)
  const stream = figureService.getFigureUpdate({ uuid: figure.uuid })
  for await (const response of stream.responses) {
    if (cancel.value) {
      console.log('Stopping stream...')
      break
    }
    console.log(`Got new value for ${figure.uuid}:`, response)

    if (!paused) {
      data.value = response
      updateGraph()
    }
  }
})

onBeforeUnmount(() => {
  console.log('Component is about to unmount, stopping stream...')
  cancel.value = true
})
</script>

<template>
  <v-row class="w-100">
    <v-col cols="12">
      <v-card class="w-100">
        <v-card-title>{{ figure.title }}</v-card-title>
        <v-card-text>
          <div :id="figure.uuid" class="w-100" />
        </v-card-text>
      </v-card>
    </v-col>
  </v-row>
</template>
