import { ApartmentOutlined, FolderOutlined } from '@ant-design/icons'
import { Col, Divider, Row, Space, Statistic, Typography } from 'antd'
import Table, { ColumnsType } from 'antd/lib/table'
import dayjs, { Dayjs } from 'dayjs'
import React, { useState, useMemo, useEffect } from 'react'
import { useParams } from 'react-router-dom'

import { useGetTenantByID } from 'apiClient/api'
import {
  useGetBillsDetails,
  getMonthlyBillsExport,
  exportMonthBillCSV,
  useGetMonthlyCost,
  useListTenantSupportPlans
} from 'apiClient/services/billing'
import {
  FormsBindedSupportPlan,
  FormsBillingConfig,
  FormsCosts,
  FormsCategoryCosts,
  FormsPrice,
  FormsUsageDetails
} from 'apiClient/services/billing/interface'
import CurrencyValue, { formatCurrencyValue } from 'components/currency/Value'
import { DatePicker } from 'components/DatePicker'
import {
  calculateTieredCostBreakdown,
  formatEffectiveRate,
  formatTieredPriceRule
} from 'pages/Tenants/TenantDetail/BusinessInfo/supportPlanPricing'
import { downloadCSV } from 'utils/dom'

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

const useBillingOverview = (orgId: string) => {
  const { data } = useGetTenantByID(orgId, {
    query: { retry: false, refetchOnWindowFocus: false }
  })
  const hasDiscount = data?.data?.has_discount
  // const discountDesc = 'Discount'
  const discount = Number(data?.data?.discount)

  const discountDisplay = useMemo(
    () => (discount ? `${100 - discount}%` : '-'),
    [discount]
  )
  return {
    hasDiscount,
    discountDisplay
  }
}

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

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

  return <a onClick={onDownload}>Download CSV</a>
}
interface CategoryCosts extends FormsCategoryCosts {
  category_item_unit_costs?: FormsCosts['category_item_unit_costs']
  order?: number
}

const SERVICE_PLAN_ICONS = ['premium', 'essential', 'starter', 'byoc']

const hasServicePlanIcon = (servicePlan?: string | null) =>
  SERVICE_PLAN_ICONS.includes((servicePlan || '').toLowerCase())

function genProjectsCosts(
  costs: { [key: string]: CategoryCosts },
  credits: { [key: string]: CategoryCosts },
  totalCosts: { [key: string]: CategoryCosts },
  depth = 0,
  parentRowKey = 'root'
): CostsItem[] {
  const keysMap: { [key: string]: number } = {}

  // get all keys from costs and credits
  // get all keys from costs and credits
  Object.keys(costs).forEach((key) => {
    keysMap[key] = costs[key].order || 0
  })
  Object.keys(credits).forEach((key) => {
    keysMap[key] = credits[key].order || 0
  })

  // adjust order by data
  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]
    })

  return keys.map((key, index) => {
    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 totalCost = totalCosts[key] || {
      cost_price: '0',
      raw_price: '0',
      discount_price: '0'
    }
    const rowKey = `${parentRowKey}/${depth}-${index}-${key}`
    const children = genProjectsCosts(
      bill.category_item_unit_costs || bill.category_unit_costs || {},
      credit.category_item_unit_costs || credit.category_unit_costs || {},
      totalCost.category_item_unit_costs || totalCost.category_unit_costs || {},
      depth + 1,
      rowKey
    )

    return {
      rowKey,
      name: key,
      bill,
      credit,
      costs: totalCost,
      depth,
      servicePlan:
        costs[key]?.service_plan ||
        credits[key]?.service_plan ||
        totalCost.service_plan,
      children: children.length ? children : undefined
    }
  })
}

interface CostsItem {
  rowKey: string
  name: string
  bill: FormsPrice
  credit: FormsPrice
  costs: FormsPrice
  depth: number
  servicePlan?: string | null
  supportPlanTierRule?: boolean
  tieredEffectiveRate?: number
  children?: CostsItem[]
}

