import { Box, Button, Drawer, Flex, Group, Stack, Typography } from '@tidbcloud/uikit'
import { TimeRange, toTimeRangeValue } from '@tidbcloud/uikit/biz'
import { IconAlertCircle } from '@tidbcloud/uikit/icons'
import React, { useEffect, useRef, useState } from 'react'
import { useQuery } from 'react-query'

import config from 'config'
import { SharedCluster } from 'dbaas/features/ClusterManagement/cluster'
import useStores from 'dbaas/stores/useStores'
import { eventTracking } from 'dbaas/utils/tracking'

import { Heatmap } from './components/Heatmap'
import { Setting } from './components/Setting'
import { Toolbar } from './components/Toolbar'
import { useStyles } from './keyviz.styles'
import { KeyVizProvider, useKeyVizContext } from './utils/context'
import { getKeyVizContext } from './utils/context-impl'
import { FEATURE_NAME } from './utils/helpers'
import { HeatmapRange } from './utils/type'
import { useKeyVizUrlState } from './utils/url-state'

const KeyViz = () => {
  useEffect(() => {
    document.title = `${config.PAGE_TITLE_PREFIX}Diagnosis - Key Visualizer`
  }, [])
  const { timeRange, setTimeRange, kind, setKind, refreshInterval, setRefreshInterval, brightness, setBrightness } =
    useKeyVizUrlState()
  const ctx = useKeyVizContext()
  const [showSetting, setShowSetting] = useState(false)
  const [prepareSelection, setPrepareSelection] = useState(false)
  const [selection, setSelection] = useState<HeatmapRange | null>(null)

  const chart = useRef<any>()

  const {
    data: heatmapData,
    isFetching,
    refetch: updateHeatmapData
  } = useQuery(
    ['keyviz', 'heatmaps', ctx.cfg.clusterId, timeRange, selection, kind],
    () => {
      let _selection = selection
      if (!_selection) {
        const [starttime, _endtime] = toTimeRangeValue(timeRange)
        _selection = { starttime }
      }
      return ctx.ds.getKeyVizHeatmap({ ..._selection, type: kind })
    },
    {
      refetchOnWindowFocus: false,
      keepPreviousData: true
    }
  )

  const { data: keyVizConfig, refetch: reloadConfig } = useQuery(
    ['keyviz', 'config', ctx.cfg.clusterId],
    () => {
      return ctx.ds.getKeyVizConfig()
    },
    {
      refetchOnWindowFocus: false
    }
  )

  useEffect(() => {
    if (keyVizConfig?.auto_collection_disabled === false) {
      updateHeatmapData()
    }
  }, [keyVizConfig?.auto_collection_disabled])

  useEffect(() => {
    if (chart.current) {
      chart.current.brightness(Math.pow(2, brightness))
    }
  }, [brightness])

  /////////////////

  function onChartInit(_chart: any) {
    chart.current = _chart
  }

  // select a range in the chart by dragging the mouse
  function onChartSelection(newSelection: HeatmapRange) {
    eventTracking(`${FEATURE_NAME} Select Chart Range`)

    setSelection(newSelection)
    setPrepareSelection(false)
    setRefreshInterval(0)
  }

  // zoom in/out the chart by scrolling the mouse
  function onChartZoom() {
    setRefreshInterval(0)
  }

  /////////////////

  function timeRangeChange(v: TimeRange) {
    eventTracking(`${FEATURE_NAME} Change Time Range`)
    setTimeRange(v)
    setSelection(null)
  }

  // if prepareSelection is true, then enable the chart to select a range by dragging the mouse
  function togglePrepareSelection() {
    eventTracking(`${FEATURE_NAME} Toggle Selection`)
    const newVal = !prepareSelection
    setPrepareSelection(newVal)

    if (chart.current) {
      chart.current.brush(newVal)
    }
  }

  // do nothing is selection is null
  function resetSelection() {
    eventTracking(`${FEATURE_NAME} Reset Selection`)

    if (!selection) return

    setSelection(null)
    setPrepareSelection(false)
  }

  function brightnessOpen() {
    eventTracking(`${FEATURE_NAME} Open Brightness`)
    setTimeout(() => {
      if (chart.current) {
        // just to trigger the heatmap chart to re-render, then the brightness indicator can be drawn
        chart.current.brightness(Math.pow(2, brightness))
      }
    }, 100)
  }

  function brightnessChange(v: number) {
    eventTracking(`${FEATURE_NAME} Change Brightness`)
    setBrightness(v)
  }

  function kindChange(v: string) {
    eventTracking(`${FEATURE_NAME} Change Data Type`)
    setKind(v)
  }

  function settingOpen() {
    eventTracking(`${FEATURE_NAME} Open Setting`)
    setShowSetting(true)
  }

  function refreshIntervalChange(v: number) {
    eventTracking(`${FEATURE_NAME} Change Refresh Interval`)
    setRefreshInterval(v)
  }

  const { classes } = useStyles()

  /////////////////

  return (
    <Stack mx={-24} h="calc(100% - 36px)">
      <Toolbar
        loading={isFetching}
        timeRange={timeRange}
        onTimeRangeChange={timeRangeChange}
        kind={kind}
        onKindChange={kindChange}
        prepareSelection={prepareSelection}
        toggleSelection={togglePrepareSelection}
        onResetSelection={resetSelection}
        refreshInterval={refreshInterval}
        onRefreshIntervalChange={refreshIntervalChange}
        onRefresh={updateHeatmapData}
        brightness={brightness}
        onBrightnessChange={brightnessChange}
        onBrightnessOpen={brightnessOpen}
        openSetting={settingOpen}
      />

      <Box className={classes.keyVizRoot}>
        {keyVizConfig?.auto_collection_disabled === true && (
          <Flex h="100%" align="center" justify="center" direction="column" gap={8}>
            <Group>
              <IconAlertCircle />
              <Typography fw={600} size="xl">
                Feature Not Enabled
              </Typography>
            </Group>
            <Typography color="dimmed" size="sm">
              Key Visualizer feature is not enabled so that visual reports cannot be viewed.
              <br />
              You can modify settings to enable the feature and wait for new data being collected.
            </Typography>
            <Button onClick={() => setShowSetting(true)} data-mp-event="mp-opensettings-1691461017932">
              Open Settings
            </Button>
          </Flex>
        )}

        {keyVizConfig?.auto_collection_disabled === false && heatmapData && (
          <Heatmap data={heatmapData} onChartInit={onChartInit} onSelect={onChartSelection} onZoom={onChartZoom} />
        )}
      </Box>

      <Drawer position="right" title="Settings" padding="md" opened={showSetting} onClose={() => setShowSetting(false)}>
        <Setting
          onClose={() => {
            setShowSetting(false)
            reloadConfig()
          }}
        />
      </Drawer>
    </Stack>
  )
}

/////////////////////////////////////////

interface KeyVizPageProps {
  cluster: SharedCluster
}

const KeyVizPage: React.FC<React.PropsWithChildren<KeyVizPageProps>> = ({ cluster }) => {
  const {
    store: {
      tenantData: { id: orgId },
      activeProjectId
    }
  } = useStores()

  return (
    <KeyVizProvider
      value={getKeyVizContext(
        {
          orgId,
          projectId: activeProjectId,
          clusterId: cluster.id,
          clusterProvider: cluster.provider,
          clusterRegion: cluster.region,
          computed: cluster.computed
        },
        true
      )}
    >
      <KeyViz />
    </KeyVizProvider>
  )
}

// use React.memo to prevent re-rendering when the cluster is updating periodically
export default React.memo(KeyVizPage, (prevProps, nextProps) => prevProps.cluster.id === nextProps.cluster.id)
