import {
  Box,
  Card,
  Flex,
  Group,
  SegmentedControl,
  SegmentedControlItem,
  Typography,
  Grid,
  Divider
} from '@tidbcloud/uikit'
import { RelativeTimeRange, TimeRange, TimeRangeValue, toTimeRangeValue } from '@tidbcloud/uikit/biz'
import { LabelTooltip } from '@tidbcloud/uikit/biz'
import dayjs from 'dayjs'
import { SeriesType } from 'metrics-chart'
import { observer } from 'mobx-react'
import { useEffect, useMemo, useState } from 'react'

import { useGetOpenAPIUsageExplorerMonthly } from 'dbaas/services/billing'
import { useListAppCluster } from 'dbaas/services/dataservice'
import { dbaasUrl } from 'dbaas/services/endpoint'
import useStores from 'dbaas/stores/useStores'
import { formatStorage, formatToK } from 'dbaas/utils/format'
import { eventTracking } from 'dbaas/utils/tracking'

import { useDataApiContext } from '../../context'

import { UsageChartConfig, Chat2DataUsageChartConfig, USAGE_METRIC_TYPES, getRegion } from './helper'
import MetricsPanel from './MetricsPanel'

const UsageOverview = observer(() => {
  const {
    store: { tenantData }
  } = useStores()
  const period = dayjs()
  const { editApp } = useDataApiContext()
  const year = period.year().toString()
  const currentPeriod = `${period.format('MMM')}1 - ${period.format('MMM')}${period.daysInMonth()}, ${year}`
  const { data } = useGetOpenAPIUsageExplorerMonthly(
    tenantData.id,
    editApp?.app_type === 'chat2query' ? 'eda' : 'dataapi',
    editApp?.id || '',
    year,
    (period.month() + 1).toString()
  )

  return (
    <Card p={24}>
      <Grid grow>
        <Grid.Col span={4}>
          <Flex align="center" justify="space-between">
            <div>
              <Typography variant="label-lg">Usage Period</Typography>
              <Typography variant="title-lg" c="carbon.8">
                {currentPeriod}
              </Typography>
            </div>
            <Divider orientation="vertical" mr={48} />
          </Flex>
        </Grid.Col>
        <Grid.Col span={8}>
          <Group gap={64} justify="space-between" grow>
            <Flex direction="column">
              <Typography variant="label-lg">API Requests</Typography>
              <Typography variant="title-lg" c="carbon.8">
                {formatToK(data?.usage_map?.request || '0')}
              </Typography>
            </Flex>
            <Flex direction="column">
              <Typography variant="label-lg">Network Transfer</Typography>
              <Typography variant="title-lg" c="carbon.8">
                {formatStorage((data?.usage_map?.network || 0) / 1024)}
              </Typography>
            </Flex>
            {editApp?.app_type === 'chat2query' && (
              <Flex direction="column">
                <Flex>
                  <Typography variant="label-lg">Chat2Query Tokens</Typography>
                  <LabelTooltip
                    width={400}
                    label="Tokens are pieces of words used by Chat2Query for natural language processing"
                  />
                </Flex>

                <Typography variant="title-lg" c="carbon.8">
                  {formatToK(data?.usage_map?.token ?? '0')}
                </Typography>
              </Flex>
            )}
          </Group>
        </Grid.Col>
      </Grid>
    </Card>
  )
})

const DEFAULT_TIME_RANGE: TimeRange = {
  type: 'relative',
  value: 30 * 60
}

export const UsagePanel: React.FC<React.PropsWithChildren<unknown>> = () => {
  const { orgId, projectId, editApp } = useDataApiContext()

  const tabs: SegmentedControlItem[] = [
    { label: 'Recent', value: USAGE_METRIC_TYPES.CUMULATIVE },
    { label: 'Daily', value: USAGE_METRIC_TYPES.DAILY }
  ]

  const currentDate = dayjs()
  const endTime = dayjs(`${currentDate.format('YYYY-MM-DD')} 23:60:60`).unix()

  const toDailyTimeRangeValue = (timeRange: RelativeTimeRange): TimeRangeValue => {
    return [endTime - timeRange.value, endTime]
  }

  const [timeRangeValue, setTimeRangeValue] = useState<TimeRangeValue>(toTimeRangeValue(DEFAULT_TIME_RANGE))
  const [tab, _setTab] = useState(USAGE_METRIC_TYPES.CUMULATIVE as string)

  const updateTimeRange = (v: string) => {
    setTimeRangeValue(
      v === USAGE_METRIC_TYPES.DAILY
        ? toDailyTimeRangeValue({
            type: 'relative',
            value: 30 * 24 * 60 * 60
          })
        : toTimeRangeValue(DEFAULT_TIME_RANGE)
    )
  }

  const setTab = (v: string) => {
    _setTab(v)
    updateTimeRange(v)
  }
  const { data: linkedClusters } = useListAppCluster(orgId, projectId, `${editApp?.id}`, {
    query: {
      enabled: !!editApp?.id,
      refetchOnWindowFocus: false
    }
  })
  // @FIXME after api changed
  const region = getRegion((linkedClusters?.data || [])[0]?.region || '')

  useEffect(() => {
    // only track region change, region may be null
    updateTimeRange(tab)
  }, [region])

  const sourceURI = `${dbaasUrl}/api/v1/dataservices/central/orgs/${orgId}/projects/${projectId}/list_dataapp_usage?year=${currentDate.year()}&month=${
    currentDate.month() + 1
  }&type=${tab}&dataapp_id=${editApp?.id}&region=${region}`

  const metricsConfig = useMemo(() => {
    return (editApp?.app_type === 'chat2query' ? Chat2DataUsageChartConfig : UsageChartConfig).map((it) => {
      const isDaily = tab === USAGE_METRIC_TYPES.DAILY
      const queries = it.queries.map((query) => {
        return {
          ...query,
          type: isDaily ? ('bar_stacked' as SeriesType) : 'line'
        }
      })
      return {
        ...it,
        queries,
        url: `${sourceURI}&${it.params}`,
        chartSettings: {
          xDomain: {
            min: timeRangeValue[0] * 1000,
            max: timeRangeValue[1] * 1000,
            minInterval: tab === USAGE_METRIC_TYPES.DAILY ? 24 * 60 * 60 * 1000 : undefined
          }
        }
      }
    })
  }, [tab, sourceURI, timeRangeValue, editApp])

  return (
    <Box mt={24}>
      <UsageOverview />
      <Card mt={24} p={24}>
        <SegmentedControl
          data={tabs}
          value={tab}
          mb={20}
          maw={160}
          onChange={(v) => {
            setTab(v)
            eventTracking('DataService Usage Tab Switch', { value: v })
          }}
        />
        <MetricsPanel
          metrics={metricsConfig}
          timeRangeValue={timeRangeValue}
          timeFormat={tab === USAGE_METRIC_TYPES.DAILY ? 'YYYY-MM-DD' : undefined}
        />
      </Card>
    </Box>
  )
}

export default observer(UsagePanel)
