import { CreditCardFilled } from '@ant-design/icons'
import { ReloadOutlined } from '@ant-design/icons'
import { Table, Row, Col, Card, Button, Form, Select, Typography } from 'antd'
import { ColumnsType } from 'antd/lib/table'
import Text from 'antd/lib/typography/Text'
import React, { Fragment, useEffect, useMemo, useState } from 'react'
import { useQueryClient } from 'react-query'

import {
  getBillingCompany,
  listBillingCompany,
  updateBillingCompany
} from 'apiClient/api'
import {
  FormsBillingCompany,
  FormsBillingInformation,
  FormsStripePaymentMethod,
  FormsTenantBillingCompany,
  FormsTenantBillingCompanyInput
} from 'apiClient/api/interface'
import {
  useGetBillingInfo,
  useUpdateTenantTaxRate,
  useListTenantPaymentMethods,
  useListTenantPaymentTypes,
  setupPaymentMethod,
  getListTenantPaymentMethodsQueryKey,
  listStripePaymentMethods,
  useGetActivePaymentMethod,
  useGetAzureSubscriptions,
  deleteAzureSubscription
} from 'apiClient/services/billing'
import {
  FormsBillingConfig,
  FormsSubscriptionDetails
} from 'apiClient/services/billing/interface'
import ModalForm from 'components/ModalForm'
import { ListToolBar } from 'components/Table'
import { capitalize } from 'utils/string'
import { format } from 'utils/time'

import { TaxIDMap } from './tax'
import { UpdateInvoiceable, UpdatePaymentCodeForm } from './Update'

const LegalEntityForm: React.FC<
  React.PropsWithChildren<{
    orgId: string
  }>
> = ({ orgId }) => {
  const [visible, setVisible] = useState(false)
  const [companies, setCompnies] = useState<FormsBillingCompany[]>([])
  const [billingCompany, setBillingCompany] =
    useState<FormsTenantBillingCompany>({})

  const fetchBillingCompany = () => {
    getBillingCompany(orgId)
      .then((resp) => {
        setBillingCompany(resp.data)
      })
      .catch((e) => {})
  }

  const fetchCompany = () => {
    listBillingCompany()
      .then((resp) => {
        setCompnies(resp.data)
      })
      .catch((e) => {})
  }

  useEffect(() => {
    fetchCompany()
    fetchBillingCompany()
  }, [])

  const onSubmit = async (data: FormsTenantBillingCompanyInput) => {
    await updateBillingCompany(orgId, {
      ...data
    })
    await fetchBillingCompany()
    setVisible(false)
  }

  const renderFormFields = () => {
    return (
      <>
        <Form.Item label="Entity">
          <Form.Item
            name="company_key"
            rules={[{ required: true, message: 'Required' }]}
            noStyle
          >
            <Select>
              {companies.map((co) => (
                <Select.Option
                  key={co.company_key}
                  value={co.company_key || ''}
                >
                  {co.name || co.company_key}
                </Select.Option>
              ))}
            </Select>
          </Form.Item>
        </Form.Item>
      </>
    )
  }

  const entity = useMemo(() => {
    return (
      companies.find((co) => co.company_key === billingCompany.company_key)
        ?.name || billingCompany.company_key
    )
  }, [billingCompany, companies])

  return (
    <p>
      Legal Entity: {entity || 'Not Set'}{' '}
      <Button type="link" onClick={() => setVisible(true)}>
        Edit
      </Button>
      <ModalForm<FormsTenantBillingCompanyInput>
        title="Update Legal Entity"
        visible={visible}
        initValues={billingCompany}
        name="update-company-form"
        onSubmit={onSubmit}
        onCancel={() => setVisible(false)}
        getFields={renderFormFields}
      ></ModalForm>
    </p>
  )
}

interface UpdatePaymentMethodFormData {
  payment_type: string
}

const UpdatePaymentMethodForm: React.FC<
  React.PropsWithChildren<{
    orgId: string
    billingConfigId: number
    defaultValues?: UpdatePaymentMethodFormData
  }>
