import {
  Card,
  Row,
  Tag,
  Typography,
  Button,
  Divider,
  Form,
  Input,
  Select,
  Steps,
  Timeline
} from 'antd'
import { PresetColorType } from 'antd/lib/_util/colors'
import { capitalize, startCase, lowerCase } from 'lodash'
import React, { useMemo, useState } from 'react'
import { useParams } from 'react-router-dom'

import {
  useCancelTenantClosureProcess,
  useGetTenantClosurePolicy,
  useGetTenantClosureReason,
  useGetTenantCreditClosureProcessInfo,
  useRunTenantClosureProcess
} from 'apiClient/api'
import { TenantGetTenantResp } from 'apiClient/services/devops/interface'
import ModalForm from 'components/ModalForm'
import dayjs, { format } from 'utils/time'

enum CreditRiskCloseStatus {
  NOT_STARTED = 'not_started',
  RUNNING = 'running',
  DONE = 'done',
  CANCELING = 'canceling',
  CANCELED = 'canceled'
}

const StatusColor: Record<CreditRiskCloseStatus, PresetColorType | 'default'> =
  {
    [CreditRiskCloseStatus.NOT_STARTED]: 'default',
    [CreditRiskCloseStatus.RUNNING]: 'green',
    [CreditRiskCloseStatus.DONE]: 'blue',
    [CreditRiskCloseStatus.CANCELING]: 'purple',
    [CreditRiskCloseStatus.CANCELED]: 'volcano'
  }

const START_PROCESS_STEPS = {
  START: 1,
  END: 2
} as const

const SuspendForm: React.FC<
  React.PropsWithChildren<{
    title?: string
    trigger: React.ReactElement
    initValues?: any
    orgId: string
    placeholder?: string
    content?: string
    onSubmit: (data: any) => Promise<any>
    withReason?: boolean
  }>
> = ({
  trigger,
  initValues,
  title,
  orgId,
  placeholder,
  content,
  onSubmit,
  withReason = true
}) => {
  const [visible, setVisible] = useState(false)
  const [step, setStep] = useState<number>(START_PROCESS_STEPS.START)
  const [reason, setReason] = useState('')
  const { data: reasons } = useGetTenantClosureReason(orgId)
  const { data: closePolicy, refetch } = useGetTenantClosurePolicy(
    orgId,
    reason || '',
    {
      query: {
        enabled: !!reason
      }
    }
  )
  const Trigger = React.cloneElement(trigger, {
    onClick: () => {
      setVisible(true)
    }
  })
  const handleSubmit = async (data: any) => {
    if (withReason && step === START_PROCESS_STEPS.START) {
      setReason(data.reason)
      await refetch()
      setStep(START_PROCESS_STEPS.END)
      return
    }
    await onSubmit(withReason ? { reason } : {})
    setVisible(false)
  }
  const getFields = () => {
    return (
      <>
        <p>{content}</p>
        {step === START_PROCESS_STEPS.START && (
          <div>
            <Form.Item
              name="org_id"
              label=""
              rules={[
                ({ getFieldValue }) => ({
                  validator(_, value) {
                    if (!value) {
                      return Promise.reject(new Error('Required'))
                    }
                    if (value !== orgId) {
                      return Promise.reject(new Error('Inconsistent Org ID'))
                    }
                    return Promise.resolve()
                  }
                })
              ]}
            >
              <Input placeholder={placeholder}></Input>
            </Form.Item>
            {withReason && (
              <Form.Item
                name="reason"
                label="Reason"
                rules={[{ required: true, message: 'Reason is required.' }]}
              >
                <Select>
                  {reasons?.data.map((reason) => {
                    return (
                      <Select.Option key={reason} value={reason}>
                        {startCase(reason)}
                      </Select.Option>
                    )
                  })}
                </Select>
              </Form.Item>
            )}
          </div>
        )}
        {step === START_PROCESS_STEPS.END && (
          <div>
            {closePolicy && (
              <Steps
                size="small"
                direction="vertical"
                style={{ marginTop: 16 }}
              >
                {closePolicy.data.close_policy?.actions?.map((item) => {
                  const startAt = dayjs()
                  const end = startAt.add(item.action_time_in_hour || 0, 'hour')
                  return (
                    <Steps.Step
                      key={item.action || ''}
                      title={capitalize(lowerCase(item.action))}
                      status={'wait'}
                      description={`${'Will finish at '}${end.format(
                        'YYYY-MM-DD HH:mm:ss'
                      )}.`}
                    ></Steps.Step>
                  )
                })}
              </Steps>
            )}
          </div>
        )}
      </>
    )
  }
  return (
    <div>
      {Trigger}
      <ModalForm
        formLayout={'vertical'}
        layout={{ wrapperCol: { span: 24 } }}
        initValues={{ ...initValues }}
        name="suspend-form"
        title={title || ''}
        visible={visible}
        onSubmit={handleSubmit}
        getFields={getFields}
        okText={
          withReason && step === START_PROCESS_STEPS.START ? 'Next' : 'Confirm'
        }
        onCancel={() => setVisible(false)}
      ></ModalForm>
    </div>
  )
}

