import {
  MinusCircleOutlined,
  PlusOutlined,
  PlusCircleOutlined
} from '@ant-design/icons'
import {
  Button,
  Table,
  Form,
  Select,
  InputNumber,
  Popconfirm,
  message,
  notification,
  Space,
  FormInstance
} from 'antd'
import { FormListProps } from 'antd/lib/form'
import { ColumnsType } from 'antd/lib/table'
import axios from 'axios'
import dayjs, { Dayjs } from 'dayjs'
import { get } from 'lodash'
import React, { useEffect, useMemo, useState } from 'react'
import { useParams } from 'react-router-dom'

import {
  tenantBindPrivateSupportPlan,
  cancelActivatedTenantSupportPlan,
  getPublicSupportPlan,
  useListTenantSupportPlans,
  cancelTenantSupportPlan
} from 'apiClient/services/billing'
import {
  FormsBindedSupportPlan,
  FormsSupportPlanInput,
  FormsSupportPlan
} from 'apiClient/services/billing/interface'
import { FormsBillingConfig } from 'apiClient/services/billing/interface'
import DatePicker from 'components/DatePicker'
import ModalForm from 'components/ModalForm'
import { ListToolBar } from 'components/Table'
import { getErrorMessage } from 'utils/error'
import { precision } from 'utils/number'
import { capitalize } from 'utils/string'
import { format } from 'utils/time'

import {
  formatSupportPlanPercentage,
  formatTieredPriceRule
} from './supportPlanPricing'

export enum PlanLevels {
  BASIC = 'Basic',
  DEVELOPER = 'Developer',
  STANDARD = 'Standard',
  ENTERPRISE = 'Enterprise',
  PREMIUM = 'Premium'
}

export enum SupportPlanCostType {
  FIXED_PRICE = 'fixed_price',
  PERCENTAGE_PRICE = 'percentage_price',
  TIERED_PRICE = 'tiered_price'
}

export const convertMonthlyUsage = (usage: string) => {
  return precision(parseFloat(usage) / 100).toString()
}

export const formatMonthlyUsage = (usage: string) => {
  return formatSupportPlanPercentage(usage)
}

export const formatSupportPlanType = (type: string) => {
  if (!type) {
    return ''
  }
  return type.split('_').map(capitalize).join(' ')
}

export const formatInputDate = (
  date: Dayjs | undefined,
  suffix = 'T00:00:00Z'
) => {
  if (!date) {
    return undefined
  }
  return date?.format('YYYY-MM-DD') + suffix
}

export const supportPlanToForm = (plan: FormsSupportPlan): FormsSupportPlan => {
  return {
    ...plan,
    support_price_percentage: formatMonthlyUsage(
      plan?.support_price_percentage || '0'
    ).toString(),
    tiered_price_rules: plan?.tiered_price_rules
      ? plan?.tiered_price_rules.map((it) => ({
          ...it,
          support_price_percentage: formatMonthlyUsage(
            it.support_price_percentage || '0'
          ).toString()
        }))
      : undefined
  }
}

const DisableSupportPlan: React.FC<
  React.PropsWithChildren<{
    orgId: string
    supportPlanId: string
    onComplete?: () => Promise<any>
  }>
> = ({ orgId, supportPlanId, onComplete }) => {
  const [loading, setLoading] = useState(false)

  const onClick = async () => {
    if (loading) {
      return
    }
    try {
      setLoading(true)
      await cancelTenantSupportPlan(orgId, supportPlanId)
      await onComplete?.()
      setLoading(false)
    } catch (e) {
      notification.error(getErrorMessage(e))
      setLoading(false)
    }
  }

  return (
    <Popconfirm
      title="Are you sure to cancel this?"
      okText="Confirm"
      cancelText="Cancel"
      onConfirm={onClick}
    >
      <Button danger loading={loading}>
        Disable
      </Button>
    </Popconfirm>
  )
}

