import { Button, Flex } from '@tidbcloud/uikit'
import { Form, FormProps } from '@tidbcloud/uikit/biz'
import { IconCheckCircle } from '@tidbcloud/uikit/icons'
import React, { useState, useRef, useEffect } from 'react'
import { FieldValues, useFormContext } from 'react-hook-form'

import { useAccessCheck } from 'dbaas/contexts/access-control'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import { eventTracking } from 'dbaas/utils/tracking'

interface CardFormProps<T extends FieldValues> extends Omit<FormProps<T>, 'onSubmit' | 'children'> {
  type: string
  onTest: (data: T) => Promise<any>
  onConfrim: (data: T) => Promise<any>
  onConfirmed?: () => void
  onCancel?: () => void
  children: (step: ActionSteps, readOnly: boolean) => React.ReactNode
  defaultValues?: any
  className?: string
  stepTexts?: Record<ActionSteps, string>
}

export function CardForm<T extends object>({
  type,
  onTest,
  onConfrim,
  onCancel,
  children,
  defaultValues,
  className,
  stepTexts,
  onConfirmed,
  ...rest
}: CardFormProps<T>) {
  const accessible = useAccessCheck('ProjectIntegrationAction')

  const [step, setStep] = useState<ActionSteps>('initial')
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState('')

  const onSubmit = async (data: T) => {
    eventTracking(`Integration To ${type} Test Integration Button Clicked`, {
      step: step
      // 'Cluster Type'
    })
    if (loading) {
      return
    }

    try {
      setLoading(true)
      if (step === 'initial') {
        await onTest(data)
        setStep('passed')
      }

      if (step === 'passed') {
        await onConfrim(data)
        setStep('confirmed')
      }

      setLoading(false)
      setError('')
    } catch (e) {
      setLoading(false)
      setError(getErrorMessage(e))
    }
  }

  const onStepChange = (step: ActionSteps) => {
    if (step === 'confirmed') {
      onConfirmed?.()
    }
  }

  const handleCancel = () => {
    eventTracking(`Integration To ${type} Cancel Button Clicked`)
    if (loading && step === 'confirmed') {
      return
    }
    if (step === 'passed') {
      setStep('initial')
    }
    if (step === 'initial') {
      onCancel?.()
    }
  }

  const readOnly = step !== 'initial'

  return (
    <Form<T>
      className={className}
      onSubmit={onSubmit}
      w={600}
      m="24px auto"
      defaultValues={defaultValues}
      withActions={false}
      formMode="all"
      {...rest}
    >
      {children(step, readOnly)}
      <Form.ErrorMessage message={error} onDismiss={() => setError('')} />
      <SubmitAction
        disabled={!accessible}
        step={step}
        loading={loading}
        onStepChange={onStepChange}
        onCancel={handleCancel}
        stepTexts={stepTexts}
      />
    </Form>
  )
}

export type ActionSteps = 'initial' | 'passed' | 'confirmed'

export const SubmitAction: React.FC<
  React.PropsWithChildren<{
    step: ActionSteps
    onStepChange?: (step: ActionSteps) => void
    loading?: boolean
    stepTexts?: Record<ActionSteps, string | React.ReactNode>
    onCancel?: () => void
    autoConfirmed?: boolean
    disabled?: boolean
  }>
> = ({ step = 'initial', onStepChange, loading, stepTexts = {}, onCancel, autoConfirmed = true, disabled }) => {
  const {
    formState: { isValid }
  } = useFormContext()

  const timeoutRef = useRef<number | null>(null)

  let StepButton = (
    <Button type="submit" disabled={!isValid || disabled} loading={loading}>
      {stepTexts[step] || 'Test'}
    </Button>
  )

  useEffect(() => {
    if (!autoConfirmed) {
      return
    }
    if (step === 'confirmed') {
      if (timeoutRef.current !== null) {
        window.clearTimeout(timeoutRef.current)
      }
      timeoutRef.current = window.setTimeout(() => {
        onStepChange?.('confirmed')
      }, 1000)
    }
    return () => {
      window.clearTimeout(timeoutRef.current || 0)
    }
  }, [step, onStepChange, autoConfirmed])

  if (step === 'passed') {
    StepButton = (
      <Button type="submit" onClick={() => onStepChange?.('passed')} loading={loading} disabled={disabled}>
        {stepTexts[step] || 'Confirm'}
      </Button>
    )
  }

  if (step === 'confirmed') {
    StepButton = (
      <Button
        type="button"
        disabled={disabled}
        onClick={() => onStepChange?.('confirmed')}
        rightSection={<IconCheckCircle size={16} />}
      >
        {stepTexts[step] || 'Confirmed'}
      </Button>
    )
  }

  return (
    <Flex justify="end" gap={16}>
      <Button variant="default" onClick={onCancel}>
        Cancel
      </Button>
      {StepButton}
    </Flex>
  )
}
