// import { getErrorMessage } from '@http/errors'
import {
  ActionIcon,
  Box,
  Card,
  Divider,
  Flex,
  FlexProps,
  Grid,
  HoverCard,
  Typography,
  useComputedColorScheme
} from '@tidbcloud/uikit'
import {
  ProTable,
  renderExpandCell,
  MRT_ColumnDef,
  MRT_Column,
  MRT_Row,
  MRT_Cell,
  MRT_TableInstance
} from '@tidbcloud/uikit/biz'
import { useMediaQuery } from '@tidbcloud/uikit/hooks'
import { IconDownload01, IconInfoCircle } from '@tidbcloud/uikit/icons'
import { useTheme } from '@tidbcloud/uikit/theme'
import { useDebounceFn } from 'ahooks'
import dayjs from 'dayjs'
// import { debounce } from 'lodash-es'
import React, { useState, useMemo } from 'react'
import { useParams } from 'react-router-dom'

import { FormsBillingConfig } from 'apiClient/services/billing/interface'
import {
  useBillingGetPartnerBills,
  useBillingGetPartnerBillsDetails,
  tCPNExportUsageCSV
} from 'apiClient/services/billing_tcpn'
import {
  FormsBillsProjects,
  FormsPartnerBillsServiceCosts,
  FormsCustomerBills,
  // FormsSummaryBillsByCustomer,
  FormsPartnerBillsDetail
} from 'apiClient/services/billing_tcpn/interface'
import { downloadCSV } from 'utils/dom'
import { getErrorMessage } from 'utils/error'

import { OnDemandBillingOverview } from '../components/BillingOverview'
import { BillsCard } from '../components/BillsCard'
import { CostsLabel } from '../components/CostsItem'
import { MoneyValue } from '../components/MoneyValue'
import MonthPicker from '../components/MonthPicker'

import { genCustomerCosts, genProjectCosts, genServiceCosts } from './helper'

export const isZero = (s: string | undefined) => {
  if (!s) {
    return false
  }
  const num = parseFloat(s)
  return num < 0.000001
}

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>
}

interface BetaTipsProps extends FlexProps {
  size?: number
}

const BetaTips: React.FC<React.PropsWithChildren<BetaTipsProps>> = ({
  children,
  size = 14,
  ...rest
}) => {
  return (
    <Flex align="center" {...rest}>
      {children}
      <HoverCard shadow="md" withinPortal withArrow width={320}>
        <HoverCard.Target>
          <Box component={IconInfoCircle} size={size} ml={4}></Box>
        </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>
  )
}

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