const isSupportPlan = (item: CostsItem) =>
  item.name.trim().toLowerCase() === 'support plan'

const TIERED_SUPPORT_PLAN_TYPES = ['tiered_price', 'tiered']

const withTieredSupportPlan = (
  costs: CostsItem[],
  supportPlan?: FormsBindedSupportPlan
) => {
  const rules = supportPlan?.tiered_price_rules
  if (
    !supportPlan ||
    !TIERED_SUPPORT_PLAN_TYPES.includes(supportPlan.type || '') ||
    !rules?.length
  ) {
    return costs
  }

  const actualUsage = costs.reduce((total, item) => {
    if (isSupportPlan(item)) {
      return total
    }

    const cost = Number(item.costs.cost_price)
    return Number.isFinite(cost) ? total + cost : total
  }, 0)

  return costs.map((item) => {
    if (!isSupportPlan(item)) {
      return item
    }

    const breakdown = calculateTieredCostBreakdown(
      item.costs.cost_price,
      actualUsage,
      rules
    )

    return {
      ...item,
      children: [
        ...(item.children || []),
        ...rules.map((rule, index) => ({
          rowKey: `${item.rowKey}/tiered-price-rule-${index}`,
          name: formatTieredPriceRule(rule),
          bill: { cost_price: '' },
          credit: { cost_price: '' },
          costs: {
            cost_price: '',
            raw_price: breakdown?.[index]?.cost.toString() || '0'
          },
          depth: item.depth + 1,
          supportPlanTierRule: true,
          tieredEffectiveRate: breakdown?.[index]?.effectiveRate
        }))
      ]
    }
  })
}

const renderProjectBillName = (record: CostsItem) => {
  if (record.depth > 0) {
    return record.name
  }

  const isInstance = hasServicePlanIcon(record.servicePlan)
  const showFolder =
    !isInstance && record.name.toLowerCase() !== 'other charges'

  return (
    <Space size={8}>
      {isInstance && <ApartmentOutlined style={{ color: '#8c8c8c' }} />}
      {showFolder && <FolderOutlined style={{ color: '#8c8c8c' }} />}
      <span>{record.name}</span>
    </Space>
  )
}

export const Bills: React.FC<
  React.PropsWithChildren<{
    billingConfig: FormsBillingConfig
    useBillingConfigOrg?: boolean
  }>
