import { Box, Divider, Modal, List, Flex, Image, Typography, Button, Alert } from '@tidbcloud/uikit'
import {
  Form,
  FormActions,
  FormCopyText,
  FormErrorMessage,
  FormPasswordInput,
  FormTextInput
} from '@tidbcloud/uikit/biz'
import { IconInfoCircle } from '@tidbcloud/uikit/icons'
import { useEffect, useState } from 'react'
import { useQueryClient } from 'react-query'

import { getMetaQueryKey } from 'dbaas/services/account'
import { useConfirmMfaAuthenticators, useStartEnableMFA } from 'dbaas/services/account'
import { CentralStartEnableMFARsp } from 'dbaas/services/account/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import { eventTracking } from 'dbaas/utils/tracking'

interface TwoFAEnablingProps {
  opened: boolean
  onClose: () => void
  onConfirm: () => void
  updating?: boolean
}

const IconNumber = ({ value }: { value: number }) => {
  return (
    <Box
      w={20}
      h={20}
      bg="carbon.6"
      c="carbon.0"
      sx={{
        borderRadius: '100%',
        fontWeight: 700,
        display: 'flex',
        alignItems: 'center',
        justifyContent: 'center',
        fontSize: 14
      }}
    >
      {value}
    </Box>
  )
}

export const RecoveryCodeDisplay = ({
  recoveryCode,
  onCompleted
}: {
  recoveryCode: string
  onCompleted: () => void
}) => {
  return (
    <Flex direction="column" gap={16} mt={16}>
      <Typography variant="body-lg">
        In the event that you need to login without your device you'll need a recovery code.
      </Typography>
      <FormCopyText value={recoveryCode} />
      <Alert variant="info" icon={<IconInfoCircle />} styles={{ root: { padding: '10px 12px' } }}>
        Copy and keep this recovery code somewhere safe.
      </Alert>
      <Divider mx={-24} mt={24} />
      <Button
        mb={-8}
        sx={{ alignSelf: 'flex-end' }}
        onClick={() => {
          onCompleted()
        }}
        data-mp-event="Keep Recovery Code Done Button Clicked"
      >
        Done
      </Button>
    </Flex>
  )
}

interface MFAInfo extends CentralStartEnableMFARsp {
  password: string
}

const SetupApp = ({
  onCancel,
  onCompleted,
  mfaInfo
}: {
  onCancel: () => void
  onCompleted: () => void
  mfaInfo: MFAInfo
}) => {
  const [step, setStep] = useState<'scanning' | 'typing' | 'completed'>('scanning')
  const [error, setError] = useState('')
  const queryClient = useQueryClient()

  const { mutateAsync, isLoading } = useConfirmMfaAuthenticators()

  const onSetup = async (values: { otp_code: string }) => {
    setError('')
    try {
      await mutateAsync({ data: { password: mfaInfo.password, ...values } })
      setStep('completed')
      queryClient.invalidateQueries(getMetaQueryKey())
    } catch (e) {
      setError(getErrorMessage(e))
      throw e
    }
  }

  const CodeInput = () => (
    <FormTextInput
      name="otp_code"
      rules={{
        required: 'Required',
        pattern: {
          value: /^\d{6}$/,
          message: 'Invalid code'
        }
      }}
    />
  )

  if (step === 'typing') {
    return (
      <Form onSubmit={onSetup} withActions={false} onCancel={onCancel}>
        <Typography variant="body-lg">
          Manually enter or copy the following code into your preferred authenticator app
        </Typography>
        <FormCopyText value={mfaInfo.secret || ''} />
        <Typography variant="body-lg">Enter the 6-digit code generated by the app below</Typography>
        <CodeInput />
        {!!error && <FormErrorMessage message={error} onDismiss={() => setError('')} />}
        <Divider mx={-24} mt={8} />
        <Flex justify={'space-between'} align="center" mb={-8}>
          <Button
            variant="default"
            onClick={() => {
              setStep('scanning')
              setError('')
            }}
          >
            Back
          </Button>
          <FormActions
            mt={0}
            onCancel={onCancel}
            loading={isLoading}
            cancelProps={{
              'data-mp-event': 'Cancel enabling MFA clicked'
            }}
            confirmProps={{
              'data-mp-event': 'Confirm enabling MFA clicked',
              'data-mp-event-type': 'recovery_code'
            }}
          />
        </Flex>
      </Form>
    )
  }
  if (step === 'scanning') {
    return (
      <Form onSubmit={onSetup} actionsProps={{ mt: 16, mb: -8 }} onCancel={onCancel} withActions={false}>
        <Flex gap={64} pr={8}>
          <List spacing={'md'} styles={{ itemIcon: { alignSelf: 'flex-start' } }}>
            <List.Item icon={<IconNumber value={1} />}>
              <b>Download</b>/Use Google Authenticator (or similar) application on your mobile device.
            </List.Item>
            <List.Item icon={<IconNumber value={2} />}>
              On your Google Authenticator (or similar) app, tap the "<b>+</b>" icon and then select "
              <b>Scan QR code</b>" to scan below.
            </List.Item>
            <List.Item icon={<IconNumber value={3} />}>Enter the 6-digit code generated by the app.</List.Item>
          </List>
          <Flex direction={'column'} align={'center'} gap={8}>
            <Image src={`data:image/gif;base64,${mfaInfo.base64_qrcode}`} w={118} h={118} fit="contain"></Image>
            <Typography
              c="peacock.7"
              onClick={() => {
                setStep('typing')
                eventTracking('Trouble Scanning Button Clicked')
              }}
              sx={{ cursor: 'pointer' }}
            >
              Trouble scanning?
            </Typography>
          </Flex>
        </Flex>
        <CodeInput />
        {!!error && <FormErrorMessage message={error} onDismiss={() => setError('')} />}
        <Divider mx={-24} mt={8} />
        <FormActions
          onCancel={onCancel}
          mt={0}
          loading={isLoading}
          cancelProps={{
            'data-mp-event': 'Cancel enabling MFA clicked'
          }}
          confirmProps={{
            'data-mp-event': 'Confirm enabling MFA clicked',
            'data-mp-event-type': 'otp'
          }}
        />
      </Form>
    )
  }

  return <RecoveryCodeDisplay recoveryCode={mfaInfo.recovery_code || ''} onCompleted={onCompleted} />
}