export const TieredPriceField = ({
  form,
  name = 'tiered_price_rules'
}: {
  form: FormInstance
  name?: string | string[]
}) => {
  const fieldName = typeof name === 'string' ? [name] : name
  return (
    <>
      <Form.Item
        label="Tier Pricing Structure"
        required
        style={{ marginBottom: 10 }}
      />
      <Form.List name={fieldName}>
        {(fields, { add, remove }) => (
          <div>
            {!!fields.length && (
              <Space align="baseline" style={{ marginBottom: 4 }}>
                <span
                  style={{
                    display: 'inline-block',
                    marginLeft: 52,
                    width: 120
                  }}
                >
                  Form
                </span>
                <span
                  style={{
                    display: 'inline-block',
                    width: 226
                  }}
                >
                  To
                </span>
                <span>Percentage</span>
              </Space>
            )}
            {fields.map((field, index) => {
              const editable = fields.length === index + 1
              return (
                <Space key={field.key} align="baseline">
                  <span style={{ display: 'inline-block', width: 44 }}>
                    Tier {index + 1}:
                  </span>
                  <Form.Item
                    {...field}
                    name={[field.name, 'lower_bound']}
                    rules={[{ required: true, message: 'Required' }]}
                    style={{ width: 120 }}
                  >
                    <InputNumber
                      style={{ width: '100%' }}
                      min="0"
                      stringMode
                      step="0.01"
                      disabled
                    ></InputNumber>
                  </Form.Item>
                  <Form.Item
                    {...field}
                    name={[field.name, 'upper_bound']}
                    rules={[
                      ({ getFieldValue }) => ({
                        validator(rule, value) {
                          if (!value) {
                            return Promise.resolve()
                          }
                          const lowerBound = getFieldValue([
                            ...fieldName,
                            field.name,
                            'lower_bound'
                          ])
                          if (
                            Number.parseFloat(value) <=
                            Number.parseFloat(lowerBound)
                          ) {
                            return Promise.reject(
                              new Error(`Should be greater than ${lowerBound}`)
                            )
                          }
                          return Promise.resolve()
                        }
                      })
                    ]}
                    style={{ width: 226 }}
                  >
                    <InputNumber
                      placeholder="Leave blank to mean unlimited"
                      style={{ width: '100%' }}
                      disabled={!editable}
                      min="0"
                      stringMode
                      step="0.01"
                    ></InputNumber>
                  </Form.Item>
                  <Form.Item>
                    <Form.Item
                      {...field}
                      name={[field.name, 'support_price_percentage']}
                      noStyle
                      rules={[{ required: true, message: 'Required' }]}
                    >
                      <InputNumber<string>
                        stringMode
                        min="0"
                        disabled={!editable}
                        max="100"
                        step="0.01"
                      ></InputNumber>
                    </Form.Item>
                    <span> %</span>
                  </Form.Item>
                  {editable && (
                    <>
                      <MinusCircleOutlined
                        onClick={() => remove(field.name)}
                        style={{ display: 'inline-block', marginLeft: 4 }}
                      />
                      <PlusCircleOutlined
                        onClick={() => {
                          form
                            .validateFields([
                              [...fieldName, field.name, 'lower_bound'],
                              [
                                ...fieldName,
                                field.name,
                                'support_price_percentage'
                              ]
                            ])
                            .then(() => {
                              const values = form.getFieldsValue([fieldName])
                              const upperBound = get(values, [
                                ...fieldName,
                                field.name
                              ]).upper_bound
                              if (!upperBound) {
                                form.setFields([
                                  {
                                    name: [
                                      ...fieldName,
                                      field.name,
                                      'upper_bound'
                                    ],
                                    errors: ['Required']
                                  }
                                ])
                                return
                              }
                              form.setFields([
                                {
                                  name: [
                                    ...fieldName,
                                    field.name,
                                    'upper_bound'
                                  ],
                                  errors: []
                                }
                              ])
                              add({
                                lower_bound: upperBound
                              })
                            })
                            .catch(() => {})
                        }}
                        style={{ display: 'inline-block', marginLeft: 4 }}
                      />
                    </>
                  )}
                </Space>
              )
            })}
            {!fields.length && (
              <Form.Item>
                <Button
                  type="dashed"
                  onClick={() => {
                    add({ lower_bound: '0' })
                  }}
                  block
                  icon={<PlusOutlined />}
                >
                  Add a Tier
                </Button>
              </Form.Item>
            )}
          </div>
        )}
      </Form.List>
    </>
  )
}

