import { PlusOutlined, UploadOutlined } from '@ant-design/icons'
import {
  Table,
  Typography,
  Select,
  Button,
  Form,
  Upload,
  Popconfirm
} from 'antd'
import { ColumnsType } from 'antd/lib/table'
import { capitalize } from 'lodash'
import React, { useState, useMemo } from 'react'

import auth from 'apiClient/auth'
import { dbaasUrl } from 'apiClient/endpoint'
import {
  createContract,
  downloadContract,
  updateContract,
  useListAllContract,
  operateContract
} from 'apiClient/services/billing'
import {
  ListAllContractParams,
  FormsContract,
  FormsContractInput
} from 'apiClient/services/billing/interface'
import { FormsBillingConfig } from 'apiClient/services/billing/interface'
import Input from 'components/Input'
import ModalForm from 'components/ModalForm'
import { ListToolBar } from 'components/Table'
import { format } from 'utils/time'

enum ContractStatus {
  DRAFT = 'draft',
  DELETED = 'deleted',
  SUBMIT = 'submit', // Pending Activation
  CANCELED = 'canceled',
  ACTIVE = 'active',
  REJECTED = 'rejected',
  TERMINATED = 'terminated'
}

enum ContractOperations {
  CREATE = 'create',
  UPDATE = 'update',
  SUBMIT = 'submit',
  CANCEL = 'cancel',
  ACCEPT = 'accept',
  REJECT = 'reject',
  DELETE = 'delete',
  TERMINATE = 'terminate'
}

enum ContractType {
  SAVING_PLAN_ORDER_FORM = 'saving_plan_order_form',
  POC_AGREEMENT = 'poc_agreement',
  PREPAYMENT_ORDER_FORM = 'prepayment_order_form'
}

const ContractOperationCodes = {
  [ContractOperations.UPDATE]: 1 << 0,
  [ContractOperations.CANCEL]: 1 << 1,
  [ContractOperations.ACCEPT]: 1 << 2,
  [ContractOperations.REJECT]: 1 << 3,
  [ContractOperations.DELETE]: 1 << 4,
  [ContractOperations.TERMINATE]: 1 << 5,
  [ContractOperations.SUBMIT]: 1 << 6
}

const ContractStatusMap: Record<string, number> = {
  [ContractStatus.DRAFT]:
    ContractOperationCodes.delete |
    ContractOperationCodes.update |
    ContractOperationCodes.submit,
  [ContractStatus.SUBMIT]:
    ContractOperationCodes.cancel |
    ContractOperationCodes.accept |
    ContractOperationCodes.reject,
  [ContractStatus.ACTIVE]: ContractOperationCodes.terminate,
  [ContractStatus.CANCELED]:
    ContractOperationCodes.submit | ContractOperationCodes.update
}

const ContractTypeMap: Record<string, string> = {
  [ContractType.SAVING_PLAN_ORDER_FORM]: 'Saving Plan Order Form',
  [ContractType.POC_AGREEMENT]: 'PoC Agreement',
  [ContractType.PREPAYMENT_ORDER_FORM]: 'Prepayment Order Form',
  common: 'Common'
}

const ContractTypeOptions = [
  {
    label: 'Saving Plan Order Form',
    value: ContractType.SAVING_PLAN_ORDER_FORM
  },
  {
    label: 'PoC Agreement',
    value: ContractType.POC_AGREEMENT
  },
  {
    label: 'Prepayment Order Form',
    value: ContractType.PREPAYMENT_ORDER_FORM
  }
]

const ContractModal: React.FC<
  React.PropsWithChildren<{
    visible: boolean
    initValues?: any
    onSubmit: () => void
    onCancel: () => void
    orgId: string
    billingConfigId: number
    type?: 'add' | 'update'
  }>
