import {
  Button,
  Checkbox,
  Divider,
  Form,
  FormInstance,
  Input,
  InputNumber,
  Select,
  TreeSelect
} from 'antd'
import config from 'config'
import dayjs, { Dayjs } from 'dayjs'
import { useCallback, useState, cloneElement } from 'react'

import {
  useGetUnitFilterQuickSelection,
  useGetUnitTypeTree
} from 'apiClient/api'
import { FormsUnitFilterSlim } from 'apiClient/api/interface'
import {
  listTenants,
  createCustomer,
  useGetTenantByID
} from 'apiClient/services/account'
import { FormsPartnerCustomer } from 'apiClient/services/account/interface'
import {
  createCPPOBillingConfig,
  createTenantDiscount,
  getBillingConfigsByManagedTenant,
  useGetPublicSupportPlan
} from 'apiClient/services/billing'
import {
  FormsSupportPlanInput,
  FormsSupportPlan
} from 'apiClient/services/billing/interface'
import DatePicker from 'components/DatePicker'
import DebounceSelect from 'components/DebounceSelect/DebounceSelect'
import ModalForm from 'components/ModalForm'
import { getTreeData } from 'pages/Tenants/TenantDetail/BusinessInfo/Discount'
import {
  convertMonthlyUsage,
  PlanLevels,
  SupportPlanCostType,
  supportPlanToForm
} from 'pages/Tenants/TenantDetail/BusinessInfo/SupportPlan'
import { precision, toFixed } from 'utils/number'
import { format } from 'utils/time'

import { SupportPlanField } from '../SupportPlan'

const fmt = 'YYYY-MM-DD'

const timeFormat = (value: Dayjs) => {
  return format(value.format(fmt), undefined, 'YYYY-MM-DD', 0)
}

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

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

const formatInputDate = (
  date: Dayjs | undefined | string,
  suffix = 'T00:00:00Z'
) => {
  if (!date) {
    return undefined
  }
  return dayjs(date).format('YYYY-MM-DD') + suffix
}
export const CreateCPPOCustomer: React.FC<
  React.PropsWithChildren<{
    partner_org_id?: string
    customer_org_id?: string
    trigger?: React.ReactElement
    title?: string
    onCreate?: () => void
  }>
