import { BrushEvent } from '@elastic/charts'
import { SimpleGrid } from '@tidbcloud/uikit'
import { TimeRangeValue } from '@tidbcloud/uikit/biz'
import { useDebounceFn } from 'ahooks'
import { SyncChartPointer as MetricsChartSyncProvider } from 'metrics-chart'
import { forwardRef, memo, useCallback, useImperativeHandle, useMemo, useRef } from 'react'

import ChartCard from 'dbaas/components/ChartCard'
import { MetricInfo, MetricRequestOptions } from 'dbaas/components/ChartCard/helpers'
import { pauseCircuitBreaker, resumeCircuitBreaker } from 'dbaas/utils/circuit-breaker'

interface MetricsPanelProps {
  metricSourceURI: string
  metrics: MetricInfo[]
  timeRangeValue: TimeRangeValue
  metricRequestOptions?: MetricRequestOptions
  onTimeRangeChange?: (t: TimeRangeValue) => void
  onLoading?: (loading: boolean) => void
  pendingOverlay?: React.ReactNode
  initialLoading?: boolean
  enableCircuitBreaker?: boolean
  onThrottleOpen?: () => void
  onRecoverySuccess?: (isForceRefresh: boolean) => void
}

export interface MetricsPanelRef {
  pauseCircuitBreaker: () => void
  resumeCircuitBreaker: () => void
}

const MetricsPanel = memo(
  forwardRef<MetricsPanelRef, MetricsPanelProps>(
    (
      {
        metricSourceURI,
        metrics,
        timeRangeValue,
        metricRequestOptions,
        onTimeRangeChange,
        onLoading,
        pendingOverlay,
        initialLoading,
        enableCircuitBreaker,
        onThrottleOpen,
        onRecoverySuccess
      },
      ref
    ) => {
      const loadingCounter = useRef(0)
      const { run: debouncedOnLoading } = useDebounceFn((v) => onLoading?.(v), { wait: 100, leading: true })

      const handleBrushEnd = useCallback(
        (v: BrushEvent) => {
          if (!v.x) {
            return
          }
          let value: [number, number]
          const tr = v.x.map((d) => (d as number) / 1000)
          const delta = tr[1] - tr[0]
          if (delta < 60) {
            const offset = Math.floor(delta / 2)
            value = [Math.ceil(tr[0] + offset - 30), Math.floor(tr[1] - offset + 30)]
          } else {
            value = [Math.ceil(tr[0]), Math.floor(tr[1])]
          }
          onTimeRangeChange?.(value)
        },
        [onTimeRangeChange]
      )

      const sharedChartSetting = useMemo(
        () => ({
          onBrushEnd: handleBrushEnd
        }),
        [handleBrushEnd]
      )

      const sharedCardProps = useMemo(() => ({ bg: 'carbon.0' as const }), [])

      const handleChartLoading = useCallback(
        (isLoading: boolean) => {
          isLoading ? (loadingCounter.current += 1) : loadingCounter.current > 0 && (loadingCounter.current -= 1)

          if (loadingCounter.current === 0) {
            debouncedOnLoading(false)
          } else {
            debouncedOnLoading(true)
          }
        },
        [debouncedOnLoading]
      )

      useImperativeHandle(
        ref,
        () => ({
          pauseCircuitBreaker: () => {
            // Pause circuit breaker for all charts (they all use the same sourceURI)
            pauseCircuitBreaker(metricSourceURI)
          },
          resumeCircuitBreaker: () => {
            // Resume circuit breaker for all charts (they all use the same sourceURI)
            resumeCircuitBreaker(metricSourceURI)
          }
        }),
        [metricSourceURI]
      )

      return (
        <MetricsChartSyncProvider>
          <SimpleGrid type="container" cols={{ base: 1, '900px': 2 }} spacing="xl">
            {metrics.map((metric) => (
              <ChartCard
                key={metric.title}
                title={metric.title}
                label={metric.label}
                sourceURI={metricSourceURI}
                timeRange={timeRangeValue}
                metric={metric}
                metricRequestOptions={metricRequestOptions}
                chartSetting={sharedChartSetting}
                onLoading={handleChartLoading}
                cardProps={sharedCardProps}
                pendingOverlay={pendingOverlay}
                initialLoading={initialLoading}
                enableCircuitBreaker={enableCircuitBreaker}
                onThrottleOpen={onThrottleOpen}
                onRecoverySuccess={onRecoverySuccess}
              />
            ))}
          </SimpleGrid>
        </MetricsChartSyncProvider>
      )
    }
  )
)

MetricsPanel.displayName = 'MetricsPanel'

export default MetricsPanel