const CSVExport = ({
  year,
  month,
  orgId
}: {
  year: number
  month: number
  orgId: string
}) => {
  const fileName = dayjs(`${year}-${month}`).format('YYYY-MM')

  const exportCSV = async () => {
    const data = await tCPNExportUsageCSV(fileName, { accessOrgId: orgId })
    downloadCSV(data.data as any as string, `${'Monthly-Usage'}-${fileName}`)
  }

  const handleClick = () => {
    exportCSV()
  }

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

export const PartnerBills: React.FC<
  React.PropsWithChildren<{
    billingConfig: FormsBillingConfig
  }>
> = ({ billingConfig }) => {
  const { org_id } = useParams<{ org_id: string }>()
  const orgId = billingConfig.tenant_id || org_id
  // max Date and default Date
  const currentDate = dayjs(new Date())
  const currentYear = currentDate.year()
  const currentMonth = currentDate.month() + 1
  // min Date 2021-9
  const minDate = dayjs('2023-9')
  const minYear = minDate.year().toString()
  const minMonth = (minDate.month() + 1).toString()

  const [invoiceDate, setInvoiceDate] = useState<{
    year: number
    month: number
  }>({
    year: currentYear,
    month: currentMonth
  })

  const billingPeriod = dayjs(`${invoiceDate.year}-${invoiceDate.month}`)

  const currentMonthBill = useBillingGetPartnerBills(
    billingPeriod.format('YYYY-MM'),
    { accessOrgId: orgId }
  )

  const error = currentMonthBill.error
    ? getErrorMessage(currentMonthBill.error)
    : ''

  const loading = currentMonthBill.isLoading

  const debouncedHandleChange = useDebounceFn(
    (year: number, month: number) => {
      setInvoiceDate({ year, month })
    },
    { wait: 200 }
  )

  const toNegative = (discount: string) => {
    return -Number(discount)
  }

  const usageDetailColumns = useMemo<MRT_ColumnDef<FormsPartnerBillsDetail>[]>(
    () => [
      {
        header: 'Billed Date',
        accessorKey: 'billedDate'
      },
      {
        header: 'Customer Name',
        accessorFn(originalRow) {
          return originalRow.customerName || '-'
        }
      },
      {
        header: 'Project Name',
        accessorFn(originalRow) {
          return originalRow.projectName || '-'
        }
      },
      {
        header: 'Cluster Name',
        accessorFn(originalRow) {
          return originalRow.clusterName || '-'
        }
      },
      {
        header: 'Service',
        accessorKey: 'service',
        accessorFn(originalRow) {
          return originalRow.servicePathName || '-'
        }
      },
      {
        header: 'Running Total',
        accessorFn: ({ runningTotal }) => {
          const num = isZero(runningTotal) ? '0' : runningTotal
          return <MoneyValue amount={num || '0'} />
        },
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      },
      {
        header: 'Discounts',
        id: 'discounts',
        accessorFn: ({ discounts }) => {
          const num = isZero(discounts) ? '0' : discounts
          return <MoneyValue amount={toNegative(num || '0')} negativeZero />
        },
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      },
      {
        header: 'Credits',
        accessorFn: ({ credits }) => {
          const num = isZero(credits) ? '0' : credits
          return <MoneyValue amount={toNegative(num || '0')} negativeZero />
        },
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      },
      {
        header: 'Total Cost',
        accessorKey: 'billable_cost',
        accessorFn: ({ totalCost }) => {
          const num = isZero(totalCost) ? '0' : totalCost
          return <MoneyValue amount={num || '0'} />
        },
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      }
    ],
    []
  )

  // do not show Export CSV and Summary by Service on current month
  const isCurrentMonth =
    invoiceDate.year === currentYear && invoiceDate.month === currentMonth

  const currentBill = currentMonthBill?.data?.data || {}

  const customerCosts = genCustomerCosts(currentBill.summaryByCustomer)
  const projectCosts = genProjectCosts(currentBill.summaryByProject)

  const serviceCosts = genServiceCosts(currentBill.summaryByService)

  const colorScheme = useComputedColorScheme()
  const isLight = colorScheme === 'light'
  const theme = useTheme(colorScheme)

  const footerRenders = useMemo(
    () => ({
      runningTotal: () => {
        return (
          <MoneyValue
            display="block"
            c={isLight ? theme.black : undefined}
            amount={currentBill?.overview?.runningTotal || ''}
          ></MoneyValue>
        )
      },
      discounts: () => {
        return (
          <MoneyValue
            display="block"
            c={isLight ? theme.black : undefined}
            amount={toNegative(currentBill?.overview?.discounts || '0')}
            negativeZero
          ></MoneyValue>
        )
      },
      credits: () => {
        return (
          <MoneyValue
            display="block"
            c={isLight ? theme.black : undefined}
            amount={toNegative(currentBill?.overview?.credits || '0')}
            negativeZero
          ></MoneyValue>
        )
      },
      totalCost: () => {
        return (
          <MoneyValue
            display="block"
            c={isLight ? theme.black : undefined}
            amount={currentBill?.overview?.totalCost || ''}
          ></MoneyValue>
        )
      }
    }),
    [currentBill, isLight, theme]
  )

  const renderCell = <T extends Record<string, any> = {}>({
    cell,
    ...rest
  }: ProTableCellProps<T>) => {
    const value = cell.getValue()
    const Cell = renderExpandCell({ cell, ...rest })
    return hasBeta(value) ? <BetaTips>{Cell}</BetaTips> : Cell
  }

  const byCustomerColumns = useMemo<MRT_ColumnDef<FormsCustomerBills>[]>(
    () => [
      {
        id: 'name',
        header: 'Customer Bills',
        accessorKey: 'customerName',
        Cell: renderCell,
        footer: loading ? undefined : 'Total'
      },
      {
        header: 'Running Total',
        accessorFn: ({ runningTotal }) => (
          <MoneyValue amount={runningTotal || '0'} />
        ),
        Footer: loading ? undefined : footerRenders.runningTotal,
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      },
      {
        header: 'Discounts',
        accessorFn: ({ discounts }) => {
          return (
            <MoneyValue amount={toNegative(discounts || '0')} negativeZero />
          )
        },
        Footer: loading ? undefined : footerRenders.discounts,
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      },
      {
        header: 'Credits',
        accessorFn: ({ credits }) => (
          <MoneyValue amount={toNegative(credits || '0')} negativeZero />
        ),
        Footer: loading ? undefined : footerRenders.credits,
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      },
      {
        header: 'Total Cost',
        accessorFn: ({ totalCost }) => <MoneyValue amount={totalCost || '0'} />,
        id: 'usage',
        Footer: loading ? undefined : footerRenders.totalCost,
        size: 106,
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      }
    ],
    [footerRenders, loading]
  )

  const byServiceColumns = useMemo<
    MRT_ColumnDef<FormsPartnerBillsServiceCosts>[]
  >(
    () => [
      {
        accessorKey: 'serviceName',
        header: 'Service Bills',
        // for skeleton loading state
        footer: loading ? undefined : 'Total',
        Cell: renderCell
      },
      {
        header: 'Running Total',
        accessorFn: ({ runningTotal }) => (
          <MoneyValue amount={runningTotal || '0'} />
        ),
        Footer: loading ? undefined : footerRenders.runningTotal,
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      },
      {
        header: 'Discounts',
        accessorFn: ({ discounts }) => {
          return (
            <MoneyValue amount={toNegative(discounts || '0')} negativeZero />
          )
        },
        Footer: loading ? undefined : footerRenders.discounts,
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      },
      {
        header: 'Credits',
        accessorFn: ({ credits }) => (
          <MoneyValue amount={toNegative(credits || '0')} negativeZero />
        ),
        Footer: loading ? undefined : footerRenders.credits,
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      },
      {
        header: 'Total Cost',
        accessorFn: ({ totalCost }) => <MoneyValue amount={totalCost || '0'} />,
        id: 'usage',
        size: 106,
        Footer: loading ? undefined : footerRenders.totalCost,
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      }
    ],
    [footerRenders, loading]
  )

  const byProjectColumns = useMemo<MRT_ColumnDef<FormsBillsProjects>[]>(
    () => [
      {
        id: 'name',
        header: 'Project Bills',
        accessorKey: 'projectName',
        Cell: renderCell,
        footer: loading ? undefined : 'Total'
      },
      {
        header: 'Running Total',
        accessorFn: ({ runningTotal }) => (
          <MoneyValue amount={runningTotal || '0'} />
        ),
        Footer: loading ? undefined : footerRenders.runningTotal,
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      },
      {
        header: 'Discounts',
        accessorFn: ({ discounts }) => {
          return (
            <MoneyValue amount={toNegative(discounts || '0')} negativeZero />
          )
        },
        Footer: loading ? undefined : footerRenders.discounts,
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      },
      {
        header: 'Credits',
        accessorFn: ({ credits }) => (
          <MoneyValue amount={toNegative(credits || '0')} negativeZero />
        ),
        Footer: loading ? undefined : footerRenders.credits,
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      },
      {
        header: 'Total Cost',
        accessorFn: ({ totalCost }) => <MoneyValue amount={totalCost || '0'} />,
        id: 'usage',
        Footer: loading ? undefined : footerRenders.totalCost,
        size: 106,
        mantineTableHeadCellProps: {
          align: 'right'
        },
        mantineTableBodyCellProps: {
          align: 'right'
        }
      }
    ],
    [footerRenders, loading]
  )

  const {
    data: billsDetails,
    isFetching,
    error: billsError
  } = useBillingGetPartnerBillsDetails(
    billingPeriod.format('YYYY-MM'),
    { accessOrgId: orgId },
    {
      query: {
        refetchInterval: false,
        refetchOnWindowFocus: false
      },
      request: {
        timeout: 45 * 1000
      }
    }
  )

  const usageDetailError = billsError ? getErrorMessage(billsError) : ''

  const currentBillingPeriod = `${billingPeriod.format(
    'MMM'
  )} 1 - ${billingPeriod.format(
    'MMM'
  )} ${billingPeriod.daysInMonth()}, ${billingPeriod.year()}`

  const isMdScreen = useMediaQuery('(max-width: 1440px)')

  return (
    <Box m="xl">
      <Card
        withBorder
        p={24}
        sx={() => ({
          overflow: 'initial'
        })}
      >
        <Grid grow>
          <Grid.Col span={isMdScreen ? 'auto' : 4}>
            <Flex align="center" justify="space-between">
              <MonthPicker
                // start form the first day of each month
                minDate={dayjs(`${minYear}-${minMonth}`)}
                maxDate={dayjs(`${currentYear}-${currentMonth}`)}
                onDateChange={debouncedHandleChange.run}
                w={isMdScreen ? 180 : 190}
              />
              <CostsLabel
                label="Billing Period"
                value={currentBillingPeriod}
                ml={12}
                sx={() => ({
                  display: isMdScreen ? 'none' : undefined
                })}
              />
              <Divider
                orientation="vertical"
                ml={isMdScreen ? 24 : undefined}
                mr={isMdScreen ? 8 : 30}
              />
            </Flex>
          </Grid.Col>
          <Grid.Col span={isMdScreen ? 9 : 8}>
            <OnDemandBillingOverview
              bill={currentBill?.overview}
              spacing={isMdScreen ? 24 : 64}
            />
          </Grid.Col>
        </Grid>
      </Card>

      <BillsCard title="Summary by Customer" mt={24}>
        <ProTable
          columns={byCustomerColumns}
          data={customerCosts || []}
          loading={loading}
          emptyMessage={'No Data'}
          errorMessage={error}
          mantinePaperProps={{ mt: 8 }}
          mantineTableFooterProps={{
            display: projectCosts?.length ? undefined : 'none'
          }}
        />
      </BillsCard>

      <BillsCard title="Summary by Project" mt={24}>
        <ProTable
          columns={byProjectColumns}
          data={projectCosts || []}
          loading={loading}
          emptyMessage={'No Data'}
          errorMessage={error}
          mantinePaperProps={{ mt: 8 }}
          mantineTableFooterProps={{
            display: projectCosts?.length ? undefined : 'none'
          }}
        />
      </BillsCard>

      <BillsCard title="Summary by Service" mt={24}>
        {
          <ProTable
            data={serviceCosts || []}
            columns={byServiceColumns}
            loading={loading}
            errorMessage={error}
            emptyMessage="No Data"
            mantinePaperProps={{ my: 8 }}
            mantineTableFooterProps={{
              display: serviceCosts?.length ? undefined : 'none'
            }}
          />
        }
        {isCurrentMonth && (
          <Typography variant="body-md">
            <strong>Note:</strong> Due to delays and other reasons, the billing
            details of the current month are for reference only. You cannot
            reconcile your account based on the data. The details of the final
            consumption for the present month are based on the data of the next
            month.
          </Typography>
        )}
      </BillsCard>
      <BillsCard
        title="Usage Details"
        mt={24}
        mb={24}
        rightSection={
          <CSVExport
            month={invoiceDate.month}
            orgId={orgId}
            year={invoiceDate.year}
          />
        }
      >
        <ProTable
          columns={usageDetailColumns}
          enableStickyHeader
          enablePinning
          loading={isFetching}
          errorMessage={usageDetailError}
          emptyMessage="No Data"
          data={billsDetails?.data?.details || []}
          initialState={{ columnPinning: { right: ['billable_cost'] } }}
          mantinePaperProps={{ my: 8 }}
          mantineTableHeadProps={{ opacity: 1 }}
          mantineTableContainerProps={{ sx: { maxHeight: '400px' } }}
          enableRowVirtualization
        ></ProTable>
      </BillsCard>
    </Box>
  )
}
