import { Alert, Group, Box, Typography, Image } from '@tidbcloud/uikit'
import { FormTextInput, Form } from '@tidbcloud/uikit/biz'
import { IconCheckCircle } from '@tidbcloud/uikit/icons'
import React, { useEffect, useState, useCallback, useMemo } from 'react'

import buildConfig from 'config'
import Link from 'dbaas/components/Link'
import { createAuth0User } from 'dbaas/services'
import { CentralAcceptInvitationReq } from 'dbaas/services'
import auth, { databaseConnection } from 'dbaas/services/auth'
import { setSSOSource } from 'dbaas/stores/localStorage'
import { useInterval } from 'dbaas/utils/useInterval'
import useSessionStorage from 'dbaas/utils/useSessionStorage'
import { firstNameRules, lastNameRules } from 'dbaas/utils/validationRules'

import { AcceptServices, MSPAgreement } from '../../Common/AcceptServices'
import { useMSPCustomer } from '../../Common/MSP'
import { PageShell } from '../../Common/Shell'
import { getEmail } from '../../utils'
import SSOLogin from '../components/SSOLogin'
import { INVITE_CALLBACK_URI } from '../constants'

type ITenantFormValues = Pick<CentralAcceptInvitationReq, 'email' | 'first_name' | 'last_name'> & { password: string }

const SSO_SIGNUP_ENABLED: boolean = buildConfig.featureFlags.enableSSOSignupInvitation

const TenantFields = React.memo(({ email, services }: { email: string; services?: React.ReactNode }) => {
  return (
    <>
      {/* Ensure users cannot edit the email field */}
      <FormTextInput name="email" placeholder="Work Email" required readOnly value={email} mb={16} />
      <Group justify="space-between" grow align="flex-start" mb={16}>
        <FormTextInput
          name="first_name"
          placeholder="First Name"
          rules={{
            required: 'Required',
            ...firstNameRules
          }}
        />
        <FormTextInput
          name="last_name"
          placeholder="Last Name"
          rules={{
            required: 'Required',
            ...lastNameRules
          }}
        />
      </Group>
      <FormTextInput
        type="password"
        name="password"
        placeholder="Password"
        autoComplete="new-password"
        mb={16}
        rules={{
          required: 'Required',
          minLength: {
            value: 8,
            message: 'At least 8 characters in length.'
          },
          maxLength: {
            value: 64,
            message: 'Maximum 64 characters in length.'
          },
          pattern: {
            value: /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[^]{8,64}$/,
            message:
              'The password should contain the following types of characters: upper case letters (A-Z), lower case letters (a-z), numbers (such as 0-9).'
          }
        }}
      />
      {!!services ? services : <AcceptServices />}
    </>
  )
})

