import TimeRangePicker from '@tidb-cloud-uikit/components/TimeRangePicker'
import { Badge, Flex, Group, Stack, Tabs, notifier } from '@tidbcloud/uikit'
import {
  DEFAULT_TIME_RANGE,
  fromTimeRangeValue,
  TimeRange,
  TimeRangeValue,
  toTimeRangeValue
} from '@tidbcloud/uikit/biz'
import { IconAlertTriangle } from '@tidbcloud/uikit/icons'
import dayjs from 'dayjs'
import { observer } from 'mobx-react'
import { useEffect, useMemo, useRef, useState } from 'react'

import { CreationPendingOverlay } from 'dbaas/components/ChartCard/CreationPendingOverlay'
import { HeroComponent } from 'dbaas/components/Measurement'
import MetricsPanel, { MetricsPanelRef } from 'dbaas/components/MetricsPanel'
import {
  DEFAULT_MAX_TIME_RANGE_DAYS,
  EXTENDED_METRICS_RETENTION_DAYS,
  ONE_DAY_SECONDS
} from 'dbaas/components/MetricsPanel/timeRange'
import AutoRefreshButton, {
  AutoRefreshButtonRef,
  DEFAULT_AUTO_REFRESH_SECONDS
} from 'dbaas/screens/ClusterV2/components/AutoRefreshButton'
import { useEssentialV2ChangefeedEnabled } from 'dbaas/screens/NextGen/my-tidb-creation/shared/use-essential-v2-enabled'
import { TidbCreatingAlertMessage } from 'dbaas/screens/NextGen/tidb-creation/shared/CreatingAlertMessage'
import { useSharedTiDBContext } from 'dbaas/screens/NextGen/tidb-mgmt-container/shared/tidb-context'
import { TiDBPageShell } from 'dbaas/screens/NextGen/tidb-mgmt-container/shared/TiDBPageShell'
import { useGetExpWhiteList } from 'dbaas/services/api'
import { useGetMetricsQueryRangeURL } from 'dbaas/services/useO11YQuery'
import { ExpFeatHashmap } from 'dbaas/stores/localStorage'
import useStores from 'dbaas/stores/useStores'
import { eventTracking } from 'dbaas/utils/tracking'

import {
  cassandraMetricsConfig,
  cassandraMetricsTabs,
  MetricConfig,
  PREMIUM_EXTENDED_QUICK_RANGES,
  getPremiumMetricsConfig,
  PREMIUM_QUICK_RANGES,
  PremiumMetricsTab,
  premiumMetricsTabs
} from './config/config'

interface MetricsProps {}

const ESSENTIAL_V2_CHANGEFEED_METRIC_TITLES = new Set(['Changefeed Checkpoint Lag', 'The Status of Changefeeds'])

