'use client';

import {
  Position,
  SettingsProps,
  TooltipStickTo,
  TooltipType
} from '@elastic/charts'
import {
  Box,
  Card,
  CardProps,
  Group,
  Stack,
  Typography
} from '@tidbcloud/uikit'
import dayjs from 'dayjs'
import { MetricsChart, TimeRangeValue } from 'metrics-chart'
import React, { useState } from 'react'

import {
  createEmptyPrometheusResponse,
  MetricInfo,
  sortPrometheusSeriesByLatestValue,
  PrometheusMatrixResponse
} from './helpers'
import { LoadingOverlay } from './LoadingOverlay'

export interface ChartCardProps {
  title: string
  label?: string
  timeRange: [number, number]
  timeFormat?: string
  metric: MetricInfo
  height?: number
  chartSetting?: SettingsProps
  fixMinInterval?: boolean
  onLoading?: (loading: boolean) => void
  cardProps?: Omit<CardProps, 'children'>
  pendingOverlay?: React.ReactNode
  initialLoading?: boolean
  fetchPromeData?: (params: {
    startTimeSec: number
    endTimeSec: number
    stepSec: number
    query: string
  }) => Promise<PrometheusMatrixResponse>
}

export function niceTimeFormatByDay(range: TimeRangeValue) {
  const minDate = dayjs(range[0] * 1000)
  const maxDate = dayjs(range[1] * 1000)
  const mins = maxDate.diff(minDate, 'minutes')

  if (mins > 5 * 60 * 24) return 'MM-DD'
  if (mins > 1 * 60 * 24) return 'MM-DD HH:mm'
  if (mins > 5) return 'HH:mm'
  return 'HH:mm:ss'
}

const ChartCard: React.FC<React.PropsWithChildren<ChartCardProps>> = ({
  title,
  label,
  timeRange,
  metric,
  onLoading,
  height = 192,
  chartSetting = {},
  fixMinInterval = true,
  timeFormat = 'YYYY-MM-DD HH:mm:ss',
  cardProps,
  initialLoading,
  pendingOverlay,
  fetchPromeData
}) => {
  return (
    <Card
      p={16}
      bg="carbon.2"
      shadow="none"
      data-testid="metric-chart-card"
      {...cardProps}
    >
      <Group mb="xs" sx={{ justifyContent: 'center' }}>
        <Typography variant="title-md">
          {title}
        </Typography>
      </Group>
      <Box pos="relative">
        {initialLoading ? (
          <LoadingOverlay height={height} />
        ) : !!pendingOverlay ? (
          <>
            <Chart
              key={`${title}_withdata`}
              metric={metric}
              height={height}
              timeRange={timeRange}
              chartSetting={chartSetting}
              fixMinInterval={fixMinInterval}
              onLoading={onLoading}
              timeFormat={timeFormat}
              fetchPromeData={() =>
                Promise.resolve(createEmptyPrometheusResponse())
              }
            />
            <Stack
              align="center"
              justify="center"
              gap={4}
              h={height}
              pos="absolute"
              top={-22}
              left={0}
              right={0}
              bottom={0}
            >
              {pendingOverlay}
            </Stack>
          </>
        ) : (
          <Chart
            key={`${title}_nodata`}
            metric={metric}
            height={height}
            timeRange={timeRange}
            chartSetting={chartSetting}
            fixMinInterval={fixMinInterval}
            onLoading={onLoading}
            timeFormat={timeFormat}
            fetchPromeData={
              fetchPromeData ||
              (() => Promise.resolve(createEmptyPrometheusResponse()))
            }
          />
        )}
      </Box>
    </Card>
  )
}

export const Chart = ({
  metric,
  height,
  timeRange,
  chartSetting,
  fixMinInterval,
  onLoading,
  timeFormat,
  fetchPromeData
}: {
  metric: MetricInfo
  height: number
  timeRange: TimeRangeValue
  chartSetting: SettingsProps
  fixMinInterval: boolean
  onLoading?: (loading: boolean) => void
  timeFormat: string
  fetchPromeData: (params: {
    startTimeSec: number
    endTimeSec: number
    stepSec: number
    query: string
  }) => Promise<any>
}) => {
  const [firstLoading, setFirstLoading] = useState(false)
  const MIN_INTERVAL_MS = 120 * 1000

  const resolvedChartSetting: SettingsProps = {
    legendPosition: Position.Right,
    legendSize: 140,
    tooltip: {
      type: TooltipType.Crosshairs,
      stickTo: TooltipStickTo.MousePosition
    },
    ...chartSetting,
    xDomain: {
      ...(chartSetting?.xDomain ?? {}),
      minInterval: MIN_INTERVAL_MS
    } as SettingsProps['xDomain']
  }

  return (
    <MetricsChart
      queries={metric.queries}
      nullValue={metric.nullValue}
      unit={metric.unit}
      height={height}
      range={timeRange}
      timezone={0}
      chartSetting={resolvedChartSetting}
      fixMinInterval={fixMinInterval}
      loadingComponent={
        firstLoading ? undefined : () => <LoadingOverlay height={height} />
      }
      onLoading={(isLoading) => {
        if (!isLoading) {
          setFirstLoading(true)
        }
        onLoading?.(isLoading)
      }}
      yAxisFormat={metric.yAxisFormat}
      ignoreErrorData={true}
      fetchPromeData={fetchPromeData}
    />
  )
}

export default ChartCard
