import { Flex } from '@tidbcloud/uikit'
import { Table, Space, Typography, Spin, Row } from 'antd'
import { ColumnsType } from 'antd/lib/table'
import { startCase, camelCase, capitalize } from 'lodash'
import React, { useCallback, useMemo, useState, useEffect } from 'react'
import { useParams } from 'react-router-dom'

import {
  listInvoices,
  useGetInvoice,
  confirmInvoice,
  useListStripeInvoices,
  suspendInvoice,
  stripeCreditCardPaymentRequiredNotification
} from 'apiClient/services/billing'
import { FormsStripeInvoice } from 'apiClient/services/billing/interface'
import {
  FormsBillingConfig,
  FormsInvoice
} from 'apiClient/services/billing/interface'
import CurrencyValue from 'components/currency/Value'
import { ListToolBar } from 'components/Table'
import { format } from 'utils/time'

import BillCosts from './BillCosts'
import { ConfirmCell } from './ConfirmCell'
import { CreateCommitmentInvoice } from './CreateInvoice'
import InvoiceDetailsModalForm from './InvoiceDetailsModalForm'

const { Text } = Typography

const StripeInvoices: React.FC<
  React.PropsWithChildren<{ orgId: string; billingConfigId: number }>
> = ({ orgId, billingConfigId }) => {
  const { data, isLoading, isRefetching, refetch } = useListStripeInvoices(
    orgId,
    billingConfigId,
    {
      query: {
        refetchInterval: 60 * 1000
      }
    }
  )

  const columns: ColumnsType<FormsStripeInvoice> = [
    {
      title: 'Month',
      dataIndex: 'created',
      render(value, record) {
        return format(
          Number.parseInt(record.created || '0') * 1000,
          undefined,
          'YYYY-MM'
        )
      }
    },
    {
      title: 'Invoice ID',
      dataIndex: 'number'
    },
    {
      title: 'Date Due',
      dataIndex: 'date_due',
      render(value, record) {
        if (record.due_date === '0') {
          return '-'
        }
        return format(
          Number.parseInt(record.due_date || '0') * 1000,
          undefined,
          'YYYY-MM-DD'
        )
      }
    },
    {
      title: 'Status',
      dataIndex: 'status',
      render(value, record) {
        return record.status ? capitalize(record.status) : '-'
      }
    },
    {
      title: 'Charge',
      dataIndex: 'total',
      render(value, record) {
        return <CurrencyValue isCent={false} value={record.total} />
      }
    },
    {
      title: 'Credit Used',
      dataIndex: 'credit_used',
      render(value, record) {
        return <CurrencyValue isCent={false} value={record.credit_used} />
      }
    },
    {
      title: 'Amount Due',
      dataIndex: 'amount_due',
      render(value, record) {
        return <CurrencyValue isCent={false} value={record.amount_due} />
      }
    },
    {
      title: 'Paid',
      dataIndex: 'amount_paid',
      render(value, record) {
        return <CurrencyValue isCent={false} value={record.amount_paid} />
      }
    },
    {
      title: 'Action',
      render(value, record) {
        if (!record.invoice_pdf) {
          return ''
        }
        return (
          <Flex gap={12}>
            <a
              download={`invoice-${format(
                Number.parseInt(record.created || '0') * 1000,
                undefined,
                'YYYY-MM'
              )}.pdf`}
              href={record.invoice_pdf}
            >
              Export
            </a>
            {record.status === 'open' && (
              <ConfirmCell
                key={record.id || ''}
                popconfirmTitle="Are you sure to require payment for this bill?"
                labels={{
                  trigger: 'Require Payment',
                  confirmed: 'Sent',
                  confirming: 'Sending notification...'
                }}
                onConfirm={async () => {
                  await stripeCreditCardPaymentRequiredNotification(
                    orgId,
                    billingConfigId,
                    record.id?.toString() || '',
                    {
                      isShowMessage: true
                    }
                  )
                  refetch()
                }}
              />
            )}
          </Flex>
        )
      }
    }
  ]

  return (
    <div>
      <ListToolBar
        title={'Stripe Invoices'}
        reload={async () => {
          await refetch()
        }}
      />
      <Table
        columns={columns}
        size="small"
        rowKey="number"
        loading={isLoading || isRefetching}
        dataSource={data?.data || []}
      />
    </div>
  )
}

const InvoiceDetails: React.FC<
  React.PropsWithChildren<{
    invoiceId: string
    orgId: string
    billingConfigId: number
  }>
> = ({ invoiceId, orgId, billingConfigId }) => {
  const { data } = useGetInvoice(orgId, billingConfigId, invoiceId)
  if (!data) {
    return (
      <Row style={{ display: 'flex', justifyContent: 'center' }}>
        <Spin />
      </Row>
    )
  }
  return (
    <BillCosts
      category_unit_costs={data.data.category_unit_costs}
      tax_rate={data.data.tax_rate}
      withTaxRate
    />
  )
}

