import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'

import {
  PromDataAccessor,
  PromQueryGroup,
  TimeSeriesChart,
  TimeSeriesChartProps
} from '@diag-ui/chart'
import { Query } from '@diag-ui/chart'
import { ActionIcon, LoadingOverlay, Text, Tooltip } from '@mantine/core'
import { IconChevronLeft, IconChevronRight } from '@tabler/icons-react'
import dayjs from 'dayjs'

import { grafanaQueryRange } from '~/api'
import { OrgType, useCurCluster, useCurOrg } from '~/hooks/state'
import { useListEventGroups } from '~/pages/event-center/shared/api'
import { Severity } from '~/pages/event-center/shared/types'
import { replaceQuery } from '~/pages/reports/shared/utils/promql'
import { clusterDetailTelemetry } from '~/telemetry'

import { TimeRange } from '../../components/TimeWindowSelect'

const ONE_DAY_SECONDS = 24 * 60 * 60
const TWO_DAYS_SECONDS = 2 * ONE_DAY_SECONDS

const qpsChart: { name: string; unit: string; queries: Query[] } = {
  name: 'QPS',
  unit: 'short',
  queries: [
    {
      name: 'total',
      promql: `sum(rate(tidb_executor_statement_total{k8s_cluster="", {label_cluster_id}}[2m]))`,
      type: 'line'
    }
  ]
}