export const SuopportPlanForm: React.FC<
  React.PropsWithChildren<{
    initValues?: any
    trigger?: React.ReactElement
    publicPlans?: Record<string, FormsBindedSupportPlan>
    onSubmit: (data: FormsSupportPlanInput) => Promise<void>
    disabeld?: boolean
    withDate?: boolean
  }>
> = ({
  initValues,
  trigger,
  onSubmit,
  disabeld,
  publicPlans,
  withDate = true
}) => {
  const [visible, setVisible] = useState(false)
  const [form] = Form.useForm<FormsSupportPlanInput>()

  const selectedType = Form.useWatch('type', form)

  const [selectedLevel, setSelectedLevel] = useState(
    initValues?.level || PlanLevels.DEVELOPER
  )

  const formatInputDate = (date: Dayjs | undefined, suffix = 'T00:00:00Z') => {
    if (!date) {
      return undefined
    }
    return date?.format('YYYY-MM-DD') + suffix
  }

  const handleSubmit = async (
    data: Omit<FormsSupportPlanInput, 'active_date' | 'expired_date'> & {
      active_date: Dayjs
      expired_date: Dayjs
    },
    form: FormInstance
  ) => {
    if (data.tiered_price_rules && data.tiered_price_rules.length) {
      const lastIndex = data.tiered_price_rules.length - 1
      const lastTier =
        data.tiered_price_rules[data.tiered_price_rules.length - 1]
      if (lastTier.upper_bound) {
        form.setFields([
          {
            name: ['tiered_price_rules', lastIndex, 'upper_bound'],
            errors: ['The to value for last tier should be empty']
          }
        ])
        return
      }
    }
    await onSubmit({
      ...data,
      support_price_percentage:
        data.type === SupportPlanCostType.FIXED_PRICE
          ? undefined
          : convertMonthlyUsage(data.support_price_percentage || '0'),
      tiered_price_rules: data.tiered_price_rules
        ? data.tiered_price_rules.map((it) => ({
            ...it,
            support_price_percentage: convertMonthlyUsage(
              it.support_price_percentage || '0'
            )
          }))
        : undefined,
      active_date: formatInputDate(data.active_date),
      expired_date: formatInputDate(data.expired_date, 'T23:59:59Z')
    })
    setVisible(false)
  }

  const today = dayjs(dayjs().format('YYYY-MM-DD'))

  const disabeldDate = (date: Dayjs) => {
    const prev = dayjs(date.format('YYYY-MM-DD'))
    return prev.isBefore(today)
  }

  useEffect(() => {
    if (publicPlans) {
      const type =
        publicPlans[selectedLevel]?.type || SupportPlanCostType.FIXED_PRICE
      form.setFieldValue('type', type)
    }
  }, [selectedLevel, publicPlans])

  const plans = [
    PlanLevels.DEVELOPER,
    PlanLevels.ENTERPRISE,
    PlanLevels.PREMIUM
  ]
  const renderFormFields = (form: FormInstance) => {
    return (
      <>
        <Form.Item
          name="type"
          label="Support Plan Type"
          rules={[{ required: true, message: 'Required' }]}
        >
          <Select>
            {[
              SupportPlanCostType.FIXED_PRICE,
              SupportPlanCostType.PERCENTAGE_PRICE,
              SupportPlanCostType.TIERED_PRICE
            ].map((pl) => (
              <Select.Option key={pl} value={pl || ''}>
                {formatSupportPlanType(pl)}
              </Select.Option>
            ))}
          </Select>
        </Form.Item>
        <Form.Item
          name="level"
          label="Support Plan Level"
          rules={[{ required: true, message: 'Required' }]}
        >
          <Select
            disabled={disabeld}
            onChange={(value) => setSelectedLevel(value)}
          >
            {plans.map((pl) => (
              <Select.Option key={pl} value={pl || ''}>
                {pl}
              </Select.Option>
            ))}
          </Select>
        </Form.Item>
        <Form.Item label="Minimum cost per month basis" required>
          <Form.Item
            name="fixed_charge_price"
            noStyle
            rules={[{ required: true, message: 'Required' }]}
          >
            <InputNumber
              min="0"
              stringMode
              step="0.01"
              style={{ display: 'inline-block', width: '90%' }}
            ></InputNumber>
          </Form.Item>
          <span> $</span>
        </Form.Item>
        {selectedType === SupportPlanCostType.PERCENTAGE_PRICE && (
          <Form.Item label="Percentage of monthly usage" required>
            <Form.Item
              name="support_price_percentage"
              noStyle
              rules={[{ required: true, message: 'Required' }]}
            >
              <InputNumber<string>
                stringMode
                min="0"
                max="100"
                step="0.01"
                style={{ display: 'inline-block', width: '80%' }}
              ></InputNumber>
            </Form.Item>
            <span> %</span>
          </Form.Item>
        )}
        {selectedType === SupportPlanCostType.TIERED_PRICE && (
          <TieredPriceField form={form} />
        )}
        {withDate && (
          <>
            <Form.Item
              label="Start Date"
              name="active_date"
              required
              rules={[{ required: true, message: 'Start Date is required.' }]}
            >
              <DatePicker
                showTime={false}
                disabledDate={disabeldDate}
                style={{ width: '100%' }}
              />
            </Form.Item>
            <Form.Item
              label="End Date"
              name="expired_date"
              rules={[
                ({ getFieldValue }) => ({
                  validator(rule, value: Dayjs) {
                    if (!value) {
                      return Promise.resolve()
                    }
                    const startDate = getFieldValue('active_date') as Dayjs
                    if (!startDate) {
                      return Promise.reject('Please fill Start Date')
                    }

                    const start = startDate.format('YYYY-MM-DD')
                    const end = dayjs(value.format('YYYY-MM-DD'))
                    if (end.isBefore(start)) {
                      return Promise.reject(
                        new Error('End Date should be greater than Start Date.')
                      )
                    }
                    return Promise.resolve()
                  }
                })
              ]}
            >
              <DatePicker
                showTime={false}
                style={{ width: '100%' }}
                disabledDate={disabeldDate}
              />
            </Form.Item>
          </>
        )}
      </>
    )
  }

  const Trigger = trigger ? (
    React.cloneElement(trigger, {
      onClick: () => {
        setVisible(true)
      }
    })
  ) : (
    <Button onClick={() => setVisible(true)}>Add Plan</Button>
  )

  const selectedPlan = useMemo(() => {
    const plan = (publicPlans || {})[selectedLevel] || {}
    return supportPlanToForm(plan)
  }, [publicPlans, selectedLevel])

  return (
    <div>
      {Trigger}
      <ModalForm
        width={636}
        layout={{
          labelCol: { span: 15 }
        }}
        form={form}
        initValues={
          initValues
            ? supportPlanToForm(initValues)
            : publicPlans
            ? {
                ...selectedPlan
              }
            : {
                level: PlanLevels.DEVELOPER,
                type: SupportPlanCostType.FIXED_PRICE
              }
        }
        labelAlign="left"
        name="change-support-plan-form"
        title="Change Support Plan"
        destroyOnClose
        visible={visible}
        onSubmit={handleSubmit}
        getFields={renderFormFields}
        onCancel={() => setVisible(false)}
      ></ModalForm>
    </div>
  )
}