const Metrics: React.FC<React.PropsWithChildren<MetricsProps>> = observer(() => {
  const tidb = useSharedTiDBContext()
  const {
    store: {
      tenantData: { id: orgId }
    }
  } = useStores()
  const {
    data: metricsURL,
    isLoading: isLoadingMetricsURL,
    isError: isMetricsURLError,
    metricRequestOptions
  } = useGetMetricsQueryRangeURL(orgId, tidb)

  const { data: whiteList } = useGetExpWhiteList(orgId, undefined, {
    query: { enabled: !!orgId, refetchOnMount: false, refetchOnWindowFocus: false }
  })
  const isRUOverviewEnabled = whiteList?.exp_names?.includes(ExpFeatHashmap.RUOverview)
  const isMetricsRetention30DayEnabled = whiteList?.exp_names?.includes(ExpFeatHashmap.MetricsRetention30Day)
  const isTieredStorageEnabled =
    whiteList?.exp_names?.includes(ExpFeatHashmap.TieredStorageBYOCPremiumWhitelist) ?? false
  const isEssentialV2ChangefeedEnabled = useEssentialV2ChangefeedEnabled()
  const isCassandra = tidb.computed.isCassandra

  const tabs = useMemo(() => {
    const metricTabs = isCassandra ? cassandraMetricsTabs : premiumMetricsTabs

    return metricTabs
      .filter((t) => {
        if (tidb.computed.isEssentialV2 && t === PremiumMetricsTab.Advanced) {
          return false
        }
        if (t === PremiumMetricsTab.RUOverview) {
          return isRUOverviewEnabled
        }
        return true
      })
      .map((t) => ({
        value: t,
        label:
          t === PremiumMetricsTab.RUOverview ? (
            <Group gap={8}>
              {t}
              <Badge variant="outline" size="sm" color="carbon" c="carbon.7" fw={500}>
                Preview
              </Badge>
            </Group>
          ) : (
            t
          )
      }))
  }, [isCassandra, isRUOverviewEnabled, tidb.computed.isEssentialV2])
  const [tab, _setTab] = useState(tabs[0].value)
  const metricsConfig: MetricConfig = useMemo(() => {
    const baseConfig = isCassandra
      ? cassandraMetricsConfig
      : getPremiumMetricsConfig(tidb.computed.isPremiumReserved, isTieredStorageEnabled)

    if (!tidb.computed.isEssentialV2 || isEssentialV2ChangefeedEnabled) {
      return baseConfig
    }

    return Object.fromEntries(
      Object.entries(baseConfig).map(([metricTab, metrics]) => [
        metricTab,
        metrics.filter((metric) => !ESSENTIAL_V2_CHANGEFEED_METRIC_TITLES.has(metric.title))
      ])
    )
  }, [
    isCassandra,
    isEssentialV2ChangefeedEnabled,
    isTieredStorageEnabled,
    tidb.computed.isEssentialV2,
    tidb.computed.isPremiumReserved
  ])

  useEffect(() => {
    if (!tabs.some((t) => t.value === tab)) {
      _setTab(tabs[0].value)
    }
  }, [tab, tabs])

  const setTab = (v: string) => {
    _setTab(v)
    autoRefreshRef.current?.refresh()
  }

  const [isMetricsLoading, setIsMetricsLoading] = useState(false)
  const [loaded, setLoaded] = useState(false)

  const [timeRange, setTimeRange] = useState<TimeRange>(DEFAULT_TIME_RANGE)
  const [timeRangeValue, setTimeRangeValue] = useState<TimeRangeValue>(toTimeRangeValue(timeRange))
  const [autoRefreshValue, setAutoRefreshValue] = useState<number>(DEFAULT_AUTO_REFRESH_SECONDS)
  const [isCircuitBreakerOpen, setIsCircuitBreakerOpen] = useState<boolean>(false)
  const autoRefreshRef = useRef<AutoRefreshButtonRef>(null)
  const previousAutoRefreshValueRef = useRef<number>(DEFAULT_AUTO_REFRESH_SECONDS)
  const isLoading = isLoadingMetricsURL || isMetricsLoading
  const metricsPanelRef = useRef<MetricsPanelRef>(null)
  const hasExtendedMetricsRetention = tidb.computed.isBYOC || isMetricsRetention30DayEnabled
  const minTimeRangeDays = hasExtendedMetricsRetention ? EXTENDED_METRICS_RETENTION_DAYS : DEFAULT_MAX_TIME_RANGE_DAYS
  const maxTimeRangeDays = tidb.computed.isBYOC ? EXTENDED_METRICS_RETENTION_DAYS : DEFAULT_MAX_TIME_RANGE_DAYS
  const quickRanges = tidb.computed.isBYOC ? PREMIUM_EXTENDED_QUICK_RANGES : PREMIUM_QUICK_RANGES

  return (
    <TiDBPageShell title="Metrics">
      <HeroComponent ready={loaded || isMetricsURLError} />
      <Stack>
        <TidbCreatingAlertMessage />
        <Flex mb={16} gap="md" justify="space-between" wrap="wrap">
          <Tabs
            value={tab}
            styles={() => ({
              list: {
                '::before': {
                  border: 'none'
                }
              },
              tabLabel: {
                fontSize: 14
              }
            })}
            onChange={(v: string) => {
              setTab(v)
              eventTracking('Monitoring Status Tab Switch', { value: v })
            }}
          >
            <Tabs.List>
              {tabs.map((item) => {
                return (
                  <Tabs.Tab key={item.value} value={item.value}>
                    {item.label}
                  </Tabs.Tab>
                )
              })}
            </Tabs.List>
          </Tabs>

          <Flex gap="md" justify="flex-end" wrap="wrap">
            <TimeRangePicker
              value={timeRange}
              onChange={(v) => {
                setTimeRange(v)
                setTimeRangeValue(toTimeRangeValue(v))
                eventTracking('Monitoring Time Range Change', { timeRange: v })
              }}
              minDateTime={() => dayjs().subtract(minTimeRangeDays, 'day').startOf('d').toDate()}
              maxDateTime={() => dayjs().endOf('d').toDate()}
              maxDuration={ONE_DAY_SECONDS * maxTimeRangeDays}
              quickRanges={quickRanges}
              loading={isLoading}
            />
            <AutoRefreshButton
              ref={autoRefreshRef}
              autoRefreshValue={autoRefreshValue}
              onAutoRefreshChange={(v) => {
                setAutoRefreshValue(v)
                if (v > 0) {
                  previousAutoRefreshValueRef.current = v
                  setIsCircuitBreakerOpen(false)
                }
                eventTracking('Monitoring Auto Refresh Interval Change', { interval: v })
              }}
              onRefresh={() => {
                if (isCircuitBreakerOpen) {
                  metricsPanelRef.current?.pauseCircuitBreaker()
                }

                setTimeRangeValue(toTimeRangeValue(timeRange))
                eventTracking('Monitoring Refresh Button Clicked')

                setTimeout(() => {
                  if (isCircuitBreakerOpen) {
                    metricsPanelRef.current?.resumeCircuitBreaker()
                  }
                }, 100)
              }}
              loading={isLoading}
              disableAutoRefreshSelect={isCircuitBreakerOpen}
              leftSection={isCircuitBreakerOpen ? <IconAlertTriangle size={16} /> : undefined}
              tooltip={
                isCircuitBreakerOpen
                  ? 'Metrics service is temporarily unavailable. We are continuously trying to reconnect in the background. If the service recovers, it will refresh immediately.'
                  : undefined
              }
            />
          </Flex>
        </Flex>

        <MetricsPanel
          ref={metricsPanelRef}
          metricSourceURI={metricsURL ?? ''}
          metrics={metricsConfig[tab] ?? []}
          onTimeRangeChange={(v) => {
            setTimeRange(fromTimeRangeValue(v))
            setTimeRangeValue(v)
          }}
          timeRangeValue={timeRangeValue}
          metricRequestOptions={metricRequestOptions}
          onLoading={(loading) => {
            if (!loading) {
              setLoaded(true)
            }
            setIsMetricsLoading(loading)
          }}
          pendingOverlay={tidb?.computed.creating || tidb?.computed.restoring ? <CreationPendingOverlay /> : null}
          initialLoading={isLoadingMetricsURL}
          enableCircuitBreaker
          onThrottleOpen={() => {
            // Pause auto refresh when circuit breaker opens
            if (autoRefreshValue > 0) {
              previousAutoRefreshValueRef.current = autoRefreshValue
            }
            setAutoRefreshValue(0)
            setIsCircuitBreakerOpen(true)
            // Show one-time notification
            notifier.warn('Metrics service is temporarily unavailable. Please try again later.', { autoClose: 6000 })
          }}
          onRecoverySuccess={(isDuringPaused) => {
            // Resume auto refresh when recovery succeeds
            setAutoRefreshValue(previousAutoRefreshValueRef.current)
            setIsCircuitBreakerOpen(false)
            // Only trigger auto refresh if not from paused state (paused state already triggers refresh)
            if (!isDuringPaused) {
              setTimeout(() => {
                autoRefreshRef.current?.refresh()
              }, 100)
            }
          }}
        />
      </Stack>
    </TiDBPageShell>
  )
})

export default Metrics
