import { PlusOutlined } from '@ant-design/icons'
import {
  Button,
  Form,
  Input,
  InputNumber,
  Select,
  Table,
  TreeSelect,
  FormInstance,
  Popconfirm,
  Divider,
  Modal,
  type InputRef
} from 'antd'
import { ColumnsType } from 'antd/lib/table'
import { DataNode } from 'antd/lib/tree'
import { Dayjs } from 'dayjs'
import dayjs from 'dayjs'
import { capitalize, startCase } from 'lodash'
import React, { Fragment, useRef, useState } from 'react'
import { Link, useParams } from 'react-router-dom'

import {
  useGetUnitFilterQuickSelection,
  useGetUnitTypeTree
} from 'apiClient/api'
import { FormsUnitFilterNode } from 'apiClient/api/interface'
import { useGetCustomersByPartnerId } from 'apiClient/services/account'
import {
  useListTenantDiscount,
  createTenantDiscount,
  reclaimTenantDiscount
} from 'apiClient/services/billing'
import {
  FormsBillingConfig,
  FormsDiscount
} from 'apiClient/services/billing/interface'
import { DatePicker } from 'components/DatePicker'
import ModalForm from 'components/ModalForm'
import { ListToolBar } from 'components/Table'
import { precision, toUSDiscount, toFixed } from 'utils/number'
import { format } from 'utils/time'

import { CloudProviderSelect } from './CloudProvider'

enum DISCOUNT_USAGE {
  Program = 'program',
  COMMITMENT_PLAN = 'commitment_plan',
  PRE_PAID = 'pre_paid',
  CPPO = 'cppo'
}

enum DISCOUNT_STATUS {
  VALID = 'valid',
  EXPIRED = 'expired',
  RECLAIMED = 'reclaimed'
}

const serverFmt = 'YYYY-MM-DDTHH:mm:ss[Z]'

type FormsDiscountReq = Omit<FormsDiscount, 'started_at' | 'expired_at'> & {
  started_at?: Dayjs
  expired_at?: Dayjs
}

export const getTreeData = (tree: FormsUnitFilterNode[]) => {
  return tree.map((t) => {
    const data: DataNode & { value: string | number } = {
      title: t.name,
      value: t.filter_id || '',
      key: t.filter_id || '',
      children: t.children ? getTreeData(t.children) : []
    }
    return data
  })
}

const timeFormat = (value: Dayjs) => {
  return format(value.format(serverFmt), undefined, 'YYYY-MM-DD HH:mm:ss Z', 0)
}

const CustomerSelect: React.FC<
  React.PropsWithChildren<{
    deafaultOptions?: { label: string; value: string }[]
  }>
> = ({ deafaultOptions, ...rest }) => {
  const [items, setItems] = useState(deafaultOptions || [])
  const [name, setName] = useState('')
  const inputRef = useRef<InputRef>(null)

  const onNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    setName(event.target.value)
  }

  const addItem = () => {
    if (!name) {
      return
    }
    setItems([...items, { label: name, value: name }])
    setName('')
    setTimeout(() => {
      inputRef.current?.focus()
    }, 0)
  }

  return (
    <Select
      style={{ minWidth: 300 }}
      {...rest}
      dropdownRender={(menu) => (
        <>
          {menu}
          <Divider style={{ margin: '8px 0' }} />
          <div style={{ padding: '0 8px 4px', display: 'flex' }}>
            <Input
              placeholder="Please enter item"
              ref={inputRef}
              value={name}
              onPressEnter={(e) => {
                e.preventDefault()
                addItem()
              }}
              onChange={onNameChange}
              style={{ flex: 1, marginRight: 8 }}
            />
            <Button
              type="text"
              icon={<PlusOutlined />}
              onClick={(e) => {
                e.preventDefault()
                addItem()
              }}
            >
              Add item
            </Button>
          </div>
        </>
      )}
      options={items}
    />
  )
}