export const SuspendCard: React.FC<
  React.PropsWithChildren<{ tenant: TenantGetTenantResp }>
> = ({ tenant }) => {
  const { org_id } = useParams<{ org_id: string }>()
  const { data: closeInfo, refetch } = useGetTenantCreditClosureProcessInfo(
    org_id,
    {
      query: {
        retry(failureCount, error) {
          return false
        },
        refetchInterval: 60 * 1000
      }
    }
  )
  const { data: closurePolicy } = useGetTenantClosurePolicy(
    org_id,
    closeInfo?.data.reason || '',
    {
      query: {
        enabled: !!closeInfo?.data.reason
      }
    }
  )

  const disabledStart =
    tenant.status === 'inactive' ||
    (closeInfo &&
      [CreditRiskCloseStatus.RUNNING, CreditRiskCloseStatus.CANCELING].includes(
        closeInfo.data.status as CreditRiskCloseStatus
      ))

  const disabledCancel =
    tenant.status === 'inactive' ||
    (closeInfo &&
      [CreditRiskCloseStatus.CANCELING].includes(
        closeInfo.data.status as CreditRiskCloseStatus
      ))

  const { mutateAsync: cancelTenantClosureProcess } =
    useCancelTenantClosureProcess()

  const { mutateAsync: runTenantClousureProcess } = useRunTenantClosureProcess()

  const notStarted =
    closeInfo?.data.status === CreditRiskCloseStatus.NOT_STARTED
  const currentProcess = closeInfo?.data.close_actions_status?.status || {}

  const currentStep = useMemo(() => {
    let step = 0
    closurePolicy?.data.close_policy?.actions?.forEach((item, index) => {
      if (currentProcess[item.action || ''] === CreditRiskCloseStatus.DONE) {
        step = index + 1
      }
    })
    return step
  }, [closurePolicy, currentProcess])

  return (
    <Card
      title={
        <>
          Suspend{' '}
          <Typography.Text mark className="word-break">
            {tenant.name}
          </Typography.Text>
        </>
      }
      extra={
        closeInfo && (
          <>
            Process Status:{' '}
            <Tag
              key={closeInfo.data.status}
              color={
                StatusColor[closeInfo.data.status as CreditRiskCloseStatus]
              }
            >
              {capitalize(closeInfo.data.status)}
            </Tag>
          </>
        )
      }
    >
      <Row>
        <SuspendForm
          title="Start deleting process"
          orgId={org_id}
          placeholder="Paste the Org ID which you would delete"
          content="Are you sure to start this process?"
          trigger={
            <Button danger disabled={disabledStart}>
              Start deleting process
            </Button>
          }
          onSubmit={async (data: { reason: string }) => {
            await runTenantClousureProcess({
              tenantId: org_id,
              reason: data.reason
            })
            refetch()
          }}
        ></SuspendForm>
        <SuspendForm
          title="Cancel deleting process"
          orgId={org_id}
          placeholder="Paste the Org ID which you would cancel"
          content="Are you sure to cancel this process?"
          onSubmit={async () => {
            await cancelTenantClosureProcess({ tenantId: org_id })
            refetch()
          }}
          withReason={false}
          trigger={
            <Button disabled={disabledCancel} style={{ marginLeft: 24 }}>
              Cancel
            </Button>
          }
        ></SuspendForm>
      </Row>
      <Divider />
      {closeInfo && !notStarted ? (
        <Timeline>
          {!!closeInfo.data.closed_at && (
            <Timeline.Item>
              {capitalize(closeInfo.data.status)} at{' '}
              {format(closeInfo.data.closed_at)}.
            </Timeline.Item>
          )}
          {!!closeInfo.data.started_at && (
            <Timeline.Item>
              Task of deleting org started deleting at{' '}
              {format(closeInfo.data.started_at)}.
              {!!closurePolicy &&
                ' Task is ahead to the step ' + (currentStep + 1) + '.'}
              {closurePolicy && (
                <Steps
                  direction="vertical"
                  size="small"
                  style={{ marginTop: 16 }}
                >
                  {closurePolicy.data.close_policy?.actions?.map((item) => {
                    const currentStatus =
                      currentProcess[item.action || ''] ===
                      CreditRiskCloseStatus.DONE
                        ? 'finish'
                        : 'wait'
                    const startAt = dayjs(closeInfo?.data.started_at)
                    const end = startAt.add(
                      item.action_time_in_hour || 0,
                      'hour'
                    )
                    return (
                      <Steps.Step
                        key={item.action || ''}
                        title={capitalize(lowerCase(item.action))}
                        status={currentStatus}
                        description={`${
                          currentStatus === 'finish'
                            ? 'Finished at '
                            : 'Waiting, until '
                        }${end.format('YYYY-MM-DD HH:mm:ss')}.`}
                      ></Steps.Step>
                    )
                  })}
                </Steps>
              )}
            </Timeline.Item>
          )}
        </Timeline>
      ) : null}
    </Card>
  )
}
