import { Box, Card, Divider, Flex, Grid } from '@tidbcloud/uikit'
import { useMediaQuery } from '@tidbcloud/uikit/hooks'
import { debounce } from 'lodash-es'
import { observer } from 'mobx-react'
import React, { useEffect, useState } from 'react'

import dayjs from 'dbaas/components/dayjs'
import { HeroComponent } from 'dbaas/components/Measurement'
import MonthPicker from 'dbaas/components/MonthPicker'
import { OrgPlanStatus } from 'dbaas/screens/Plans/constant'
import { useGetExpWhiteList } from 'dbaas/services/api'
import { useGetBillsDetails, useGetMonthlyCost } from 'dbaas/services/billing'
import { FormsBillingConfig, FormsCosts } from 'dbaas/services/billing/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import { ExpFeatHashmap } from 'dbaas/stores/localStorage'
import useStores from 'dbaas/stores/useStores'
import { addOffsetUTC } from 'dbaas/utils/format'

import { OnDemandBillingOverview, useCurrentBillingCycle } from '../components/BillingOverview'
import { BillsCard } from '../components/BillsCard'
import { CostsLabel } from '../components/CostsItem'
import { TimezoneTips } from '../components/HeadLabel'
import { buildMonthlyBillFromCostItems, zeroByocCostItems } from '../helpers/byoc-bill'

import { CSVExport, genProjectsCosts } from './helpers'
import { InstanceBills } from './InstanceBills'
import { ProjectBillsTable } from './ProjectBillsTable'
import { ServiceBillsTable } from './ServiceBillsTable'
import { UsageDetailsTable } from './UsageDetailsTable'

export const Bills: React.FC<React.PropsWithChildren<{ billingConfig: FormsBillingConfig }>> = observer(
  ({ billingConfig }) => {
    const {
      store: {
        tenantData,
        config: { premiumEnabled, enableByocBill }
      }
    } = useStores()
    const orgId = tenantData.id
    const { data: useCassandraServiceNames = false } = useGetExpWhiteList(orgId, undefined, {
      query: {
        enabled: !!orgId,
        select: (data) => data?.exp_names?.includes(ExpFeatHashmap.CassandraEnable) ?? false,
        refetchInterval: false,
        refetchOnMount: false,
        refetchOnWindowFocus: false
      }
    })

    // 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.max([dayjs(addOffsetUTC(tenantData.created_at, tenantData.timezone || 0)), dayjs('2021-9')])
    const minYear = minDate.year().toString()
    const minMonth = (minDate.month() + 1).toString()

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

    const { data: bill, isLoading: loading } = useGetMonthlyCost(
      orgId,
      billingConfig.billing_config_id,
      invoiceDate.year.toString(),
      invoiceDate.month.toString(),
      {
        query: {
          enabled: !!billingConfig && !!billingConfig.billing_config_id,
          onError(err: any) {
            setError(err.response?.data?.message || 'Unknown Error')
          },
          refetchInterval: false,
          refetchOnWindowFocus: false
        }
      }
    )

    const currentMonthBill = useCurrentBillingCycle(tenantData.id, billingConfig)

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

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

    const currentBill = isCurrentMonth ? currentMonthBill?.data : bill
    const useItemCosts =
      !!currentBill?.invoice_costs?.category_use_item && !!currentBill?.credits_costs?.category_use_item

    const projectCosts = genProjectsCosts(
      currentBill?.invoice_costs?.label_unit_costs?.project || {},
      currentBill?.credits_costs?.label_unit_costs?.project || {},
      currentBill?.total_costs?.label_unit_costs?.project || {},
      (key) => {
        if (key.toLowerCase() === 'Other Charges'.toLowerCase()) {
          return useItemCosts
        }
        return false
      }
    )

    const label: keyof FormsCosts = useItemCosts ? 'kind_category_units_costs' : 'category_item_unit_costs'

    const serviceCosts = genProjectsCosts(
      currentBill?.invoice_costs?.[label] || {},
      currentBill?.credits_costs?.[label] || {},
      currentBill?.total_costs?.[label] || {},
      useItemCosts
    )
    const visibleServiceCosts = enableByocBill ? zeroByocCostItems(serviceCosts) : serviceCosts
    const visibleServiceBill = enableByocBill
      ? buildMonthlyBillFromCostItems(currentBill, visibleServiceCosts)
      : currentBill

    const {
      data: billsDetails,
      isFetching,
      refetch,
      error: billsError,
      isFetched
    } = useGetBillsDetails(
      orgId,
      billingConfig.billing_config_id,
      invoiceDate.year.toString(),
      invoiceDate.month.toString(),
      {
        query: {
          enabled: useItemCosts && !enableByocBill,
          refetchInterval: false,
          refetchOnWindowFocus: false
        },
        request: {
          timeout: 45 * 1000
        }
      }
    )

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

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

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

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

    useEffect(() => {
      if (useItemCosts && !enableByocBill) {
        refetch()
      }
    }, [enableByocBill, useItemCosts, refetch])

    const ProjectExport =
      !enableByocBill && !isCurrentMonth && tenantData.plan !== OrgPlanStatus.POC ? (
        <CSVExport
          configId={billingConfig.billing_config_id}
          year={invoiceDate.year}
          month={invoiceDate.month}
          orgId={orgId}
          type="project"
        />
      ) : null

    const UsageExport =
      !enableByocBill && useItemCosts && !useCassandraServiceNames ? (
        <CSVExport
          configId={billingConfig.billing_config_id}
          year={invoiceDate.year}
          month={invoiceDate.month}
          orgId={orgId}
          type="usage"
        />
      ) : null

    return (
      <Box pb={96}>
        <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}
                  w={isMdScreen ? 180 : 190}
                />
                <CostsLabel
                  label={
                    <Flex align="center" gap={4}>
                      Billing Period <TimezoneTips />
                    </Flex>
                  }
                  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={visibleServiceBill} spacing={isMdScreen ? 24 : 64} />
            </Grid.Col>
          </Grid>
        </Card>

        {premiumEnabled ? (
          <InstanceBills
            projectData={projectCosts}
            serviceData={visibleServiceCosts}
            usageData={billsDetails?.details || []}
            loading={loading}
            currentBill={visibleServiceBill}
            error={error}
            isCurrentMonth={isCurrentMonth}
            ProjectExport={ProjectExport}
            UsageExport={UsageExport}
            useCassandraServiceNames={useCassandraServiceNames}
            hideResourceAndUsage={enableByocBill}
          />
        ) : (
          <>
            {!enableByocBill && (
              <BillsCard title="Summary by Project" rightSection={ProjectExport} mt={24}>
                <ProjectBillsTable data={projectCosts} loading={loading} error={error} currentBill={currentBill} />
              </BillsCard>
            )}

            <BillsCard title="Summary by Service" mt={24}>
              <ServiceBillsTable
                data={visibleServiceCosts}
                loading={loading}
                error={error}
                isCurrentMonth={isCurrentMonth}
                currentBill={visibleServiceBill}
                useCassandraServiceNames={useCassandraServiceNames}
              />
            </BillsCard>

            {!enableByocBill && (
              <BillsCard title="Usage Details" rightSection={UsageExport} mt={24} mb={24}>
                <UsageDetailsTable
                  data={billsDetails?.details || []}
                  loading={isFetching}
                  error={usageDetailError}
                  useCassandraServiceNames={useCassandraServiceNames}
                />
              </BillsCard>
            )}
          </>
        )}

        {isFetched && <HeroComponent />}
      </Box>
    )
  }
)