> = ({ orgId, defaultValues, billingConfigId }) => {
  const [visible, setVisible] = useState(false)
  const { data, refetch } = useListTenantPaymentTypes(orgId, billingConfigId)

  const queryClient = useQueryClient()

  const onSubmit = async (data: UpdatePaymentMethodFormData) => {
    await setupPaymentMethod(orgId, billingConfigId, data.payment_type)
    refetch()
    queryClient.invalidateQueries(
      getListTenantPaymentMethodsQueryKey(orgId, billingConfigId)
    )
    setVisible(false)
  }

  const renderFormFields = () => {
    return (
      <>
        <Form.Item label="Payment Method">
          <Form.Item
            name="payment_type"
            rules={[{ required: true, message: 'Required' }]}
            noStyle
          >
            <Select>
              {data?.data.map((co) => (
                <Select.Option
                  key={co.payment_type}
                  value={co.payment_type || ''}
                >
                  {PaymentTypes[(co.payment_type || '').toLowerCase()] ||
                    co.payment_type?.toUpperCase()}
                  {co.payable ? ' (Payable)' : ' (UnPayable)'}
                </Select.Option>
              ))}
            </Select>
          </Form.Item>
        </Form.Item>
      </>
    )
  }

  return (
    <>
      <Button type="link" onClick={() => setVisible(true)}>
        Edit
      </Button>
      <ModalForm<UpdatePaymentMethodFormData>
        title="Update Payment Method"
        visible={visible}
        initValues={defaultValues}
        name="update-payment-method-form"
        onSubmit={onSubmit}
        onCancel={() => setVisible(false)}
        getFields={renderFormFields}
      ></ModalForm>
    </>
  )
}

const BillingProfile: React.FC<React.PropsWithChildren<{ orgId: string }>> = ({
  orgId
}) => {
  const { isLoading, mutateAsync } = useUpdateTenantTaxRate()
  const { data, refetch } = useGetBillingInfo(orgId)

  const address = useMemo(() => {
    return ['line2', 'line1', 'city', 'state', 'country', 'postal_code']
      .map((k: keyof FormsBillingInformation) => {
        return data?.data[k] || ''
      })
      .filter((item) => !!item)
      .join(', ')
  }, [data])

  const taxId = useMemo(() => {
    if (!data?.data.tax_vat) {
      return 'Not Set'
    }
    const type = TaxIDMap[data.data.country_code + ':' + data?.data.tax_id_type]
    if (type) {
      return type.description + ' (' + data.data.tax_vat + ')'
    }
    return data.data.tax_vat
  }, [data])

  return (
    <Card title="Billing Profile">
      <LegalEntityForm orgId={orgId} />
      <p>
        <Text strong>Business Legal address</Text>
      </p>
      <p>{address || 'Not Set'}</p>
      <Text strong>Business Tax ID</Text>
      <p>{taxId}</p>
      <Text strong>Tax Rate</Text>
      <p>
        <Typography.Text type={data?.data.tax_rate ? 'success' : 'warning'}>
          {data?.data.tax_rate?.rate !== undefined &&
          data.data.tax_rate?.rate !== null
            ? data?.data.tax_rate.display_name +
              '(' +
              data?.data.tax_rate.rate +
              '%)'
            : 'Not Set'}
        </Typography.Text>
        <Button
          type="link"
          icon={<ReloadOutlined />}
          loading={isLoading}
          onClick={async () => {
            try {
              await mutateAsync({ tenantId: orgId })
              await refetch()
            } catch (e) {}
          }}
        >
          Refresh
        </Button>
      </p>
    </Card>
  )
}
const PaymentTypes: Record<string, string> = {
  stripe: 'Credit Card',
  gcp: 'GCP Marketplace',
  aws: 'AWS Marketplace',
  azure: 'Azure Marketplace',
  alicloud: 'AliCloud',
  wire_transfer: 'Wire Transfer'
}

