import { useMemo } from 'react'
import * as echarts from 'echarts'
import ReactECharts from 'echarts-for-react'

import type { BeaconVibrationSample } from '../../../../entities/beacon/model/types'
import type {
  MachineStateDefinition,
  RecognizedMachineStateInterval,
} from '../../../../entities/machine/model/types'
import {
  buildCalibrationTooltip,
  formatCalibrationDateTime,
  getIntervalAtTime,
  getIntervalColor,
  getNearestVibrationSample,
} from './utils'

type MachineCalibrationTimelineChartProps = {
  definitions: MachineStateDefinition[]
  intervals: RecognizedMachineStateInterval[]
  samples: BeaconVibrationSample[]
  tooltipGroupId: string
}

type RectShape = {
  x: number
  y: number
  width: number
  height: number
}

type CustomRenderParams = {
  coordSys: RectShape
}

type CustomRenderApi = {
  value: (index: number) => number
  coord: (value: [number, number]) => [number, number]
  style: () => Record<string, unknown>
}

type TimelineSeriesItem = {
  value: [number, number, number]
  itemStyle: {
    color: string
  }
  meta: RecognizedMachineStateInterval
}

type TimelineTooltipParam = {
  axisValue?: number | string
  data?: TimelineSeriesItem | [number, number]
}

type AxisPointerLabelParam = {
  value: number | string
}

const fontFamily = 'Montserrat Variable, Montserrat, sans-serif'
const fallbackTimelineStart = Date.UTC(2026, 6, 9, 0, 0, 0)

function clipRectByRect(shape: RectShape, rect: RectShape) {
  const x = Math.max(shape.x, rect.x)
  const y = Math.max(shape.y, rect.y)
  const x2 = Math.min(shape.x + shape.width, rect.x + rect.width)
  const y2 = Math.min(shape.y + shape.height, rect.y + rect.height)

  if (x2 < x || y2 < y) return null

  return {
    x,
    y,
    width: x2 - x,
    height: y2 - y,
  }
}

function renderTimelineItem(
  params: CustomRenderParams,
  api: CustomRenderApi,
) {
  const rowIndex = api.value(0)
  const start = api.coord([api.value(1), rowIndex])
  const end = api.coord([api.value(2), rowIndex])
  const height = 22
  const rectShape = clipRectByRect(
    {
      x: start[0],
      y: start[1] - height / 2,
      width: Math.max(1, end[0] - start[0]),
      height,
    },
    {
      x: params.coordSys.x,
      y: params.coordSys.y,
      width: params.coordSys.width,
      height: params.coordSys.height,
    },
  )

  if (!rectShape) return null

  return {
    type: 'rect',
    transition: ['shape', 'style'],
    shape: {
      ...rectShape,
      r: 999,
    },
    style: api.style(),
  }
}

