import { SearchOutlined } from '@ant-design/icons'
import {
  Button,
  Col,
  Input,
  message,
  Popconfirm,
  Row,
  Space,
  Spin,
  Table,
  Typography
} from 'antd'
import { ColumnsType } from 'antd/lib/table'
import { FilterValue } from 'antd/lib/table/interface'
import dayjs from 'dayjs'
import { capitalize } from 'lodash'
import React, { useCallback, useMemo, useState } from 'react'

import {
  confirmInvoice,
  postApiV1DevopsBillingProxyApiV1BillingPaying,
  useListStripeInvoices,
  useListAllInvoices,
  useGetInvoice,
  suspendInvoice
} from 'apiClient/services/billing'
import {
  FormsInvoiceForOpsList,
  FormsStripeInvoice
} from 'apiClient/services/billing/interface'
import CurrencyValue from 'components/currency/Value'
import { DatePicker } from 'components/DatePicker'
import { ListToolBar } from 'components/Table'
import { ConfirmCell } from 'pages/Tenants/TenantDetail/BusinessInfo/Billing/Invoices/ConfirmCell'
import { format } from 'utils/time'

import BillCosts from './BillCosts'
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 = useMemo<ColumnsType<FormsStripeInvoice>>(() => {
    return [
      {
        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 (
            <a
              download={`invoice-${format(
                Number.parseInt(record.created || '0') * 1000,
                undefined,
                'YYYY-MM'
              )}.pdf`}
              href={record.invoice_pdf}
            >
              Export
            </a>
          )
        }
      }
    ]
  }, [])

  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: string
  }>
> = ({ invoiceId, orgId, billingConfigId }) => {
  const { data } = useGetInvoice(orgId, billingConfigId as any, 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
    />
  )
}

const DATE_FORMAT = 'YYYY-MM-DDTHH:mm:ss[Z]'
const USD_FORMATTER = new Intl.NumberFormat('en-US', {
  style: 'currency',
  currency: 'USD'
})
const INVOICE_STATUSES = [
  'inited',
  'generated',
  'confirmed',
  'sent',
  'paid',
  'suspended',
  'split',
  'below_threshold_carry',
  'expired_carryover'
]
const PAYMENT_TYPES = ['stripe', 'wire_transfer']

interface InvoiceTableFilters {
  id: FilterValue | null
  payment_type: FilterValue | null
  status: FilterValue | null
}

