import { ActionIcon, Box, Flex, FlexProps, HoverCard, Typography } from '@tidbcloud/uikit'
import { MRT_Cell, MRT_Column, MRT_Row, MRT_TableInstance, renderExpandCell } from '@tidbcloud/uikit/biz'
import { IconChevronDown, IconChevronRight, IconDownload01, IconInfoCircle } from '@tidbcloud/uikit/icons'
import React, { ReactNode } from 'react'

import dayjs from 'dbaas/components/dayjs'
import { exportMonthBillCSV, getMonthlyBillsExport } from 'dbaas/services/billing'
import {
  FormsCategoryCosts,
  FormsCosts,
  FormsPrice,
  FormsMonthlycostExplorerResult
} from 'dbaas/services/billing/interface'
import { downloadCSV } from 'dbaas/utils/dom'
import { eventTracking } from 'dbaas/utils/tracking'

import { StarterTips } from '../components/HeadLabel'
import { MoneyValue } from '../components/MoneyValue'

export interface CostsItem {
  name: string
  bill: FormsPrice
  credit: FormsPrice
  costs: FormsPrice
  subRows: CostsItem[]
  servicePlan?: string | null
  nestedRow?: boolean
}

export interface CategoryCosts extends FormsCategoryCosts {
  category_item_unit_costs?: FormsCosts['category_item_unit_costs']
  order?: number
}

export interface ProTableCellProps<TData extends Record<string, any>> {
  cell: MRT_Cell<TData>
  renderedCellValue: number | string | React.ReactNode
  column: MRT_Column<TData>
  row: MRT_Row<TData>
  table: MRT_TableInstance<TData>
}

export const toNegative = (discount: string) => -Number(discount)

export const hasBeta = (value: any) => {
  if (typeof value === 'string') {
    return value.toLowerCase().includes('(beta)')
  }
  return false
}

export const hasBasic = (value: any) => {
  if (typeof value === 'string') {
    return value.toLowerCase().includes('(basic)')
  }
  return false
}

export const BetaTips: React.FC<React.PropsWithChildren<FlexProps & { size?: number }>> = ({
  children,
  size = 14,
  ...rest
}) => {
  return (
    <Flex align="center" {...rest}>
      {children}
      <HoverCard shadow="md" withArrow width={320}>
        <HoverCard.Target>
          <IconInfoCircle size={size} ml={4} />
        </HoverCard.Target>
        <HoverCard.Dropdown>
          <Typography variant="body-lg">
            Beta features are listed on this bill, but you'll receive full discounts and will not be charged for their
            usage.
          </Typography>
        </HoverCard.Dropdown>
      </HoverCard>
    </Flex>
  )
}

export const BasicTips: React.FC<React.PropsWithChildren<FlexProps & { size?: number; service?: string }>> = ({
  children,
  size = 14,
  service,
  ...rest
}) => {
  return (
    <Flex align="center" {...rest}>
      {children}
      <HoverCard shadow="md" withArrow width={320}>
        <HoverCard.Target>
          <IconInfoCircle size={size} ml={4} />
        </HoverCard.Target>
        <HoverCard.Dropdown>
          <Typography variant="body-lg">
            Before June 5th, all {service?.toLowerCase().includes('tikv') ? 'TiKV' : 'TiFlash'} storage is classified as
            the Basic type
          </Typography>
        </HoverCard.Dropdown>
      </HoverCard>
    </Flex>
  )
}

interface CellProps<TData extends Record<string, any>> {
  cell: MRT_Cell<TData>
  renderedCellValue: number | string | ReactNode
  cellWrapper?: (row: MRT_Row<TData>, cell: MRT_Cell<TData>) => ReactNode
  column: MRT_Column<TData>
  row: MRT_Row<TData>
  table: MRT_TableInstance<TData>
}

export const renderCustomExpandCell = <T extends Record<string, any> = {}>({
  row,
  cell,
  cellWrapper
}: CellProps<T>) => {
  const canExpand = row.getCanExpand()
  const value = cellWrapper ? cellWrapper(row, cell) : (cell.getValue() as any as React.ReactNode)

  const paddingLeft = row.depth * 20

  const icon = row.getIsExpanded() ? <IconChevronDown size={18} /> : <IconChevronRight size={18} />
  return (
    <Box
      sx={() => ({
        paddingLeft: canExpand ? paddingLeft : paddingLeft + 6,
        display: 'flex',
        alignItems: 'center',
        cursor: canExpand ? 'pointer' : undefined,
        '& > svg': {
          flexShrink: 0
        }
      })}
      onClick={row.getToggleExpandedHandler()}
    >
      {canExpand && <Box sx={{ display: 'flex', alignItems: 'center', marginRight: 8 }}>{icon}</Box>}
      {value}
    </Box>
  )
}