export function MachineCalibrationTimelineChart({
  definitions,
  intervals,
  samples,
  tooltipGroupId,
}: MachineCalibrationTimelineChartProps) {
  const option = useMemo(() => {
    const firstStart = intervals[0]
      ? new Date(intervals[0].startedAt).getTime()
      : fallbackTimelineStart
    const lastInterval = intervals.at(-1)
    const lastEnd = lastInterval
      ? new Date(lastInterval.endedAt).getTime()
      : firstStart + 60 * 60 * 1000
    const rangeMs = Math.max(60 * 60 * 1000, lastEnd - firstStart)
    const padding = Math.min(60 * 60 * 1000, Math.floor(rangeMs * 0.04))
    const data: TimelineSeriesItem[] = intervals.map((interval) => ({
      value: [
        0,
        new Date(interval.startedAt).getTime(),
        new Date(interval.endedAt).getTime(),
      ],
      itemStyle: {
        color: getIntervalColor(interval, definitions),
      },
      meta: interval,
    }))
    const helperData = samples.length > 0
      ? samples.map((sample) => [sample.timeMillis, 0])
      : intervals.flatMap((interval) => [
          [new Date(interval.startedAt).getTime(), 0],
          [new Date(interval.endedAt).getTime(), 0],
        ])

    return {
      animation: true,
      animationDuration: 220,
      textStyle: {
        fontFamily,
        fontWeight: 500,
      },
      tooltip: {
        trigger: 'axis',
        triggerOn: 'mousemove|click',
        axisPointer: {
          type: 'line',
          axis: 'x',
          lineStyle: {
            color: 'rgba(3, 28, 154, 0.35)',
            width: 1,
          },
          label: {
            show: true,
            backgroundColor: '#20263a',
            color: '#ffffff',
            fontFamily,
            formatter: (params: AxisPointerLabelParam) => {
              return formatCalibrationDateTime(Number(params.value))
            },
          },
        },
        borderWidth: 0,
        backgroundColor: '#20263a',
        padding: 12,
        textStyle: {
          color: '#ffffff',
          fontSize: 13,
          fontFamily,
        },
        extraCssText:
          'border-radius: 14px; box-shadow: 0 12px 32px rgba(16, 24, 40, 0.22);',
        transitionDuration: 0,
        formatter: (
          params: TimelineTooltipParam | TimelineTooltipParam[],
        ) => {
          const point = Array.isArray(params) ? params[0] : params
          const timeMillis = Number(point?.axisValue)

          if (!Number.isFinite(timeMillis)) return ''

          const interval = getIntervalAtTime(intervals, timeMillis)
          const sample = getNearestVibrationSample(samples, timeMillis)

          return buildCalibrationTooltip({
            definitions,
            interval,
            sample,
            timeMillis,
          })
        },
      },
      axisPointer: {
        link: [
          {
            xAxisIndex: 'all',
          },
        ],
      },
      grid: {
        left: 28,
        right: 28,
        top: 26,
        bottom: 50,
        height: 92,
      },
      dataZoom: [
        {
          type: 'slider',
          height: 22,
          bottom: 10,
          borderColor: 'transparent',
          backgroundColor: 'rgba(146, 155, 170, 0.12)',
          fillerColor: 'rgba(3, 28, 154, 0.1)',
          showDataShadow: false,
          showDetail: false,
          brushSelect: false,
        },
        {
          type: 'inside',
        },
      ],
      xAxis: {
        type: 'time',
        min: firstStart - padding,
        max: lastEnd + padding,
        axisLabel: {
          color: '#738098',
          fontSize: 12,
          fontFamily,
          hideOverlap: true,
        },
        axisLine: {
          lineStyle: {
            color: 'rgba(146, 155, 170, 0.24)',
          },
        },
        axisTick: {
          show: false,
        },
        splitLine: {
          show: false,
        },
      },
      yAxis: {
        type: 'category',
        inverse: true,
        data: [''],
        axisLabel: {
          show: false,
        },
        axisLine: {
          show: false,
        },
        axisTick: {
          show: false,
        },
        splitLine: {
          show: false,
        },
      },
      series: [
        {
          type: 'custom',
          name: 'Распознанные состояния',
          renderItem: renderTimelineItem,
          encode: {
            x: [1, 2],
            y: 0,
          },
          data,
        },
        {
          type: 'line',
          name: 'Курсор',
          data: helperData,
          symbol: 'none',
          showSymbol: false,
          lineStyle: {
            opacity: 0,
          },
          itemStyle: {
            opacity: 0,
          },
          emphasis: {
            disabled: true,
          },
        },
      ],
    }
  }, [definitions, intervals, samples])

  if (intervals.length === 0) {
    return (
      <div className="machine-chart-empty">
        Нет распознанных состояний за выбранный период
      </div>
    )
  }

  return (
    <div className="machine-calibration-timeline-chart">
      <ReactECharts
        option={option}
        notMerge
        lazyUpdate
        onChartReady={(chart) => {
          chart.group = tooltipGroupId
          echarts.connect(tooltipGroupId)
        }}
        style={{ height: 210 }}
      />
    </div>
  )
}
