import { Card, Typography, Center, LoadingOverlay } from '@tidbcloud/uikit'
import { Form, FormSelect } from '@tidbcloud/uikit/biz'
import { IconAlertTriangle, IconBuilding05, IconCheckCircle, IconXCircle } from '@tidbcloud/uikit/icons'
import { Suspense, useState } from 'react'
import { useForm } from 'react-hook-form'

import TimeComponent from 'dbaas/components/TimeComponent'
import { useGetUserOrgsProjects } from 'dbaas/services/account'
import auth from 'dbaas/services/auth'
import { checkUserCode, confirmAuthorization } from 'dbaas/services/oauth2'
import { Oauth2InnerDeviceCheckResponse } from 'dbaas/services/oauth2/interface'
import { eventTracking } from 'dbaas/utils/tracking'
import { useGAPageView } from 'dbaas/utils/tracking/usePageViewTracking'

import { OAUTH_DEVICE } from '../Components/constants'
import { PageShell } from '../Components/Shell'
import { VerificationCodeInput } from '../Components/VerificationCodeInput'

const getDeviceParams = () => {
  const urlParams = new URLSearchParams(window.location.search)
  const code = urlParams.get('user_code') || ''

  return {
    code
  }
}

const reLogin = () => {
  auth.logout(
    `/oauth/signin?returnTo=${encodeURIComponent(
      window.location.pathname + window.location.search
    )}&usage=${OAUTH_DEVICE}`,
    false
  )
}

const handleRequestError = (e: any) => {
  if (e?.response?.status === 401) {
    reLogin()
  }
}

const ConfirmCode: React.FC<
  React.PropsWithChildren<{
    onComplete?: (e: Oauth2InnerDeviceCheckResponse) => void
    code: string
    onCancel?: () => void
  }>
> = ({ onComplete, code, onCancel }) => {
  const onSubmit = async (data: { user_code: string[] }) => {
    try {
      data.user_code.splice(4, 0, '-')
      const res = await checkUserCode({ user_code: data.user_code.join('') }, { isHandleErr: true })
      eventTracking('Confirmed Device Code')
      onComplete?.(res)
    } catch (e) {
      handleRequestError(e)
      throw e
    }
  }

  return (
    <Card w={674} px={40} py={24}>
      <Form
        defaultValues={{
          user_code: code.split('')
        }}
        onSubmit={onSubmit}
        onCancel={onCancel}
        actionsProps={{
          cancelText: 'Cancel',
          cancelProps: {
            'data-mp-event': 'Cancel Device Code Button Clicked'
          },
          confirmText: 'Confirm Code',
          confirmProps: {
            'data-mp-event': 'Confirm Device Code Button Clicked'
          }
        }}
        errorMessageProps={{
          styles: {
            message: {
              width: '96%'
            }
          }
        }}
      >
        <Typography variant="headline-lg">Device Confirmation</Typography>
        <Typography variant="action-lg" c="carbon.7">
          Hi, {auth.getAuthInfo().email}
        </Typography>
        <Typography variant="label-lg">
          Please confirm this is the code displayed in your terminal. If code is incorrect, please return to the CLI to
          get a new verification code.
        </Typography>
        <VerificationCodeInput name="user_code" defaultValue={code} />
      </Form>
    </Card>
  )
}

const Authorization: React.FC<
  React.PropsWithChildren<{
    onComplete?: () => void
    code: string
    onCancel?: () => void
    checkResult?: Oauth2InnerDeviceCheckResponse
  }>