export const SupportPlan: React.FC<
  React.PropsWithChildren<{
    billingConfig: FormsBillingConfig
  }>
> = ({ billingConfig }) => {
  const { org_id } = useParams<{ org_id: string }>()

  const { data, refetch } = useListTenantSupportPlans(
    org_id,
    billingConfig.billing_config_id,
    {
      query: {
        refetchInterval: false,
        refetchIntervalInBackground: false,
        refetchOnWindowFocus: false
      }
    }
  )

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

  const [plans, setPlans] = useState<FormsSupportPlan[]>([])
  const [cancelling, setCancelling] = useState(false)

  const plansMap = plans.reduce(
    (prev, next) => {
      prev[next.level || ''] = next
      return prev
    },
    {
      [PlanLevels.BASIC]: {
        level: PlanLevels.BASIC,
        type: SupportPlanCostType.FIXED_PRICE
      }
    } as Record<string, FormsBindedSupportPlan>
  )

  const fetchPublicPlans = () => {
    getPublicSupportPlan()
      .then((resp) => {
        setPlans(resp.data)
      })
      .catch((e) => {})
  }

  const onSubmit = async (data: FormsSupportPlanInput) => {
    await tenantBindPrivateSupportPlan(org_id, data)
    getData()
  }

  const onDelete = async () => {
    if (cancelling) {
      return
    }
    setCancelling(true)
    try {
      await cancelActivatedTenantSupportPlan(org_id)
      await getData()
    } catch (e) {
      if (axios.isAxiosError(e)) {
        message.error(e.response?.data?.message)
      } else {
        message.error('Cancel Failed')
      }
    } finally {
      setCancelling(false)
    }
  }

  const columns: ColumnsType<FormsBindedSupportPlan> = [
    {
      title: 'Support Valid Range (UTC±00:00)',
      render: (_: any, record: FormsBindedSupportPlan) => {
        if (record.level === PlanLevels.BASIC) {
          return '-'
        }
        return `${format(record.active_date, undefined, 'YYYY/MM/DD', 0)} - ${
          record.expired_date
            ? format(record.expired_date, undefined, 'YYYY/MM/DD', 0)
            : 'Now'
        }`
      }
    },
    {
      title: 'Type',
      render: (_: any, record: FormsBindedSupportPlan) => {
        return formatSupportPlanType(record.type || '')
      }
    },
    {
      title: 'Support Plan',
      render: (_: any, record: FormsBindedSupportPlan) => {
        return record.level
      }
    },
    {
      title: 'Monthly Costs',
      render: (_: any, record: FormsBindedSupportPlan) => {
        return record.level === PlanLevels.BASIC
          ? '-'
          : `$${record.fixed_charge_price}`
      }
    },
    {
      title: 'Percentage of monthly usage',
      render: (_: any, record: FormsBindedSupportPlan) => {
        return record.level === PlanLevels.BASIC
          ? '-'
          : `${formatMonthlyUsage(record.support_price_percentage || '')}%`
      }
    },
    {
      title: 'Tiered Pricing',
      render(value, record, index) {
        if (!record.tiered_price_rules?.length) {
          return '-'
        }
        return (
          <ul>
            {record.tiered_price_rules.map((it, index) => {
              return (
                <li key={index.toString()} style={{ listStyle: 'inside' }}>
                  {formatTieredPriceRule(it)}
                </li>
              )
            })}
          </ul>
        )
      }
    },
    {
      title: 'Status',
      render: (value, record) => {
        return capitalize(record.status?.replaceAll('_', ' ') || '')
      }
    },
    {
      title: 'Operation',
      width: 180,
      render: (_, record) => {
        if (
          record.level !== PlanLevels.BASIC &&
          (record.status === 'active' || record.status === 'to_be_activated')
        ) {
          return (
            <DisableSupportPlan
              key={record.binded_support_plan_id?.toString()}
              orgId={org_id}
              supportPlanId={record.binded_support_plan_id?.toString() || ''}
              onComplete={refetch}
            />
          )
        }
        return ''
      }
    }
  ]

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

  return (
    <div>
      <ListToolBar
        reload={getData}
        actions={[
          <SuopportPlanForm publicPlans={plansMap} onSubmit={onSubmit} />,
          data?.data.length && data.data[0].level !== PlanLevels.BASIC ? (
            <Popconfirm
              title="Cancal current plan?"
              placement="right"
              okText="Confirm"
              cancelText="cancel"
              onConfirm={onDelete}
            >
              <Button type="primary" danger loading={cancelling}>
                Cancel Current Plan
              </Button>
            </Popconfirm>
          ) : null
        ]}
      ></ListToolBar>
      <Table
        columns={columns}
        dataSource={data?.data || []}
        rowKey="tenant_id"
      ></Table>
    </div>
  )
}