const CompleteCustomRegister = ({
  email,
  password,
  login
}: {
  email: string
  password: string
  login: (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => void
}) => {
  const [counter, setCounter] = useState(5)

  const countDown = () => {
    if (counter > 0) {
      setCounter(counter - 1)
    }
  }

  useInterval(countDown, 1000, false)

  useEffect(() => {
    if (counter === 0) {
      // login to auth0
      auth.auth0.login(
        {
          realm: databaseConnection,
          email,
          password,
          redirectUri: INVITE_CALLBACK_URI
        },
        function (err) {
          if (err) {
            // login error
            console.error(err?.description || 'Something went wrong.')
            // redirect to universal login
            auth.login()
          }
        }
      )
    }
  }, [counter, password, email])

  return (
    <Box ta="center">
      <Box c="green.5">
        <IconCheckCircle size={64} />
      </Box>
      <div>
        <p>
          Your account <strong>{email}</strong> has been successfully activated!
        </p>
        <p>
          You will be redirected to the sign in page after <strong>{counter} s</strong> or click{' '}
          <Link
            className="link"
            onClick={login}
            href="/"
            eventName="Sign In Link Clicked"
            eventParams={{ source: 'Invite' }}
          >
            Sign In
          </Link>
          .
        </p>
      </div>
      <div>
        <p>
          Please contact{' '}
          <Link
            href="mailto:tidbcloud-support@pingcap.com"
            eventName="Tidbcloud Email Support Link Clicked"
            eventParams={{ source: 'Invite' }}
          >
            tidbcloud-support@pingcap.com
          </Link>{' '}
          if you have any questions.
          <br />
        </p>
      </div>
    </Box>
  )
}

const SignUp: React.FC<React.PropsWithChildren<unknown>> = () => {
  const search = window.location.search
  const urlParams = useMemo(() => new URLSearchParams(search), [search])
  const email = getEmail(urlParams.get('email') || '') // invited user email
  const token = urlParams.get('token') || '' // invite token
  const orgId = urlParams.get('org_id') || '' //invite user from a exist tenant
  const orgName = urlParams.get('org_name') // invite organization name

  const [step, setStep] = useState(0)
  const [password, setPassword] = useState('')
  const [loading, setLoading] = useState(false)

  const [inviteUser, setInviteUser] = useSessionStorage<
    CentralAcceptInvitationReq & { invite_link: string; connection: string; search: string }
  >('invite_user')

  const { isMSPCustomer, advertisings, logo_url, disclaimers } = useMSPCustomer(urlParams.get('msp') || '')

  const login = (e: React.MouseEvent<HTMLAnchorElement, MouseEvent>) => {
    e.preventDefault()
    auth.logout()
  }

  const changeStep = useCallback((step: number) => {
    setStep(step)
  }, [])

  const goNext = useCallback(() => {
    changeStep(step + 1)
  }, [step, changeStep])

  const registerUser = async (data: ITenantFormValues) => {
    setLoading(true)
    try {
      await createAuth0User(orgId, {
        password: data.password,
        token,
        org_id: orgId
      })
      goNext()
    } finally {
      setLoading(false)
    }

    setInviteUser({
      first_name: data.first_name,
      last_name: data.last_name,
      email,
      org_id: orgId,
      invite_link: window.location.pathname + search,
      connection: databaseConnection,
      search
    })
    setPassword(data.password)
  }

  const beforeSSOAction = (connectionType: string) => {
    setInviteUser({
      first_name: '',
      last_name: '',
      email,
      org_id: orgId,
      invite_link: window.location.pathname + search,
      connection: connectionType,
      search
    })
    setSSOSource('invite_signup')
  }

  const first_name = inviteUser?.first_name || ''
  const last_name = inviteUser?.last_name || ''
  const defaultTenant = useMemo(
    () => ({
      email,
      first_name,
      last_name,
      password: ''
    }),
    [email, first_name, last_name]
  )

  return (
    <PageShell
      extra={!!logo_url ? <Image src={logo_url} height={40} fit="contain" sx={{ maxWidth: 4 * 40 }} /> : undefined}
      slogans={!!advertisings?.length ? advertisings : undefined}
      withAdvertisement={!advertisings?.length}
    >
      <Box w={step === 1 ? 'auto' : 360} m="0 auto" px={step === 1 ? 32 : undefined}>
        {step === 1 ? (
          <CompleteCustomRegister email={email} password={password} login={login} />
        ) : (
          <div>
            <Box sx={{ wordBreak: 'break-word', wordWrap: 'break-word', whiteSpace: 'normal' }}>
              <Alert mb={16}>
                You have been invited to join{' '}
                {orgName ? (
                  <>
                    the <b>{orgName}</b> organization
                  </>
                ) : (
                  'TiDB Cloud'
                )}
                . To accept the invitation, please sign up.
              </Alert>
              <Typography variant="headline-md">Create an account</Typography>
            </Box>

            <div>
              {SSO_SIGNUP_ENABLED && <SSOLogin action="sign-up" beforeAction={beforeSSOAction} />}
              <Form<ITenantFormValues>
                layoutProps={{ gap: 0 }}
                onSubmit={registerUser}
                defaultValues={defaultTenant}
                actionsProps={{
                  mt: 16,
                  confirmText: 'Join',
                  cancelProps: {
                    display: 'none'
                  },
                  confirmProps: {
                    'data-mp-event': 'mp-join-1691461016271',
                    loading,
                    w: '100%',
                    h: 40
                  }
                }}
              >
                <TenantFields
                  email={email}
                  services={isMSPCustomer ? <MSPAgreement agreement={disclaimers} /> : undefined}
                />
              </Form>
            </div>

            <Typography variant="body-md" mt={8}>
              Already have an account?{' '}
              <Link
                className="link"
                onClick={login}
                href="/"
                eventName="Sign In Link Clicked"
                eventParams={{ source: 'Invite' }}
              >
                Sign In
              </Link>
            </Typography>
          </div>
        )}
      </Box>
    </PageShell>
  )
}

export default SignUp