> = ({ onComplete, checkResult, code, onCancel }) => {
  const form = useForm({
    mode: 'all',
    defaultValues: {
      org_id: ''
    }
  })

  const onSubmit = async (data: { org_id: string }) => {
    try {
      await confirmAuthorization({ ...data, action: 'approve', user_code: code }, { isHandleErr: true })
      eventTracking('Confirmed Device Code Authorization')
      onComplete?.()
    } catch (e) {
      handleRequestError(e)
      throw e
    }
  }

  const { data, isLoading } = useGetUserOrgsProjects({
    request: {
      isHandleErr: true,
      _warningStatus: [400, 401]
    },
    query: {
      refetchInterval: false,
      refetchOnWindowFocus: false,
      onSuccess(data) {
        form.reset({ org_id: data.orgs?.[0]?.id || '' })
      },
      onError(err) {
        handleRequestError(err)
      }
    }
  })

  const orgs = (data?.orgs || []).map((it) => {
    return {
      label: it.name || '',
      value: it.id || ''
    }
  })

  const hasOrgs = !!data && !!data.orgs && data.orgs.length

  return (
    <Card w={hasOrgs ? 640 : 694} px={40} py={24} mih={224}>
      {isLoading ? (
        <LoadingOverlay visible={true} />
      ) : !hasOrgs ? (
        <>
          <Center>
            <IconAlertTriangle size={40} c="yellow.7" />
          </Center>
          <Typography variant="headline-lg" mt={24}>
            Your account is not assoicate with any organization.
          </Typography>
          <Typography variant="action-lg" c="carbon.7" lh="22px" mt={24} ta="center">
            Please{' '}
            <a href="https://www.pingcap.com/contact-us/" target="_blank" rel="noreferrer">
              contact us
            </a>
            , and we will assist you in resolving this matter.
          </Typography>
        </>
      ) : (
        <Form
          form={form}
          onSubmit={onSubmit}
          onCancel={onCancel}
          actionsProps={{
            cancelText: 'Cancel',
            cancelProps: {
              'data-mp-event': 'Cancel Device Code Authorization Button Clicked'
            },
            confirmText: 'Confirm Authorization',
            confirmProps: {
              'data-mp-event': 'Confirm Device Code Authorization Button Clicked'
            }
          }}
          errorMessageProps={{
            styles: {
              message: {
                width: '96%'
              }
            }
          }}
        >
          <Typography variant="headline-lg">Confirm your authorization</Typography>
          <Typography variant="label-lg" c="carbon.7" lh="22px">
            Confirm linking your account with TiDB Cloud CLI. Requested from {checkResult?.data?.ip}{' '}
            {checkResult?.data?.user_agent} on{' '}
            <TimeComponent time={checkResult?.data?.created_at || ''} format="MM/DD/YYYY HH:mmA" /> to access the
            following organization.
          </Typography>
          {!!data && !!data.orgs && !data.orgs.length && (
            <Typography variant="label-lg" c="carbon.7" lh="22px">
              Your account is not assoicated with any organization. Please{' '}
              <a href="https://www.pingcap.com/contact-us/" target="_blank" rel="noreferrer">
                contact us
              </a>
              , and we will assist you in resolving this matter.
            </Typography>
          )}
          <FormSelect name="org_id" data={orgs} leftSection={<IconBuilding05 c="carbon.8" size={16} />} />
        </Form>
      )}
    </Card>
  )
}

const Connected = () => {
  return (
    <Card w={450} p={40}>
      <Center>
        <IconCheckCircle size={40} c="green.7" />
      </Center>
      <Typography variant="headline-lg" mt={24} ta="center">
        Your device is now connected.
      </Typography>
      <Typography variant="action-lg" c="carbon.8" my={24} h={72} ta="center" px={16}>
        You can close this browser window and return to TiDB Cloud CLI.
      </Typography>
      <Typography variant="label-lg" component="a" ta="center" c="peacock.7" display="block">
        <a href="https://docs.pingcap.com/tidbcloud/get-started-with-cli" target="_blank" rel="noreferrer">
          CLI documentation link
        </a>
      </Typography>
    </Card>
  )
}

const Cancelled = () => {
  return (
    <Card w={632} p={40}>
      <Center>
        <IconXCircle size={40} c="red.7" />
      </Center>
      <Typography variant="headline-lg" mt={24} ta="center">
        You cancelled the OAuth authorization request
      </Typography>
      <Center>
        <Typography variant="action-lg" c="carbon.8" w={304} my={24} h={72} ta="center" px={16}>
          You can close this browser window and return to TiDB Cloud CLI.
        </Typography>
      </Center>
      <Typography variant="label-lg" component="a" ta="center" c="peacock.7" display="block">
        CLI documentation link
      </Typography>
    </Card>
  )
}

const STEPS = {
  CONFIRM_CODE: 'confirm_code',
  AUTHING: 'authing',
  CONNECTED: 'connected',
  CANCELLED: 'cancelled'
} as const

export const DeviceCode = () => {
  const [step, setSteps] = useState<string>(STEPS.CONFIRM_CODE)
  const params = getDeviceParams()
  const code = params.code
  const [checkResponse, setCheckResponse] = useState<Oauth2InnerDeviceCheckResponse | undefined>(undefined)

  useGAPageView()

  if (!auth.isAuthenticated()) {
    reLogin()
    return null
  }
  return (
    <Suspense fallback={<div></div>}>
      <PageShell>
        {step === STEPS.CONFIRM_CODE && (
          <ConfirmCode
            code={code.replaceAll('-', '')}
            onComplete={(res) => {
              setSteps(STEPS.AUTHING)
              setCheckResponse(res)
            }}
            onCancel={() => {
              setSteps(STEPS.CANCELLED)
            }}
          />
        )}
        {step === STEPS.AUTHING && (
          <Authorization
            code={code}
            onComplete={() => setSteps(STEPS.CONNECTED)}
            onCancel={() => {
              setSteps(STEPS.CANCELLED)
            }}
            checkResult={checkResponse}
          />
        )}
        {step === STEPS.CONNECTED && <Connected />}
        {step === STEPS.CANCELLED && <Cancelled />}
      </PageShell>
    </Suspense>
  )
}

export default DeviceCode