export const AddDiscountForm: React.FC<
  React.PropsWithChildren<{
    title?: string
    orgId?: string
    billingConfig?: FormsBillingConfig
    onSubmit: (data: FormsDiscount) => Promise<void>
    isPartner?: boolean
  }>
> = ({ title, billingConfig, onSubmit, isPartner, orgId }) => {
  const [visible, setVisible] = useState(false)
  const handleSubmit = async (data: FormsDiscountReq) => {
    if (data.unit_filters) {
      // @ts-ignore
      data.unit_filters = data.unit_filters.map((it) => {
        return {
          filter_id: it
        }
      })
    }
    await onSubmit({
      ...data,
      discount: toFixed(
        precision(100 - Number.parseFloat(data.discount || '0')) / 100,
        4,
        true
      ),
      started_at: data.started_at?.format(serverFmt) || '',
      expired_at: data.expired_at?.format(serverFmt) || ''
    })
    setVisible(false)
  }

  const currentDate = dayjs(dayjs().format('YYYY-MM-DD') + ' 00:00:00')

  const { data } = useGetUnitTypeTree({
    query: {
      refetchInterval: false,
      refetchOnWindowFocus: false,
      refetchIntervalInBackground: false,
      refetchOnMount: false
    }
  })
  const { data: defaultDiscount } = useGetUnitFilterQuickSelection(
    'default-discount',
    {
      query: {
        refetchInterval: false,
        refetchOnWindowFocus: false,
        refetchIntervalInBackground: false,
        refetchOnMount: false
      }
    }
  )

  const { data: customers } = useGetCustomersByPartnerId(
    orgId || '',
    {
      page: 1,
      per_page: 1000
    },
    {
      query: {
        enabled: isPartner && !!orgId,
        refetchInterval: false,
        refetchOnWindowFocus: false
      }
    }
  )

  const isCPPOCustomer = billingConfig?.type === 'CPPOCustomer'

  const renderFields = (form: FormInstance) => {
    return (
      <>
        {isPartner && (
          <Form.Item name="customers" label="End Customer Org">
            <Select mode="multiple">
              {(customers?.data || []).map((item) => {
                return (
                  <Select.Option
                    key={item.customer_org_id || ''}
                    value={item.customer_org_id || ''}
                  >
                    {item.name} (Org ID: {item.customer_org_id})
                  </Select.Option>
                )
              })}
            </Select>
          </Form.Item>
        )}
        <Form.Item
          name="unit_filters"
          label="Discount Type"
          required
          rules={[{ required: true, message: 'Required' }]}
        >
          <TreeSelect
            showCheckedStrategy="SHOW_PARENT"
            treeCheckable
            treeDefaultExpandAll
            treeData={getTreeData(data?.data ? data.data?.children || [] : [])}
          />
        </Form.Item>
        <CloudProviderSelect />
        <Form.Item name="description" label="Discount Description to Customer">
          <CustomerSelect
            deafaultOptions={[
              {
                label: 'Commitment Plan Default Discount',
                value: 'Commitment Plan Default Discount'
              },
              {
                label: 'Cross AZ Traffic Saving Program',
                value: 'Cross AZ Traffic Saving Program'
              },
              {
                label: 'DM Program',
                value: 'DM Program'
              }
            ]}
          />
        </Form.Item>
        <Form.Item
          label="Discount Percentage"
          required
          rules={[{ required: true, message: 'Required' }]}
        >
          <Form.Item name="discount" noStyle>
            <InputNumber<string> stringMode min="0" max="100" precision={2} />
          </Form.Item>
          <span className="ant-form-text">% Off</span>
        </Form.Item>
        <Form.Item
          name="started_at"
          label="Discount Start Date"
          required
          rules={[{ required: true, message: 'Required' }]}
        >
          <DatePicker
            showNow={false}
            showTime={{ format: 'HH:mm:ss' }}
            format={timeFormat}
          />
        </Form.Item>
        <Form.Item
          name="expired_at"
          label="Discount End Date"
          required
          rules={[
            ({ getFieldValue }) => ({
              validator(rule, value: Dayjs) {
                if (!value) {
                  return Promise.reject(new Error('Required'))
                }
                const startDate = getFieldValue('started_at') as Dayjs
                if (!startDate) {
                  return Promise.reject('Please fill Start Date')
                }
                if (value.isBefore(startDate)) {
                  return Promise.reject(
                    new Error('End Date should be greater than Start Date')
                  )
                }
                return Promise.resolve()
              }
            })
          ]}
        >
          <DatePicker
            showNow={false}
            showTime={{ format: 'HH:mm:ss' }}
            format={timeFormat}
          />
        </Form.Item>
        <Form.Item
          name="usage"
          label="Usage"
          required
          rules={[{ required: true, message: 'Required' }]}
        >
          {isCPPOCustomer ? (
            <Select disabled>
              <Select.Option value={DISCOUNT_USAGE.CPPO}>
                CPPO Discount
              </Select.Option>
            </Select>
          ) : (
            <Select>
              {[
                DISCOUNT_USAGE.COMMITMENT_PLAN,
                DISCOUNT_USAGE.PRE_PAID,
                DISCOUNT_USAGE.Program
              ].map((t) => (
                <Select.Option key={t} value={t}>
                  {startCase(t)}
                </Select.Option>
              ))}
            </Select>
          )}
        </Form.Item>
        <Form.Item
          name="note"
          label="Note"
          rules={[{ max: 128, message: 'Should be less than 128 characters' }]}
        >
          <Input.TextArea style={{ height: 80 }}></Input.TextArea>
        </Form.Item>
      </>
    )
  }

  return (
    <div>
      <Button type="primary" onClick={() => setVisible(true)}>
        Add Discount
      </Button>
      <ModalForm<FormsDiscountReq>
        width={730}
        layout={{
          labelCol: { span: 8 }
        }}
        initValues={{
          started_at: currentDate,
          expired_at: currentDate.add(1, 'day'),
          // @ts-ignore
          unit_filters: (defaultDiscount?.data || []).map(
            (it) => it.filter_id || ''
          ),
          usage: isCPPOCustomer ? 'cppo' : ''
        }}
        name="add-credit-form"
        // labelAlign="left"
        title={title || 'Add Discount'}
        visible={visible}
        onSubmit={handleSubmit}
        onCancel={() => setVisible(false)}
        getFields={renderFields}
      ></ModalForm>
    </div>
  )
}