> = ({
  partner_org_id,
  customer_org_id,
  trigger,
  title = 'Add a CPPO Customer',
  onCreate
}) => {
  const [visible, setVisible] = useState(false)
  const [showSupportPlan, setShowSupportPlan] = useState(false)
  const { data: plan } = useGetPublicSupportPlan()
  const publicPlans = (plan?.data || []).reduce<
    Record<string, FormsSupportPlan>
  >((prev, next) => {
    prev[next.level || ''] = next
    return prev
  }, {})

  const onSubmit = async (data: {
    partner_org_id: string | { value: string; label: string }
    customer_org_id: string | { value: string; label: string }
    discount: string
    unit_filters: string[]
    payment_code: string
    payment_sub_code: string
    effected_at: string
    expired_at: string
    support_plan?: FormsSupportPlanInput
  }) => {
    const effected_at =
      dayjs(data.effected_at).utc().startOf('day').format('YYYY-MM-DD') +
      'T00:00:00Z'
    const expired_at =
      dayjs(data.expired_at).utc().endOf('day').format('YYYY-MM-DD') +
      'T23:59:59Z'
    const customer: FormsPartnerCustomer = {
      partner_type: 'CPPO',
      effected_at,
      partner_org_id,
      customer_org_id
    }

    if (
      typeof data.partner_org_id !== 'string' &&
      data.partner_org_id &&
      'value' in data.partner_org_id
    ) {
      customer.partner_org_id = data.partner_org_id.value
    }
    if (
      typeof data.customer_org_id !== 'string' &&
      data.customer_org_id &&
      'value' in data.customer_org_id
    ) {
      customer.customer_org_id = data.customer_org_id.value
    }

    // create customer and bind billing config
    await createCustomer(customer)
    await createCPPOBillingConfig(customer.customer_org_id!, {
      tenant_id: customer.customer_org_id!,
      reseller_id: customer.partner_org_id!,
      payment_code: data.payment_code,
      payment_sub_code: data.payment_sub_code,
      effective_date: effected_at,
      support_plan: showSupportPlan
        ? {
            ...data.support_plan,
            support_price_percentage:
              data.support_plan?.type === SupportPlanCostType.PERCENTAGE_PRICE
                ? convertMonthlyUsage(
                    data.support_plan.support_price_percentage || ''
                  )
                : undefined,
            tiered_price_rules: data.support_plan?.tiered_price_rules
              ? data.support_plan?.tiered_price_rules.map((it) => ({
                  ...it,
                  support_price_percentage: convertMonthlyUsage(
                    it.support_price_percentage || '0'
                  )
                }))
              : undefined,
            expired_date: formatInputDate(
              data.support_plan?.expired_date,
              'T23:59:59Z'
            )
          }
        : undefined,
      discounts: [
        {
          usage: 'cppo',
          discount: toFixed(
            precision(100 - Number.parseFloat(data.discount || '0')) / 100,
            4,
            true
          ),
          unit_filters: data.unit_filters
            ? (data.unit_filters.map((it) => {
                return {
                  filter_id: Number(it)
                }
              }) as FormsUnitFilterSlim[])
            : undefined,
          started_at: effected_at,
          expired_at
        }
      ]
    })

    onCreate?.()
    onClose()
  }

  const onClose = () => {
    setVisible(false)
  }

  const { data: partner } = useGetTenantByID(partner_org_id || '', {
    query: {
      enabled: !!partner_org_id && visible,
      refetchOnWindowFocus: false,
      refetchInterval: false
    }
  })

  const { data: org } = useGetTenantByID(customer_org_id || '', {
    query: {
      enabled: !!customer_org_id && visible,
      refetchOnWindowFocus: false,
      refetchInterval: false
    }
  })

  const Trigger = trigger ? (
    cloneElement(trigger, {
      onClick: () => {
        setVisible(true)
      }
    })
  ) : (
    <Button type="primary" onClick={() => setVisible(true)}>
      Add a CPPO Customer
    </Button>
  )

  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 [startDate, setStartDate] = useState<Dayjs>()
  const onDateChange = (c: any[]) => {
    const change = c[0]
    const name = change.name[0]
    const value = change.value
    if (!change) {
      return
    }

    if (name === 'effected_at') {
      setStartDate(value)
    }
  }

  const renderFields = useCallback(
    (form: FormInstance<any>) => {
      return (
        <>
          <Form.Item
            name="partner_org_id"
            label="Linked Reseller"
            required
            rules={[{ required: true, message: 'Required' }]}
          >
            <Select disabled>
              <Select.Option value={partner?.data.id || ''}>
                {partner?.data.name}
              </Select.Option>
            </Select>
          </Form.Item>
          <Form.Item
            name="customer_org_id"
            label="TiDB Cloud Org"
            required
            rules={[{ required: true, message: 'Required' }]}
          >
            {!!org ? (
              <Select disabled>
                <Select.Option value={org.data.id || ''}>
                  {org.data.name}
                </Select.Option>
              </Select>
            ) : (
              <DebounceSelect
                showSearch
                placeholder="Search by ID/Name/Email"
                fetchOptions={async (search: string) => {
                  const data = await listTenants({
                    org_tag: '',
                    status: ['active'],
                    search
                  })
                  return (data.data.items || []).map((item) => {
                    return {
                      label: `${item.name} (Org ID: ${item.id})` || '',
                      value: item.id || ''
                    }
                  })
                }}
              />
            )}
          </Form.Item>
          <Form.Item name="payment_code" label="AWS Payment Code">
            <Input />
          </Form.Item>
          <Form.Item name="payment_sub_code" label="Secondary Payment Code">
            <Input />
          </Form.Item>
          <Form.Item
            name="effected_at"
            label="Effective Date"
            required
            rules={[{ required: true, message: 'required' }]}
          >
            <DatePicker
              picker="date"
              format={timeFormat}
              disabledDate={(date) => {
                if (config.SKIP_PARTNER_ACTIVE_CHECK) {
                  return false
                }
                const end = dayjs().add(1, 'day').utc().startOf('day')
                return dayjs(date).utc().startOf('day').isBefore(end)
              }}
            />
          </Form.Item>

          <Divider>Discount Info</Divider>

          <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>
          <Form.Item label="Discount Percentage" required>
            <Form.Item
              name="discount"
              noStyle
              rules={[{ required: true, message: 'Required' }]}
            >
              <InputNumber<string> stringMode min="0" max="100" precision={2} />
            </Form.Item>
            <span className="ant-form-text">% Off</span>
          </Form.Item>
          <Form.Item
            label="Discount Start Date"
            required
            rules={[{ required: true, message: 'Required' }]}
          >
            {!!startDate && serverTimeFormat(startDate.startOf('day'))} (CPPO
            Effective Date)
          </Form.Item>
          <Form.Item
            name="expired_at"
            label="Discount End Date"
            required
            rules={[
              ({ getFieldValue }) => ({
                validator(rule, value: Dayjs) {
                  if (!value) {
                    return Promise.reject('Required')
                  }
                  const startDate = getFieldValue(['effected_at']) as Dayjs
                  if (!startDate) {
                    return Promise.reject('Please fill Effective Date')
                  }

                  const start = dayjs(startDate).utc().startOf('day')
                  const end = dayjs(value).utc().startOf('day')
                  if (!end.isAfter(start)) {
                    return Promise.reject(
                      new Error(
                        'Discount End Date should be greater than Effective Date.'
                      )
                    )
                  }
                  return Promise.resolve()
                }
              })
            ]}
          >
            <DatePicker
              picker="date"
              format={(v) => serverTimeFormat(v.endOf('day'))}
              placeholder="Select date"
            />
          </Form.Item>
          <Form.Item label="Discount Type" required>
            CPPO Discount
          </Form.Item>
          <Form.Item label="With Support Plan">
            <Select
              onChange={(value) => setShowSupportPlan(value === 'yes')}
              value={showSupportPlan ? 'yes' : 'no'}
            >
              <Select.Option value="no">
                Cancel the Support Plan on Direct Stage
              </Select.Option>
              <Select.Option value="yes">
                Cancel the Support Plan on Direct Stage and Bind a new one
              </Select.Option>
            </Select>
          </Form.Item>
          {showSupportPlan && (
            <>
              <Divider>Support Plan Info</Divider>
              <SupportPlanField
                readOnly={false}
                publicPlans={publicPlans}
                form={form}
                onLevelChange={(value) => {
                  const plan = publicPlans[value]
                  const data = supportPlanToForm(plan)
                  form.setFieldsValue({
                    support_plan: {
                      fixed_charge_price: data.fixed_charge_price,
                      support_price_percentage: data.support_price_percentage,
                      tiered_price_rules: data.tiered_price_rules
                    }
                  })
                }}
              />
            </>
          )}
        </>
      )
    },
    [org, partner, startDate, showSupportPlan]
  )

  return (
    <div>
      {Trigger}
      <ModalForm
        initValues={{
          partner_org_id: partner?.data.id || '',
          customer_org_id: org?.data.id || '',
          effected_at: '',
          payment_code: '',
          // @ts-ignore
          unit_filters: (defaultDiscount?.data || []).map(
            (it) => it.filter_id || ''
          ),
          support_plan: {
            ...supportPlanToForm(publicPlans[PlanLevels.ENTERPRISE])
          }
        }}
        layout={{ labelCol: { span: 8 } }}
        width={700}
        name="create-cppo-customer-form"
        title={title}
        visible={visible}
        onSubmit={onSubmit}
        onCancel={onClose}
        getFields={renderFields}
        onFieldsChange={onDateChange}
        destoryOnClose
      ></ModalForm>
    </div>
  )
}