> = ({
  visible,
  onSubmit,
  onCancel,
  initValues,
  orgId,
  billingConfigId,
  type = 'add'
}) => {
  const handleSubmit = async (data: FormsContractInput) => {
    if (type === 'add') {
      await createContract(orgId, billingConfigId, data)
    } else {
      await updateContract(orgId, billingConfigId, initValues.id, data)
    }
    onSubmit()
  }

  const renderFormFields = () => {
    return (
      <>
        <Form.Item
          name={'contract_type'}
          label="Contract Type"
          rules={[
            {
              required: true,
              message: 'Please Select Type'
            }
          ]}
        >
          <Select>
            {ContractTypeOptions.map((t) => (
              <Select.Option key={t.label} value={t.value}>
                {t.label}
              </Select.Option>
            ))}
          </Select>
        </Form.Item>
        <Form.Item
          name={'contract_id'}
          label="Contract ID"
          rules={[
            {
              required: true,
              message: 'Please input contract id'
            }
          ]}
        >
          <Input placeholder="Input Contract ID" type={'email'}></Input>
        </Form.Item>
        <Form.Item
          name={'contact_email'}
          label="Contact"
          rules={[
            {
              required: true,
              type: 'email',
              message: 'Invalid Email'
            }
          ]}
        >
          <Input placeholder="Input contact's email" type={'email'}></Input>
        </Form.Item>
        <Form.Item
          name={'file_path'}
          label="Upload PDF"
          // valuePropName="file.response.filePath"
          getValueFromEvent={(value) => {
            return value?.file.response?.filePath
          }}
          rules={[
            {
              required: true,
              message: 'Please upload file'
            }
          ]}
        >
          <Upload
            name={'file'}
            accept="application/pdf"
            multiple={false}
            headers={{
              Authorization: `Bearer ${auth.getAuthToken()}`,
              'X-Requested-With': null as unknown as string // 禁用默认 header，避免 CORS 预检失败
            }}
            action={`${dbaasUrl}/api/v1/admin/upload`}
          >
            <Button icon={<UploadOutlined />}>Click to upload</Button>
          </Upload>
        </Form.Item>
      </>
    )
  }

  return (
    <ModalForm<FormsContractInput>
      getFields={renderFormFields}
      visible={visible}
      initValues={
        initValues
          ? initValues
          : {
              contract_type: ContractType.SAVING_PLAN_ORDER_FORM,
              file_path: '',
              contact_email: ''
            }
      }
      title="Add a Contract"
      name="subscription-form"
      onSubmit={handleSubmit}
      onCancel={onCancel}
      okText="Save Draft"
    ></ModalForm>
  )
}

const canEdit = (status: string) => {
  return !!(
    ContractStatusMap[status] &&
    ContractStatusMap[status] & ContractOperationCodes.update
  )
}

const canSubmit = (status: string) => {
  return !!(
    ContractStatusMap[status] &&
    ContractStatusMap[status] & ContractOperationCodes.submit
  )
}

const canCancel = (status: string) => {
  return !!(
    ContractStatusMap[status] &&
    ContractStatusMap[status] & ContractOperationCodes.cancel
  )
}

const canDelete = (status: string) => {
  return !!(
    ContractStatusMap[status] &&
    ContractStatusMap[status] & ContractOperationCodes.delete
  )
}

const canTerminate = (status: string) => {
  return !!(
    ContractStatusMap[status] &&
    ContractStatusMap[status] & ContractOperationCodes.terminate
  )
}

export const Contracts: React.FC<
  React.PropsWithChildren<{ billingConfig: FormsBillingConfig }>