const formatPaymentTypeLabel = (
  paymentType?: string,
  isThirdParty?: boolean
) => {
  const normalizedPaymentType = (paymentType || '').toLowerCase()

  if (normalizedPaymentType === 'alicloud') {
    return isThirdParty ? 'AliCloud Co-sell' : 'AliCloud Resell'
  }

  if (PaymentTypes[normalizedPaymentType]) {
    return PaymentTypes[normalizedPaymentType]
  }

  return paymentType
    ?.split('_')
    .map((segment) => capitalize(segment))
    .join(' ')
}

const PaymentMethods: React.FC<
  React.PropsWithChildren<{ orgId: string; billingConfigId: number }>
> = ({ orgId, billingConfigId }) => {
  const { data } = useListTenantPaymentMethods(orgId, billingConfigId)

  return (
    <Card title="Payment">
      {data && !!data.data.length ? (
        data.data
          .filter((d) => d.status === 'active')
          .map((p, index) => {
            const isCPPOPayment = p.payment_method_meta?.is_aws_cppo_payment
            const width = isCPPOPayment ? 180 : 116
            return (
              <Fragment key={(p.payment_method_id || '') + index.toString()}>
                <p>
                  <Text strong style={{ width, display: 'inline-block' }}>
                    Payment Method
                  </Text>
                  <span style={{ marginLeft: '2rem' }}>
                    {formatPaymentTypeLabel(
                      p.payment_type,
                      p.payment_method_meta?.is_third_party
                    )}
                    {p.managed_by_sales && ' (Manual Billing)'}
                  </span>
                  <UpdatePaymentMethodForm
                    orgId={orgId}
                    defaultValues={{ payment_type: p.payment_type || '' }}
                    billingConfigId={billingConfigId}
                  />
                </p>
                <p>
                  <Text strong style={{ width, display: 'inline-block' }}>
                    Payment Code
                  </Text>
                  <span style={{ marginLeft: '2rem' }}>
                    {p.payment_code || 'Null'}
                  </span>
                  {isCPPOPayment && !p.invoiceable && (
                    <UpdatePaymentCodeForm
                      orgId={orgId}
                      defaultValues={{
                        payment_code: p.payment_code || '',
                        payment_sub_code: p.payment_sub_code || ''
                      }}
                      paymentType={p.payment_type || ''}
                      billingConfigId={billingConfigId}
                    />
                  )}
                </p>
                {isCPPOPayment && (
                  <>
                    <p>
                      <Text strong style={{ width, display: 'inline-block' }}>
                        Secondary Payment Code
                      </Text>
                      <span style={{ marginLeft: '2rem' }}>
                        {p.payment_sub_code || 'Null'}
                      </span>
                    </p>
                    <p>
                      <Text strong style={{ width, display: 'inline-block' }}>
                        Invoiceable
                      </Text>
                      <span style={{ marginLeft: '2rem' }}>
                        {p.invoiceable ? 'Yes' : 'No'}
                      </span>
                      {!p.invoiceable && (
                        <UpdateInvoiceable
                          orgId={orgId}
                          paymentType={p.payment_type || ''}
                          billingConfigId={billingConfigId}
                        />
                      )}
                    </p>
                  </>
                )}
              </Fragment>
            )
          })
      ) : (
        <p>
          <Text strong>Payment Method</Text>
          <span style={{ marginLeft: '2rem' }}>Not Set</span>
          <UpdatePaymentMethodForm
            orgId={orgId}
            billingConfigId={billingConfigId}
          />
        </p>
      )}
    </Card>
  )
}

export const StripePaymentMethod: React.FC<
  React.PropsWithChildren<{
    billingConfig: FormsBillingConfig
  }>