export const renderCellWithTips = <T extends Record<string, any> = {}>({ cell, ...rest }: ProTableCellProps<T>) => {
  const value = cell.getValue()
  const Cell = renderExpandCell({ cell, ...rest })
  if (value === 'TiDB Cloud Starter') {
    return <StarterTips>{Cell}</StarterTips>
  }
  if (typeof value === 'string' && hasBasic(value)) {
    return (
      <BasicTips size={14} service={value as string}>
        {Cell}
      </BasicTips>
    )
  }
  return hasBeta(value) ? <BetaTips>{Cell}</BetaTips> : Cell
}

export const createFooterRenders = (
  currentBill: FormsMonthlycostExplorerResult | undefined,
  isLight: boolean,
  theme: any
) => ({
  runningTotal: () => (
    <MoneyValue
      monospaced
      display="block"
      ta="right"
      c={isLight ? theme.black : undefined}
      amount={currentBill?.total_costs?.raw_price || ''}
    ></MoneyValue>
  ),
  discounts: () => (
    <MoneyValue
      monospaced
      display="block"
      ta="right"
      c={isLight ? theme.black : undefined}
      amount={toNegative(currentBill?.total_costs?.discount_price || '0')}
      negativeZero
    ></MoneyValue>
  ),
  credits: () => (
    <MoneyValue
      monospaced
      display="block"
      ta="right"
      c={isLight ? theme.black : undefined}
      amount={toNegative(currentBill?.credits_costs?.cost_price || '0')}
      negativeZero
    ></MoneyValue>
  ),
  totalCost: () => (
    <MoneyValue
      monospaced
      display="block"
      ta="right"
      c={isLight ? theme.black : undefined}
      amount={currentBill?.invoice_costs?.cost_price || ''}
    ></MoneyValue>
  )
})

export function genProjectsCosts(
  costs: { [key: string]: CategoryCosts },
  credits: { [key: string]: CategoryCosts },
  totalCosts: { [key: string]: CategoryCosts },
  genSubRows: boolean | ((key: string) => boolean) = false
): CostsItem[] {
  const keysMap: { [key: string]: number } = {}

  Object.keys(costs).forEach((key) => {
    keysMap[key] = costs[key].order || 0
  })
  Object.keys(credits).forEach((key) => {
    keysMap[key] = credits[key].order || 0
  })

  const keys = Object.keys(keysMap)
    .map((key) => {
      return [key, keysMap[key]] as [string, number]
    })
    .sort((a, b) => {
      return a[1] - b[1] > 0 ? 1 : -1
    })
    .map((item) => {
      return item[0]
    })

  let nested = false

  return keys
    .map((key) => {
      const bill = costs[key] || { cost_price: '0', raw_price: '0', discount_price: '0' }
      const credit = credits[key] || { cost_price: '0', raw_price: '0', discount_price: '0' }
      const shouldGenSubRows = typeof genSubRows === 'function' ? genSubRows(key) : genSubRows
      const subRows = shouldGenSubRows
        ? genProjectsCosts(
            bill.category_item_unit_costs || bill.category_unit_costs || {},
            credit.category_item_unit_costs || credit.category_unit_costs || {},
            totalCosts[key].category_item_unit_costs || totalCosts[key].category_unit_costs || {},
            genSubRows
          )
        : []
      if (subRows.length) {
        nested = true
      }

      const servicePlan = costs[key]?.service_plan || credits[key]?.service_plan || totalCosts[key]?.service_plan
      return {
        name: key,
        servicePlan,
        bill,
        credit,
        costs: totalCosts[key],
        subRows
      }
    })
    .map((item) => ({ ...item, nestedRow: nested }))
}

export interface CSVExportProps {
  year: number
  month: number
  orgId: string
  configId: number
  type: 'project' | 'usage'
}

export const CSVExport = ({
  year,
  month,
  orgId,
  configId,
  type = 'project'
}: {
  year: number
  month: number
  orgId: string
  configId: number
  type: 'project' | 'usage'
}) => {
  const fileName = dayjs(`${year}-${month}`).format('MMMM-YYYY')

  const exportCSV = async () => {
    const data =
      type === 'project'
        ? await exportMonthBillCSV(orgId, configId, year.toString(), month.toString())
        : await getMonthlyBillsExport(orgId, configId, year.toString(), month.toString())
    downloadCSV(data as string, `${type === 'project' ? 'Bills' : 'Monthly-Usage'}-${fileName}`)
  }

  const handleClick = () => {
    eventTracking('Export CSV Link Clicked', {
      type
    })
    exportCSV()
  }

  return (
    <ActionIcon size={32} variant="subtle" onClick={handleClick} c="carbon.8" mb={8}>
      <IconDownload01 size={20} />
    </ActionIcon>
  )
}