export const TenantBills: React.FC<
  React.PropsWithChildren<{ billingConfig: FormsBillingConfig }>
> = ({ billingConfig }) => {
  const { org_id: orgId } = useParams<{ org_id: string }>()
  const org_id = billingConfig.tenant_id || orgId
  const [invoices, setInvoices] = useState<FormsInvoice[]>([])
  const [invoice, setInvoice] = useState<FormsInvoice | null>(null)
  const [detailsModalVisible, setDetailsModalVisible] = useState(false)
  const [loading, setLoading] = useState(true)

  const getData = async () => {
    setLoading(true)
    try {
      const data = (
        await listInvoices(
          org_id,
          billingConfig.billing_config_id,
          { brief: true },
          { timeout: 20 * 1000 }
        )
      ).data
      setInvoices(data)
    } catch (e) {
    } finally {
      setLoading(false)
    }
  }

  useEffect(() => {
    getData()
    // eslint-disable-next-line
  }, [])

  const renderActionCell = useCallback(
    (_: any, record: FormsInvoice) => {
      const { status } = record

      const handleOpen = () => {
        setInvoice(record)
        setDetailsModalVisible(true)
      }

      return (
        <Space>
          <a onClick={handleOpen}>Details</a>
          {status === 'generated' && (
            <>
              <ConfirmCell
                key={record.invoice_id}
                popconfirmTitle="Are you sure to confirm this bill?"
                onConfirm={async () => {
                  await confirmInvoice(
                    record.tenant_id!.toString(),
                    record.binded_billing_config_id as any,
                    record.invoice_id!.toString(),
                    {
                      isShowMessage: true
                    }
                  )
                  getData()
                }}
              />
              <ConfirmCell
                key={record.invoice_id}
                popconfirmTitle="Are you sure to suspend this bill?"
                labels={{
                  trigger: 'Suspend',
                  confirmed: 'Suspended',
                  confirming: 'Suspending...'
                }}
                onConfirm={async () => {
                  await suspendInvoice(
                    record.tenant_id!.toString(),
                    record.binded_billing_config_id as any,
                    record.invoice_id!.toString(),
                    {
                      isShowMessage: true
                    }
                  )
                  getData()
                }}
              />
            </>
          )}
        </Space>
      )
    },
    // eslint-disable-next-line
    [org_id]
  )

  const columns = useMemo(() => {
    const dataCols = ['status', 'start_date', 'end_date', 'cost_price'].map(
      (_) => {
        if (['start_date', 'end_date'].includes(_)) {
          return {
            title: startCase(camelCase(_)),
            dataIndex: _,
            render: (text: any, record: FormsInvoice) => (
              <Text>
                {format(
                  record[_ as 'start_date' | 'end_date'],
                  'en',
                  'YYYY-MM',
                  0
                )}
              </Text>
            )
          }
        }

        if (_ === 'cost_price') {
          return {
            title: startCase(camelCase(_)),
            dataIndex: _,
            render: (text: any, record: FormsInvoice) => (
              <CurrencyValue isCent={false} value={record.cost_price} />
            )
          }
        }

        return {
          title: startCase(camelCase(_)),
          dataIndex: _
        }
      }
    )
    return [
      ...dataCols,
      {
        title: 'Action',
        dataIndex: 'action',
        render: renderActionCell
      }
    ]
  }, [renderActionCell])

  const onDetailsModalClose = useCallback(() => {
    setDetailsModalVisible(false)
  }, [])

  return (
    <>
      <ListToolBar
        title={'All Invoices'}
        reload={getData}
        actions={[
          <CreateCommitmentInvoice
            billingConfig={billingConfig}
            orgId={org_id}
            onComplete={() => getData()}
          />
        ]}
      />

      <Table<FormsInvoice>
        columns={columns}
        rowKey="invoice_id"
        dataSource={invoices}
        loading={loading}
        size="small"
        expandable={{
          expandedRowRender: (record) => (
            <InvoiceDetails
              orgId={org_id}
              billingConfigId={billingConfig.billing_config_id}
              invoiceId={record.invoice_id.toString() || ''}
              key={invoice?.invoice_id}
            />
          )
        }}
      />

      <StripeInvoices
        orgId={org_id}
        billingConfigId={billingConfig.billing_config_id}
      />

      {/* Bill Details ModalForm */}
      {invoice && (
        <InvoiceDetailsModalForm
          orgId={org_id}
          billingConfigId={billingConfig.billing_config_id}
          key={invoice.invoice_id}
          open={detailsModalVisible}
          invoice={invoice}
          onCancel={onDetailsModalClose}
        />
      )}
    </>
  )
}

export default TenantBills