export const Invoices: React.FC<React.PropsWithChildren<unknown>> = () => {
  const [invoice, setInvoice] = useState<FormsInvoiceForOpsList | null>(null)
  const [detailsModalVisible, setDetailsModalVisible] = useState(false)
  const [isConfirmingCurrentMonth, setIsConfirmingCurrentMonth] =
    useState(false)
  const [tableFilters, setTableFilters] = useState<InvoiceTableFilters>({
    id: null,
    payment_type: ['stripe'],
    status: null
  })
  const [date, setDate] = useState(dayjs())
  const selectedMonth = date.format('YYYY-MM')
  const dateRange = useMemo(
    () => ({
      from: date.startOf('month').format(DATE_FORMAT),
      to: date.add(1, 'month').startOf('month').format(DATE_FORMAT)
    }),
    [date]
  )

  const {
    data: invoices,
    isLoading,
    isRefetching,
    refetch
  } = useListAllInvoices(
    { brief: true, from: dateRange.from, to: dateRange.to },
    { query: { refetchOnWindowFocus: false } }
  )

  const invoiceSummary = useMemo(() => {
    const tenantSearch = String(tableFilters.id?.[0] || '').toLowerCase()
    const data = (invoices?.data || []).filter((invoice) => {
      const matchesTenant =
        !tenantSearch ||
        (invoice.tenant_name || '').toLowerCase().includes(tenantSearch) ||
        String(invoice.tenant_id || '')
          .toLowerCase()
          .includes(tenantSearch)
      const matchesStatus =
        !tableFilters.status?.length ||
        tableFilters.status.includes(invoice.status || '')
      const matchesPaymentType =
        !tableFilters.payment_type?.length ||
        tableFilters.payment_type.includes(invoice.payment_type || '')

      return matchesTenant && matchesStatus && matchesPaymentType
    })
    return {
      amount: data.reduce(
        (total, invoice) => total + (Number(invoice.cost_price) || 0),
        0
      )
    }
  }, [invoices?.data, tableFilters])

  const columns = useMemo(() => {
    return [
      {
        title: 'Tenant',
        width: 210,
        dataIndex: 'id',
        filteredValue: tableFilters.id,
        filterDropdown: ({
          clearFilters,
          confirm,
          selectedKeys,
          setSelectedKeys
        }: any) => (
          <div style={{ padding: 8 }}>
            <Input.Search
              autoFocus
              placeholder="Search by name or ID"
              value={selectedKeys[0]}
              onChange={(event) =>
                setSelectedKeys(event.target.value ? [event.target.value] : [])
              }
              onSearch={() => confirm()}
              style={{ display: 'block', marginBottom: 8, width: 260 }}
            />
            <Button
              onClick={() => {
                clearFilters?.()
                confirm()
              }}
              size="small"
              type="link"
            >
              Reset
            </Button>
          </div>
        ),
        filterIcon: (filtered: boolean) => (
          <SearchOutlined style={{ color: filtered ? '#1677ff' : undefined }} />
        ),
        onFilter: (
          value: string | number | boolean,
          record: FormsInvoiceForOpsList
        ) => {
          const search = String(value).trim().toLowerCase()
          return (
            (record.tenant_name || '').toLowerCase().includes(search) ||
            String(record.tenant_id || '')
              .toLowerCase()
              .includes(search)
          )
        },
        render: (_: any, record: FormsInvoiceForOpsList) => (
          <Row>
            <Col span={24}>
              {record.tenant_name ? (
                <Typography.Text
                  style={{ width: 210 }}
                  ellipsis={{ tooltip: record.tenant_name }}
                >
                  {record.tenant_name}
                </Typography.Text>
              ) : (
                <span style={{ color: '#aaa' }}>-</span>
              )}
            </Col>
            <Col span={24}>
              <Typography.Text type="secondary">
                {record.tenant_id}
              </Typography.Text>
            </Col>
          </Row>
        )
      },
      {
        title: 'Status',
        dataIndex: 'status',
        filteredValue: tableFilters.status,
        filters: INVOICE_STATUSES.map((status) => ({
          text: status,
          value: status
        })),
        filterMultiple: true,
        onFilter: (
          value: string | number | boolean,
          record: FormsInvoiceForOpsList
        ) => record.status === value
      },
      {
        title: 'Payment',
        dataIndex: 'payment_type',
        filteredValue: tableFilters.payment_type,
        filters: PAYMENT_TYPES.map((paymentType) => ({
          text: paymentType,
          value: paymentType
        })),
        filterMultiple: true,
        onFilter: (
          value: string | number | boolean,
          record: FormsInvoiceForOpsList
        ) => record.payment_type === value,
        render: (paymentType: string | undefined) => paymentType || '-'
      },
      {
        title: 'Start Date',
        dataIndex: 'start_date',
        render: (text: any, record: FormsInvoiceForOpsList) => (
          <Text>{format(record.start_date, 'en', 'YYYY-MM')}</Text>
        )
      },
      {
        title: 'End Date',
        dataIndex: 'end_date',
        render: (text: any, record: FormsInvoiceForOpsList) => (
          <Text>{format(record.end_date, 'en', 'YYYY-MM')}</Text>
        )
      },
      {
        title: 'Cost Price',
        dataIndex: 'cost_price',
        render: (text: any, record: FormsInvoiceForOpsList) => (
          <CurrencyValue isCent={false} value={record.cost_price} />
        )
      },
      {
        title: 'Action',
        dataIndex: 'action',
        render: (_: any, record: FormsInvoiceForOpsList) => {
          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
                        }
                      )
                      refetch()
                    }}
                  />
                  <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
                        }
                      )
                      refetch()
                    }}
                  />
                </>
              )}
            </Space>
          )
        }
      }
    ]
  }, [refetch, tableFilters])

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

  const confirmSelectedMonthInvoices = async () => {
    setIsConfirmingCurrentMonth(true)
    try {
      await postApiV1DevopsBillingProxyApiV1BillingPaying(
        { month: selectedMonth },
        { isShowMessage: true }
      )
      message.success(`Invoice confirmation task created for ${selectedMonth}`)
    } finally {
      setIsConfirmingCurrentMonth(false)
    }
  }

  return (
    <>
      <ListToolBar
        title={'All Invoices'}
        reload={async () => {
          await refetch()
        }}
        actions={[
          <Space
            align="center"
            size="middle"
            style={{ height: 32, fontSize: 12 }}
          >
            <Text style={{ fontSize: 'inherit' }}>
              Amount:{' '}
              <Text strong style={{ fontSize: 14 }}>
                {isLoading || isRefetching
                  ? '...'
                  : USD_FORMATTER.format(invoiceSummary.amount)}
              </Text>
            </Text>
          </Space>,
          <DatePicker
            picker="month"
            value={date}
            onChange={(val) => setDate(val!)}
            allowClear={false}
          />
          // <CreateCommitmentInvoice
          //   billingConfig={billingConfig}
          //   orgId={org_id}
          //   onComplete={() => getData()}
          // />
        ]}
        trailingActions={[
          <Popconfirm
            title={`Confirm all invoices for ${selectedMonth}?`}
            onConfirm={confirmSelectedMonthInvoices}
            okText="Yes"
            cancelText="No"
          >
            <Button loading={isConfirmingCurrentMonth} type="primary">
              Confirm Current Month
            </Button>
          </Popconfirm>
        ]}
      />

      <Table<FormsInvoiceForOpsList>
        columns={columns}
        rowKey="invoice_id"
        dataSource={invoices?.data}
        loading={isLoading || isRefetching}
        size="small"
        onChange={(_, filters) =>
          setTableFilters({
            id: filters.id || null,
            payment_type: filters.payment_type || null,
            status: filters.status || null
          })
        }
        pagination={{
          showTotal: (total) => (
            <Text style={{ fontSize: 14 }}>Total: {total}</Text>
          )
        }}
        expandable={{
          expandedRowRender: (record) => (
            <InvoiceDetails
              orgId={record.tenant_id!.toString()}
              billingConfigId={record.binded_billing_config_id!}
              invoiceId={record.invoice_id!.toString()}
              key={record.invoice_id}
            />
          )
        }}
      />

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

      {/* Bill Details ModalForm */}
      {invoice && (
        <InvoiceDetailsModalForm
          orgId={invoice.tenant_id!.toString()}
          billingConfigId={invoice.binded_billing_config_id!}
          key={invoice.invoice_id}
          open={detailsModalVisible}
          invoice={invoice}
          onCancel={onDetailsModalClose}
        />
      )}
    </>
  )
}

export default Invoices