export const DiscountTable: React.FC<
  React.PropsWithChildren<{
    loading?: boolean
    onReclaim: (record: FormsDiscount) => Promise<void>
    data: FormsDiscount[]
    isPartner?: boolean
  }>
> = ({ onReclaim, data, loading, isPartner }) => {
  const [reclaiming, setReclaiming] = useState<string | null>(null)
  const handleReclaim = (discount: FormsDiscount) => async () => {
    setReclaiming(discount.discount_sid || null)
    try {
      await onReclaim(discount)
    } finally {
      setReclaiming(null)
    }
  }
  const columns: ColumnsType<FormsDiscount> = [
    {
      title: 'Discount Code',
      dataIndex: 'discount_code'
    },
    {
      title: 'Status',
      render: (_: any, record) => {
        return capitalize(record.status)
      }
    },
    {
      title: 'Cloud Provider',
      render: (_: any, record) => {
        return record.provider?.toUpperCase() || '-'
      }
    },
    {
      title: 'Discount Type',
      render: (_: any, record) => {
        const openModal = () => {
          Modal.info({
            title: 'Discount Type',
            centered: true,
            content: (
              <div>{record.unit_filters?.map((it) => it.name).join(', ')}</div>
            )
          })
        }

        if (!record.unit_filters) {
          return '-'
        }
        if (record.unit_filters.length <= 3) {
          return record.unit_filters.map((it) => it.name).join(', ')
        }
        return (
          <>
            {record.unit_filters
              .slice(0, 2)
              .map((it) => it.name)
              .join(', ')}{' '}
            <a type="link" onClick={openModal}>
              Details
            </a>
          </>
        )
      }
    },
    {
      title: 'Discount Description',
      dataIndex: 'description'
    },
    {
      title: 'Discount Percentage',
      render: (_: any, record) => {
        const discount = Number.parseFloat(record.discount || '0') * 100
        return `${toUSDiscount(discount)} % Off`
      }
    },
    {
      title: 'Discount Start Date',
      render: (_: any, record) => {
        return `${format(
          record.started_at,
          undefined,
          'YYYY-MM-DD HH:mm:ss Z',
          0
        )}`
      }
    },
    {
      title: 'Discount End Date',
      render: (_: any, record) => {
        return `${format(
          record.expired_at,
          undefined,
          'YYYY-MM-DD HH:mm:ss Z',
          0
        )}`
      }
    },
    {
      title: 'Usage',
      render: (_, record) => {
        return startCase(record.usage || '')
      }
    },
    {
      title: 'Note',
      dataIndex: 'note'
    },
    {
      title: 'Action',
      width: 180,
      render: (_: any, record) => {
        if (record.status !== DISCOUNT_STATUS.VALID) {
          return null
        }
        return (
          <Popconfirm
            title={
              <>
                <b>Reclaim Discount</b>
                <p>Are you sure to reclaim this discount?</p>
              </>
            }
            placement="right"
            okText="Confirm"
            cancelText="Cancel"
            onConfirm={handleReclaim(record)}
          >
            <Button type="primary" loading={reclaiming === record.discount_sid}>
              Reclaim
            </Button>
          </Popconfirm>
        )
      }
    }
  ]

  if (isPartner) {
    columns.splice(1, 0, {
      title: 'Customers',
      dataIndex: 'customers',
      render: (_: any, record) => {
        return record.customers?.map((it, index) => {
          return (
            <Fragment key={it}>
              <Link to={`/orgs/${it}`}>{it}</Link>
              {index < (record.customers?.length || 0) - 1 && <br />}
            </Fragment>
          )
        })
      }
    })
  }

  return (
    <Table
      loading={loading}
      columns={columns}
      dataSource={data || []}
      rowKey="discount_sid"
    ></Table>
  )
}