> = ({ billingConfig }) => {
  const [loading, setLoading] = useState(false)
  const [payments, setPayments] = useState<FormsStripePaymentMethod[]>([])
  const orgId = billingConfig.tenant_id || ''
  const { data: activePayment } = useGetActivePaymentMethod(
    orgId,
    billingConfig.billing_config_id
  )
  const getData = async () => {
    setLoading(true)
    try {
      const resp = await listStripePaymentMethods(
        orgId,
        billingConfig.billing_config_id
      )
      setPayments(resp.data)
      setLoading(false)
    } catch (e) {
      setLoading(false)
    }
  }
  const columns: ColumnsType<FormsStripePaymentMethod> = [
    {
      title: 'Bank',
      render: (_: any, record: FormsStripePaymentMethod) => {
        return (
          <span>
            <CreditCardFilled /> {record.id}
          </span>
        )
      }
    },
    {
      title: 'Card Number',
      render: (_: any, record: FormsStripePaymentMethod) => {
        return `**** **** **** ${record.card?.last4}`
      }
    },
    {
      title: 'Exp Date',
      render: (_: any, record: FormsStripePaymentMethod) => {
        return (
          record.card?.exp_month?.padStart(2, '0') + '/' + record.card?.exp_year
        )
      }
    }
  ]

  useEffect(() => {
    getData()
  }, [])

  return (
    <div>
      <Row>
        <Col span={14}>
          <Card>
            {activePayment?.data?.payment_type === 'azure' ? (
              <AzureSubscriptions
                code={activePayment?.data.payment_code || ''}
              />
            ) : (
              <>
                <ListToolBar reload={getData}></ListToolBar>
                <Table
                  columns={columns}
                  dataSource={payments}
                  size="small"
                  loading={loading}
                  rowKey="id"
                ></Table>
              </>
            )}
          </Card>
        </Col>
        <Col span={9} offset={1}>
          <div style={{ marginBottom: '20px' }}>
            <PaymentMethods
              orgId={orgId}
              billingConfigId={billingConfig.billing_config_id}
            />
          </div>
          <BillingProfile orgId={orgId} />
        </Col>
      </Row>
    </div>
  )
}

export const AzureSubscriptions = ({ code }: { code: string }) => {
  const { data, refetch } = useGetAzureSubscriptions(code)
  const columns: ColumnsType<FormsSubscriptionDetails> = [
    {
      title: 'ID',
      dataIndex: 'id'
    },
    {
      title: 'Name',
      dataIndex: 'name'
    },
    {
      title: 'Status',
      dataIndex: 'saasSubscriptionStatus',
      render(_, record) {
        return capitalize(record?.saasSubscriptionStatus?.toLowerCase() || '')
      }
    },
    {
      title: 'Start Date',
      render(_value, record) {
        return record?.term?.startDate ? format(record.term?.startDate) : '-'
      }
    },
    {
      title: 'End Date',
      render(_value, record) {
        return record?.term?.endDate ? format(record.term?.endDate) : '-'
      }
    },
    {
      title: 'Actions',
      width: 78,
      render(_value, record) {
        if (record.saasSubscriptionStatus === 'Subscribed') {
          return (
            <CancelAzureSubscription id={record.id || ''} onDeleted={refetch} />
          )
        }
        return ''
      }
    }
  ]

  return (
    <>
      <ListToolBar
        title="Azure Subscriptions"
        reload={async () => {
          await refetch()
        }}
      />
      <Table columns={columns} dataSource={data?.data?.subscriptions || []} />
    </>
  )
}

const CancelAzureSubscription = ({
  id,
  onDeleted
}: {
  id: string
  onDeleted?: () => void
}) => {
  const [visible, setVisible] = useState(false)

  const onSubmit = async () => {
    await deleteAzureSubscription(id)
    onDeleted?.()
    setVisible(false)
  }
  return (
    <>
      <Button danger onClick={() => setVisible(true)} type="link">
        Cancel
      </Button>
      <ModalForm
        onSubmit={onSubmit}
        name="confirm-model-form"
        title="Confirm"
        visible={visible}
        okText="Confirm"
        okButtonProps={{ danger: true }}
        getFields={() => {
          return (
            <>
              <Typography.Title level={5}>
                Are you sure to cancel the Azure subscription?
              </Typography.Title>
              <div>Important to note:</div>
              <ul>
                <li style={{ listStyle: 'inside' }}>
                  Make sure if there is any pending payments of this customer?
                </li>
                <li style={{ listStyle: 'inside' }}>
                  After you cancel the subscription, the customer's org will
                  return to the state of unpayable.
                </li>
              </ul>
            </>
          )
        }}
        onCancel={() => setVisible(false)}
      ></ModalForm>
    </>
  )
}