> = ({ billingConfig }) => {
  const [page, setPage] = useState<ListAllContractParams>({
    page: 1,
    page_size: 20
  })

  const [selectedContract, setSelectedContract] =
    useState<FormsContract | null>(null)

  const org_id = billingConfig.tenant_id || ''

  const { data, refetch, isLoading, isFetching } = useListAllContract(
    org_id,
    billingConfig.billing_config_id,
    page,
    {
      query: {
        refetchInterval: 60 * 1000
      }
    }
  )

  const getData = async () => {
    await refetch()
  }

  const columns = useMemo<ColumnsType<FormsContract>>(
    () => [
      {
        title: 'Contract ID',
        dataIndex: 'contract_id'
      },
      {
        title: 'Type',
        dataIndex: 'contract_type',
        render(value, record) {
          return ContractTypeMap[record.contract_type || '']
        }
      },
      {
        title: 'Contact',
        dataIndex: 'contact_email'
      },
      {
        title: 'Status',
        dataIndex: 'status',
        render(value, record) {
          const { status, reason_for_last_operation, operated_at } = record
          return (
            <>
              {status === ContractStatus.SUBMIT
                ? 'Pending Activation'
                : capitalize(status)}
              {reason_for_last_operation && operated_at ? (
                <>
                  {' '}
                  ({reason_for_last_operation} on{' '}
                  {format(operated_at, undefined, 'YYYY-MM-DD HH:mm:ss Z')})
                </>
              ) : null}
            </>
          )
        }
      },
      {
        title: 'PDF',
        render: (value, row) => {
          const onDownload = async () => {
            const data = await downloadContract(
              org_id,
              billingConfig.billing_config_id,
              row.id?.toString() || '',
              {
                responseType: 'arraybuffer'
              }
            )
            const file = new Blob([data.data as any as ArrayBuffer], {
              type: 'application/pdf'
            })
            const fileUrl = URL.createObjectURL(file)
            const a = document.createElement('a')
            document.body.appendChild(a)
            a.href = fileUrl
            a.download = `contract-${row.contract_id}.pdf`
            a.click()
            setTimeout(() => {
              document.body.removeChild(a)
            }, 0)
          }
          return (
            <div>
              <a onClick={onDownload}>Download</a>
            </div>
          )
        }
      },
      {
        title: 'Created At',
        render: (value, row) => {
          return format(row.created_at, undefined, 'YYYY-MM-DD HH:mm:ss Z')
        }
      },
      {
        title: 'Actions',
        render: (value, row) => {
          return (
            <div>
              {canEdit(row.status || '') && (
                <Button
                  type="link"
                  size="small"
                  onClick={() => {
                    setSelectedContract(row)
                  }}
                >
                  Edit
                </Button>
              )}
              {canSubmit(row.status || '') && (
                <Popconfirm
                  title={`Submit ${row.contract_id}?`}
                  placement="right"
                  okText="Confirm"
                  cancelText="Cancel"
                  onConfirm={async () => {
                    await operateContract(
                      org_id,
                      billingConfig.billing_config_id,
                      row.id?.toString() || '',
                      'submit'
                    )
                    refetch()
                  }}
                >
                  <Button type="link" size="small">
                    Submit
                  </Button>
                </Popconfirm>
              )}
              {canCancel(row.status || '') && (
                <Popconfirm
                  title={`Cancel ${row.contract_id}?`}
                  placement="right"
                  okText="Confirm"
                  cancelText="Cancel"
                  onConfirm={async () => {
                    await operateContract(
                      org_id,
                      billingConfig.billing_config_id,
                      row.id?.toString() || '',
                      'cancel'
                    )
                    refetch()
                  }}
                >
                  <Button type="link" size="small">
                    Cancel
                  </Button>
                </Popconfirm>
              )}
              {canTerminate(row.status || '') && (
                <Popconfirm
                  title={`Terminate ${row.contract_id}?`}
                  placement="right"
                  okText="Confirm"
                  cancelText="Cancel"
                  onConfirm={async () => {
                    await operateContract(
                      org_id,
                      billingConfig.billing_config_id,
                      row.id?.toString() || '',
                      'terminate'
                    )
                    refetch()
                  }}
                >
                  <Button type="link" size="small">
                    Terminate
                  </Button>
                </Popconfirm>
              )}
              {canDelete(row.status || '') && (
                <Popconfirm
                  title={`Delete ${row.contract_id}?`}
                  placement="right"
                  okText="Confirm"
                  cancelText="Cancel"
                  onConfirm={async () => {
                    await operateContract(
                      org_id,
                      billingConfig.billing_config_id,
                      row.id?.toString() || '',
                      'delete'
                    )
                    refetch()
                  }}
                >
                  <Button type="link" danger size="small">
                    Delete
                  </Button>
                </Popconfirm>
              )}
            </div>
          )
        }
      }
    ],
    []
  )

  const actions = useMemo(
    () => [
      <Button
        type="primary"
        name="create"
        icon={<PlusOutlined />}
        onClick={() =>
          setSelectedContract({
            contract_id: '',
            contract_type: ContractType.SAVING_PLAN_ORDER_FORM
          })
        }
      >
        Create
      </Button>
    ],
    []
  )

  return (
    <>
      <ListToolBar reload={getData} actions={actions}></ListToolBar>
      <Table
        columns={columns}
        dataSource={data?.data.contracts || []}
        rowKey="id"
        loading={isLoading || isFetching}
        pagination={{
          current: data?.data.page,
          pageSize: data?.data.page_size,
          total: data?.data.total_results,
          onChange(page, pageSize?) {
            setPage({
              page,
              page_size: pageSize
            })
          }
        }}
        size="small"
      ></Table>
      {selectedContract !== null && (
        <ContractModal
          visible={true}
          initValues={selectedContract}
          orgId={org_id}
          billingConfigId={billingConfig.billing_config_id}
          type={selectedContract?.id ? 'update' : 'add'}
          onSubmit={() => {
            setSelectedContract(null)
            refetch()
          }}
          onCancel={() => {
            setSelectedContract(null)
          }}
        ></ContractModal>
      )}
    </>
  )
}