export const ManageDiscounts: React.FC<
  React.PropsWithChildren<{
    billingConfig?: FormsBillingConfig
    isPartner?: boolean
  }>
> = React.memo(({ billingConfig, isPartner }) => {
  const { org_id: orgId } = useParams<{ org_id: string }>()
  const org_id = billingConfig?.tenant_id || orgId
  const { data, refetch, isFetching } = useListTenantDiscount(
    org_id,
    billingConfig?.billing_config_id!,
    {
      query: {
        refetchInterval: false,
        refetchIntervalInBackground: false,
        refetchOnWindowFocus: false
      }
    }
  )

  const onReclaim = async (record: FormsDiscount) => {
    await reclaimTenantDiscount(
      org_id,
      billingConfig?.billing_config_id!,
      record.discount_sid || ''
    )
    refetch()
  }

  const onAdd = async (data: FormsDiscount) => {
    await createTenantDiscount(
      org_id,
      billingConfig?.billing_config_id!,
      data,
      { timeout: 15 * 1000 }
    )
    refetch()
  }

  return (
    <div>
      <ListToolBar
        actions={[
          <AddDiscountForm
            billingConfig={billingConfig}
            onSubmit={onAdd}
            isPartner={isPartner}
            orgId={org_id}
          />
        ]}
        reload={async () => {
          await refetch()
        }}
      ></ListToolBar>
      <DiscountTable
        loading={isFetching}
        data={data?.data || []}
        onReclaim={onReclaim}
        isPartner={isPartner}
      ></DiscountTable>
    </div>
  )
})