const PasswordVerify = ({ onCancel, onCompleted }: { onCancel: () => void; onCompleted: (data: MFAInfo) => void }) => {
  const { mutateAsync, isLoading } = useStartEnableMFA()
  const [error, setError] = useState('')
  const onSubmit = async (values: { password: string }) => {
    try {
      setError('')
      const data = await mutateAsync({ data: values })
      onCompleted({ ...data, password: values.password })
    } catch (e) {
      setError(getErrorMessage(e))
    }
  }

  return (
    <Form onSubmit={onSubmit} onCancel={onCancel} withActions={false}>
      <FormPasswordInput
        mt={16}
        rules={{ required: 'Required' }}
        name="password"
        placeholder="Enter your password"
        label="Verify your password first, to continue setting up your authentication method"
      />
      {!!error && <FormErrorMessage message={error} onDismiss={() => setError('')} />}
      <Divider mx={-24} mt={24} />
      <FormActions
        mt={0}
        loading={isLoading}
        onCancel={onCancel}
        cancelProps={{
          'data-mp-event': 'Cancel password verfication Button Clicked'
        }}
        confirmProps={{
          'data-mp-event': 'Confirm password verfication  Button Clicked'
        }}
      ></FormActions>
    </Form>
  )
}

export const TwoFAEnabling = ({ opened, onClose, onConfirm, updating: _updating }: TwoFAEnablingProps) => {
  const [step, setStep] = useState<'verify' | 'setup'>('verify')
  const [mfaResp, setMFAResp] = useState<MFAInfo>({ password: '' })

  useEffect(() => {
    // reset step after setup done
    if (!opened) {
      setTimeout(() => {
        setStep('verify')
        setMFAResp({ password: '' })
      }, 100)
    }
  }, [opened])

  return (
    <Modal
      title={step === 'verify' ? 'Set Up Multi-Factor Authentication' : 'Set Up Authenticator App'}
      centered
      size="lg"
      opened={opened}
      onClose={() => {
        onClose()
      }}
      returnFocus={false}
    >
      {step === 'verify' ? (
        <PasswordVerify
          onCancel={onClose}
          onCompleted={(data) => {
            setMFAResp(data)
            setStep('setup')
          }}
        />
      ) : (
        <SetupApp
          mfaInfo={mfaResp}
          onCancel={onClose}
          onCompleted={() => {
            onConfirm()
          }}
        />
      )}
    </Modal>
  )
}