> = ({ billingConfig }) => {
  const defaultMonth = dayjs()
  const currentYear = defaultMonth.get('year')
  const currentMonth = defaultMonth.get('month') + 1
  const { org_id: orgID } = useParams<{ org_id: string }>()
  const org_id = billingConfig.tenant_id || orgID

  const { discountDisplay } = useBillingOverview(org_id)

  const [selectedMonth, setSelectedMonth] = useState({
    year: defaultMonth.get('year'),
    // start from 0
    month: defaultMonth.get('month') + 1
  })

  const onMonthChange = (date: Dayjs) => {
    if (!date) {
      return
    }
    setSelectedMonth({
      year: date.get('year'),
      month: date.get('month') + 1
    })
  }

  const { data, isLoading, isFetching } = useGetMonthlyCost(
    org_id,
    billingConfig.billing_config_id,
    selectedMonth.year.toString(),
    selectedMonth.month.toString(),
    {
      query: {
        retry: false,
        refetchOnWindowFocus: false
      }
    }
  )

  const currentBill = data?.data

  const {
    data: supportPlansData,
    isLoading: isLoadingSupportPlans,
    isFetching: isFetchingSupportPlans
  } = useListTenantSupportPlans(org_id, billingConfig.billing_config_id, {
    query: {
      retry: false,
      refetchOnWindowFocus: false
    }
  })

  const activeSupportPlan = supportPlansData?.data.find(
    (supportPlan) => supportPlan.status === 'active'
  )

  const projectCosts = genProjectsCosts(
    currentBill?.invoice_costs?.label_unit_costs?.project || {},
    currentBill?.credits_costs?.label_unit_costs?.project || {},
    currentBill?.total_costs?.label_unit_costs?.project || {}
  )
  const hasProjectServicePlan = projectCosts.some((item) =>
    hasServicePlanIcon(item.servicePlan)
  )

  const useItemCosts =
    !!currentBill?.invoice_costs?.category_use_item &&
    !!currentBill?.credits_costs?.category_use_item

  const isPrev =
    selectedMonth.year < currentYear ||
    (selectedMonth.year === currentYear && selectedMonth.month < currentMonth)

  const label: keyof FormsCosts = useItemCosts
    ? 'kind_category_units_costs'
    : 'category_item_unit_costs'
  const serviceCosts = withTieredSupportPlan(
    genProjectsCosts(
      currentBill?.invoice_costs?.[label] || {},
      currentBill?.credits_costs?.[label] || {},
      currentBill?.total_costs?.[label] || {}
    ),
    activeSupportPlan
  )

  const byProjectColumns = useMemo<ColumnsType<CostsItem>>(
    () => [
      {
        title: hasProjectServicePlan
          ? 'Project & Instance Bills'
          : 'Project Bills',
        dataIndex: 'name',
        render(value, record) {
          return renderProjectBillName(record)
        }
      },
      {
        title: 'Running Total',
        render(value, record) {
          return (
            <CurrencyValue
              isCent={false}
              align="right"
              value={record.costs.raw_price}
            ></CurrencyValue>
          )
        },
        align: 'right'
      },
      {
        title: 'Discounts',
        render(value, record) {
          return (
            <CurrencyValue
              isCent={false}
              align="right"
              prefix="-$"
              value={record.costs.discount_price}
            ></CurrencyValue>
          )
        },
        align: 'right',
        width: 140
      },
      {
        title: 'Credits',
        render(value, record) {
          return (
            <CurrencyValue
              isCent={false}
              align="right"
              prefix="-$"
              value={record.credit.cost_price}
            ></CurrencyValue>
          )
        },
        align: 'right',
        width: 140
      },
      {
        title: 'Total Cost',
        render(value, record) {
          return (
            <CurrencyValue
              isCent={false}
              align="right"
              value={record.bill.cost_price}
            ></CurrencyValue>
          )
        },
        align: 'right',
        width: 140
      }
    ],
    [hasProjectServicePlan]
  )

  const byServiceColumns = useMemo<ColumnsType<CostsItem>>(
    () => [
      {
        title: 'Service Bills',
        render(value, record) {
          return record.name
        },
        id: 'name'
      },
      {
        title: 'Running Total',
        render(value, record) {
          return (
            <CurrencyValue
              align="right"
              isCent={false}
              value={record.costs.raw_price || 0}
              suffix={
                record.tieredEffectiveRate === undefined
                  ? undefined
                  : `(${formatEffectiveRate(record.tieredEffectiveRate)}%)`
              }
            ></CurrencyValue>
          )
        },
        align: 'right'
      },
      {
        title: 'Discounts',
        render(value, record) {
          if (record.supportPlanTierRule) {
            return null
          }
          return (
            <CurrencyValue
              align="right"
              isCent={false}
              prefix="-$"
              value={record.costs.discount_price}
            ></CurrencyValue>
          )
        },
        align: 'right',
        width: 140
      },
      {
        title: 'Credits',
        render(value, record) {
          if (record.supportPlanTierRule) {
            return null
          }
          return (
            <CurrencyValue
              align="right"
              prefix="-$"
              isCent={false}
              value={record.credit.cost_price}
            ></CurrencyValue>
          )
        },
        id: 'usage',
        align: 'right',
        width: 140
      },
      {
        title: 'Total Cost',
        render(value, record) {
          if (record.supportPlanTierRule) {
            return null
          }
          return (
            <CurrencyValue
              align="right"
              isCent={false}
              value={record.bill.cost_price}
            ></CurrencyValue>
          )
        },
        width: 140,
        id: 'usage',
        align: 'right'
      }
    ],
    [discountDisplay]
  )

  const usageDetailColumns = useMemo<ColumnsType<FormsUsageDetails>>(
    () => [
      {
        title: 'Billed Date',
        dataIndex: 'billed_date'
      },
      {
        title: 'Project Name',
        dataIndex: 'project_name'
      },
      {
        title: 'Cluster Name',
        dataIndex: 'cluster_name'
      },
      {
        title: 'Service',
        dataIndex: 'service'
      },
      {
        title: 'Running Total',
        dataIndex: 'amount',
        render(value, record, index) {
          const num = isZero(record.amount) ? '0' : record.amount
          return <CurrencyValue isCent={false} align="right" value={num} />
        },
        align: 'right',
        width: 140
      },
      {
        title: 'Discounts',
        dataIndex: 'discount_cost',
        render(value, record, index) {
          const num = isZero(record.discount_cost) ? '0' : record.discount_cost
          return (
            <CurrencyValue
              isCent={false}
              align="right"
              prefix="-$"
              value={num}
            />
          )
        },
        align: 'right',
        width: 140
      },
      {
        title: 'Credits',
        dataIndex: 'credit_usage',
        render(value, record, index) {
          const num = isZero(record.credit_usage) ? '0' : record.credit_usage
          return (
            <CurrencyValue
              prefix="-$"
              isCent={false}
              align="right"
              value={num}
            />
          )
        },
        align: 'right',
        width: 140
      },
      {
        title: 'Total Cost',
        dataIndex: 'billable_cost',
        render(value, record, index) {
          const num = isZero(record.billable_cost) ? '0' : record.billable_cost
          return <CurrencyValue isCent={false} align="right" value={num} />
        },
        align: 'right',
        fixed: 'right',
        width: 140
      }
    ],
    []
  )

  const {
    data: billsDetails,
    isFetching: isFetchingUsage,
    isLoading: isLoadingUsage,
    refetch
    // error: billsError
  } = useGetBillsDetails(
    org_id,
    billingConfig.billing_config_id,
    selectedMonth.year.toString(),
    selectedMonth.month.toString(),
    {
      query: {
        enabled: useItemCosts,
        retry: false,
        refetchOnWindowFocus: false
      }
    }
  )

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

  const format = (amount: number | string | undefined) => {
    return formatCurrencyValue(amount, false)
  }

  const billFooter = () => {
    return (
      <>
        <Table.Summary.Row style={{ fontWeight: 700 }}>
          <Table.Summary.Cell index={0}>Total</Table.Summary.Cell>
          <Table.Summary.Cell index={1}>
            <CurrencyValue
              align="right"
              isCent={false}
              value={currentBill?.total_costs?.raw_price || ''}
            />
          </Table.Summary.Cell>
          <Table.Summary.Cell index={2}>
            <CurrencyValue
              align="right"
              isCent={false}
              prefix="-$"
              value={currentBill?.total_costs?.discount_price || ''}
            />
          </Table.Summary.Cell>
          <Table.Summary.Cell index={3}>
            <CurrencyValue
              align="right"
              prefix="-$"
              isCent={false}
              value={currentBill?.credits_costs?.cost_price || ''}
            />
          </Table.Summary.Cell>
          <Table.Summary.Cell index={4}>
            <CurrencyValue
              align="right"
              isCent={false}
              value={currentBill?.invoice_costs?.cost_price || ''}
            />
          </Table.Summary.Cell>
        </Table.Summary.Row>
      </>
    )
  }

  return (
    <div>
      <Row gutter={16} align="middle">
        <Col span={5}>
          <Row align="middle">
            <Col>
              <Typography.Text strong>Select Month</Typography.Text>
            </Col>
            <Col flex={'16px'}></Col>
            <DatePicker
              defaultValue={defaultMonth}
              picker="month"
              onChange={onMonthChange}
            ></DatePicker>
          </Row>
        </Col>
        <Col span={5}>
          <Statistic
            title="Billing Period"
            value={`${selectedMonth.month}/1/${selectedMonth.year} - ${
              selectedMonth.month
            }/${dayjs(
              selectedMonth.year + '-' + selectedMonth.month
            ).daysInMonth()}/${selectedMonth.year}`}
          />
        </Col>
        <Col span={1}>
          <Divider type="vertical"></Divider>
        </Col>
        <Col span={13}>
          <Row gutter={16}>
            <Col span={6}>
              <Statistic
                title="Running Total"
                prefix="$"
                precision={2}
                value={format(currentBill?.total_costs?.raw_price || '')}
              />
            </Col>
            <Col span={6}>
              <Statistic
                title="Discounts"
                prefix="-$"
                precision={2}
                value={format(currentBill?.total_costs?.discount_price || '')}
              />
            </Col>
            <Col span={6}>
              <Statistic
                title="Credits"
                prefix="-$"
                precision={2}
                value={format(currentBill?.credits_costs?.cost_price || '')}
              />
            </Col>
            <Col span={6}>
              <Statistic
                title="Total Cost"
                prefix="$"
                precision={2}
                value={format(currentBill?.invoice_costs?.cost_price || '')}
              />
            </Col>
          </Row>
        </Col>
      </Row>
      <Divider></Divider>
      <Row>
        <Col span={24}>
          <Row style={{ marginBottom: 8 }}>
            <Col flex="auto">
              <Typography.Text strong>Summary by Project</Typography.Text>
            </Col>
            <Col>
              {isPrev && (
                <CSVExport
                  year={selectedMonth.year}
                  month={selectedMonth.month}
                  billingConfigId={billingConfig.billing_config_id}
                  orgId={org_id}
                  type="project"
                />
              )}
            </Col>
          </Row>
          <Table
            loading={isLoading || isFetching}
            dataSource={projectCosts || []}
            columns={byProjectColumns}
            pagination={false}
            rowKey="rowKey"
            summary={billFooter}
          ></Table>
        </Col>
      </Row>
      <Row style={{ marginTop: 24 }}>
        <Col span={24}>
          <div style={{ marginBottom: 8 }}>
            <Typography.Text strong>Summary by Service</Typography.Text>
          </div>
          <Table
            loading={
              isLoading ||
              isFetching ||
              isLoadingSupportPlans ||
              isFetchingSupportPlans
            }
            dataSource={serviceCosts || []}
            columns={byServiceColumns}
            pagination={false}
            rowKey="rowKey"
            summary={billFooter}
          ></Table>
        </Col>
      </Row>
      <Row style={{ marginTop: 24 }}>
        <Col span={24}>
          <Row style={{ marginBottom: 8 }}>
            <Col flex="auto">
              <Typography.Text strong>Usage Detail</Typography.Text>
            </Col>
            <Col>
              {useItemCosts && (
                <CSVExport
                  year={selectedMonth.year}
                  month={selectedMonth.month}
                  billingConfigId={billingConfig.billing_config_id}
                  orgId={org_id}
                  type="usage"
                />
              )}
            </Col>
          </Row>
          <Table
            loading={isLoadingUsage || isFetchingUsage}
            dataSource={billsDetails?.data?.details || []}
            columns={usageDetailColumns}
            pagination={false}
            rowKey={(record, index) =>
              [
                record.billed_date || '',
                record.project_name || '',
                record.cluster_name || '',
                record.service || '',
                index ?? 0
              ].join('-')
            }
            scroll={{ x: 1500, y: 600 }}
          ></Table>
        </Col>
      </Row>
    </div>
  )
}