export const QPSChart: React.FC<{
  highlightTimeRange: TimeRange
  onHighlightTimeRangeChange: (newTr: TimeRange) => void
}> = ({ highlightTimeRange, onHighlightTimeRangeChange }) => {
  const { curOrg } = useCurOrg()
  const { curCluster } = useCurCluster()

  const { end } = highlightTimeRange
  const [chartTimeRange, setChartTimeRange] = useState(() => ({
    begin: end - TWO_DAYS_SECONDS,
    end: end + 30 * 60
  }))
  const showPreDayBtn = useMemo(() => {
    return chartTimeRange.begin > curCluster!.created!
  }, [chartTimeRange.begin, curCluster?.created])

  const endTime = curCluster!.endTime!
  const showNextDayBtn =
    endTime === 0
      ? chartTimeRange.end < dayjs().unix()
      : chartTimeRange.end < endTime

  const [loadingMetric, setLoadingMetric] = useState(false)

  const chartRef = useRef<any>(null)

  const highlightAnnotation: TimeSeriesChartProps['annotations'] =
    useMemo(() => {
      return [
        {
          id: 'highlight_region',
          type: 'region',
          start: [highlightTimeRange.start * 1000, 'min'],
          end: [highlightTimeRange.end * 1000, 'max'],
          top: true,
          style: {
            fillOpacity: 0.2
          }
        }
      ]
    }, [highlightTimeRange.start, highlightTimeRange.end])

  const highlightPoints = useRef<any>(null)
  const handleEvent = useCallback(
    (_c: any, e: any) => {
      if (e.type === 'element-range-highlight:afterhighlight') {
        highlightPoints.current = e.data.event.points
      }
      if (
        highlightPoints.current &&
        (e.type === 'mouseup' || e.type === 'dragend')
      ) {
        // the box where draw the lines, not include the x axis and y axis
        // value: {x: 44.69598388671875, y: 6, height: 134, width: 1038.8040161132812}
        const drawBox = e.view.views[0].coordinateBBox

        // scale
        const scaleDefKey = e.view.scalePool.syncScales.get('timestamp')[0]
        const scaleDef = e.view.scalePool.scales.get(scaleDefKey).scaleDef
        const timeDelta = scaleDef.max - scaleDef.min

        const beginPoint = highlightPoints.current[0].x
        const endPoint =
          highlightPoints.current[highlightPoints.current.length - 1].x

        const bTime =
          ((beginPoint - drawBox.x) / drawBox.width) * timeDelta + scaleDef.min
        const eTime =
          ((endPoint - drawBox.x) / drawBox.width) * timeDelta + scaleDef.min

        if (eTime - bTime < 5 * 1000) {
          // if selected time range is less than 5s, ignore it
          return
        }

        const tr = { start: bTime / 1000, end: eTime / 1000 }
        onHighlightTimeRangeChange(tr)
        clusterDetailTelemetry.selectTimeRange(tr)

        // https://g2plot.antv.antgroup.com/api/plot-api#12-addannotations
        chartRef.current.getChart().addAnnotations(
          [
            {
              id: 'highlight_region',
              type: 'region',
              start: [bTime, 'min'],
              end: [eTime, 'max'],
              top: true,
              style: {
                fillOpacity: 0.2
              }
            }
          ],
          chartRef.current.getChart().chart.views[0]
        )

        // reset
        highlightPoints.current = null
      }
    },
    [onHighlightTimeRangeChange]
  )

  const { data: eventGroupsRes } = useListEventGroups({
    timeRange: [chartTimeRange.begin, chartTimeRange.end],
    severity: Severity.Warning
  })
  useEffect(() => {
    if (!eventGroupsRes) {
      return
    }
    let annotaions: TimeSeriesChartProps['annotations'] = []
    const groups = eventGroupsRes.data.activity_groups ?? []
    groups.forEach((g, i) => {
      const activities = (g.activities ?? []).filter((a) => a.type === 'Event')
      if (activities.length === 1) {
        // single event
        const e = g.activities![0]
        const ts = e.calibration_time! * 1000
        annotaions!.push({
          type: 'line',
          start: [ts, 'min'],
          end: [ts, 'max'],
          style: {
            lineDash: [4, 4],
            stroke: '#F4664A'
          },
          top: true,
          text: {
            content: (e.display_name || e.name)!,
            autoRotate: false,
            position: `${(i * 5) % 100}%`,
            style: {
              opacity: 1
            }
          }
        })
      }
      if (activities.length > 1) {
        // multiple events
        const eFirst = g.activities![0]
        const eLast = g.activities![g.activities!.length - 1]
        const tsFirst = eFirst.calibration_time! * 1000
        const tsLast = eLast.calibration_time! * 1000
        annotaions!.push({
          type: 'region',
          start: [tsFirst, 'min'],
          end: [tsLast, 'max'],
          style: {
            lineWidth: 1,
            lineDash: [4, 4],
            stroke: 'red'
          },
          top: true
        })
        annotaions!.push({
          type: 'text',
          position: [tsFirst, 'max'],
          content: g.name,
          offsetX: 5,
          style: {
            fontSize: 14,
            opacity: 1
          }
        })
      }
    })

    setTimeout(() => {
      chartRef.current
        .getChart()
        .addAnnotations(annotaions, chartRef.current.getChart().chart.views[0])
    }, 1000)
  }, [eventGroupsRes])

  return (
    <PromDataAccessor
      fetch={(query, tp) => {
        const _query = replaceQuery(
          query,
          curCluster!.id!,
          OrgType.Cloud,
          curCluster?.deployType
        )
        return grafanaQueryRange({
          query: _query,
          orgId: curOrg!.id!,
          clusterId: curCluster!.id!,
          start: tp.start_time,
          end: tp.end_time,
          step: tp.step.toString() + 's',
          isCloud: true
        }).then((res) => res.data)
      }}
      params={{
        start_time: chartTimeRange.begin,
        end_time: chartTimeRange.end
      }}
      onBatchLoadingChange={setLoadingMetric}
    >
      <div className='pl-20 relative'>
        <div className='absolute top-16 -ml-20'>
          <Text>QPS Trend</Text>
        </div>
        <TimeSeriesChart
          ref={chartRef}
          onEvents={handleEvent}
          height={200}
          modifyConfig={(ori) => ({
            ...ori,
            legend: false,
            interactions: [{ type: 'brush-x-highlight' }]
          })}
          annotations={highlightAnnotation}
        >
          <PromQueryGroup queries={qpsChart.queries} unit={qpsChart.unit} />
        </TimeSeriesChart>

        {showPreDayBtn && (
          <div className='absolute top-20 left-32'>
            <Tooltip label='Previous Day' position='right' withArrow>
              <ActionIcon
                radius='xl'
                variant='light'
                onClick={() => {
                  setChartTimeRange((pre) => ({
                    begin: pre.begin - ONE_DAY_SECONDS,
                    end: pre.end - ONE_DAY_SECONDS
                  }))
                  clusterDetailTelemetry.clickPreviousDay()
                }}
              >
                <IconChevronLeft size={16} />
              </ActionIcon>
            </Tooltip>
          </div>
        )}
        {showNextDayBtn && (
          <div className='absolute top-20 right-2'>
            <Tooltip label='Next Day' position='left' withArrow>
              <ActionIcon
                radius='xl'
                variant='light'
                onClick={() => {
                  setChartTimeRange((pre) => ({
                    begin: pre.begin + ONE_DAY_SECONDS,
                    end: pre.end + ONE_DAY_SECONDS
                  }))
                  clusterDetailTelemetry.clickNextDay()
                }}
              >
                <IconChevronRight size={16} />
              </ActionIcon>
            </Tooltip>
          </div>
        )}

        <LoadingOverlay
          loaderProps={{ size: 'sm', variant: 'bars' }}
          visible={loadingMetric}
        />
      </div>
    </PromDataAccessor>
  )
}
