import {
  Chart,
  Settings,
  Axis,
  Position,
  LineSeries,
  ScaleType,
  CurveType,
  Fit,
  LineAnnotation,
  AnnotationDomainType,
  Tooltip
} from '@elastic/charts'
import { useChartColors, useChartThemeConfig } from '@tidb-cloud-uikit/theme/Chart'
import { Box, BoxProps, Typography, TypographyProps } from '@tidbcloud/uikit'
import dayjs from 'dayjs'

import { useTimeFormatter } from 'dbaas/components/TimeComponent'
import { moneyFormatter } from 'dbaas/utils/numberFormat'

import { ForecastResultResp } from './helpers'
import { useStyles } from './styles'

export const SpendingEstimationChart: React.FC<
  React.PropsWithChildren<{
    size?: { h?: BoxProps['h']; w?: BoxProps['w'] }
    markerFontSize?: TypographyProps['fz']
    cost: number
    currentLimit?: number
    data: ForecastResultResp
  }>
> = ({ markerFontSize = 11, size = { h: 200 }, data, cost, currentLimit = 0 }) => {
  const { themeConfig } = useChartThemeConfig()
  const { chartColors, themeColors, chartColorsOpacity04 } = useChartColors()

  const diff = data.predict_month_end_water_mark - currentLimit

  const boundary = data.predict_month_end_water_mark * 0.1

  const shouldCurrentReverse = diff >= 0 && diff < boundary
  const shouldRecommendReverse = diff < 0 && Math.abs(diff) < boundary

  const { classes } = useStyles({ currentReverse: shouldCurrentReverse, recommendReverse: shouldRecommendReverse })

  const currentDate = dayjs()
  const currentTimestamp = dayjs(`${currentDate.format('YYYY-MM-DD')} 00:00:00`)
    .utc(true)
    .unix()

  const xAxisFormatter = useTimeFormatter('MM/DD', 0)

  const isToday = (value: number | string) => {
    if (Math.abs(Number(value) - currentTimestamp) < 60 * 60) {
      return true
    }
    return false
  }

  return (
    <Box className={classes.container} {...size}>
      <Chart>
        <Settings
          baseTheme={{
            ...themeConfig,
            chartMargins: {
              left: 0,
              right: 0,
              top: 0,
              bottom: 0
            },
            chartPaddings: {
              left: -10,
              right: -5,
              top: 0,
              bottom: 0
            },
            axes: {
              ...themeConfig.axes,
              gridLine: {
                horizontal: { visible: false, dash: [], stroke: '', strokeWidth: 0, opacity: 0 },
                vertical: { visible: false, dash: [], stroke: '', strokeWidth: 0, opacity: 0 },
                lumaSteps: []
              }
            }
          }}
        />
        <Tooltip
          headerFormatter={({ value }) => {
            const formatted = xAxisFormatter(value)
            if (isToday(value)) {
              return <>{formatted} (Today)</>
            }
            if (value === data.predict_reach_spent_limit_date) {
              return <>{formatted} (Exceed spending limit)</>
            }
            return <>{xAxisFormatter(value)}</>
          }}
        ></Tooltip>
        <Axis id="x" position={Position.Bottom} tickFormat={xAxisFormatter} />
        {!!data?.predict_month_end_water_mark && (
          <>
            <Axis
              id="y"
              position={Position.Left}
              hide={true}
              tickFormat={(value) => {
                return moneyFormatter(value)
              }}
              domain={{ max: Math.max(data.predict_month_end_water_mark, currentLimit) * 1.1, min: 0 }}
            />
            <LineAnnotation
              id="recommend limit"
              domainType={AnnotationDomainType.YDomain}
              dataValues={[{ dataValue: data.predict_month_end_water_mark }]}
              marker={
                <Typography variant="body-sm" c="sky.7" fz={markerFontSize}>
                  Recommend limit {moneyFormatter(data.predict_month_end_water_mark)}
                </Typography>
              }
              style={{ line: { stroke: chartColorsOpacity04[0] } }}
              markerPosition={'top'}
            />
          </>
        )}

        {!!currentLimit && (
          <LineAnnotation
            id="cureent limit"
            domainType={AnnotationDomainType.YDomain}
            dataValues={[{ dataValue: currentLimit }]}
            marker={
              <Typography variant="body-sm" c="red.7" fz={markerFontSize}>
                Current limit {moneyFormatter(currentLimit)}
              </Typography>
            }
            style={{ line: { stroke: themeColors.red[4] } }}
            markerPosition={'top'}
          />
        )}
        {!!data?.predict_reach_spent_limit_date && (
          <LineAnnotation
            id="exceed spend limit"
            domainType={AnnotationDomainType.XDomain}
            dataValues={[{ dataValue: data?.predict_reach_spent_limit_date }]}
            style={{ line: { stroke: chartColorsOpacity04[7] } }}
          />
        )}

        <LineSeries
          id="Estimation"
          fit={Fit.Linear}
          xScaleType={ScaleType.Time}
          // yScaleType={ScaleType.Linear}
          xAccessor={0}
          yAccessors={[1]}
          curve={CurveType.CURVE_MONOTONE_X}
          lineSeriesStyle={{ line: { dash: [4], strokeWidth: 2, stroke: chartColors.airy[7] } }}
          pointStyleAccessor={(datum) => {
            return {
              shape: 'circle',
              fill: chartColorsOpacity04[7],
              strokeWidth: 0,
              opacity: data.predict_reach_spent_limit_date && data.predict_reach_spent_limit_date === datum.x ? 1 : 0,
              radius: 4,
              visible: true
            }
          }}
          data={data?.predict_water_mark_records || []}
        />
        <LineSeries
          id="History"
          fit={Fit.Linear}
          xScaleType={ScaleType.Time}
          xAccessor={0}
          yAccessors={[1]}
          curve={CurveType.CURVE_MONOTONE_X}
          data={
            // @FIXME after interval changed
            data?.water_mark_history_records?.map((record) => (isToday(record[0]) ? [record[0], cost] : [...record])) ||
            []
          }
          lineSeriesStyle={{ line: { strokeWidth: 2 } }}
          pointStyleAccessor={(datum) => {
            return {
              shape: 'circle',
              fill: chartColorsOpacity04[1],
              strokeWidth: 0,
              opacity: isToday(datum.x) ? 1 : 0,
              radius: 4,
              visible: true
            }
          }}
        />
      </Chart>
    </Box>
  )
}
