import { FailedSignInResponse } from '@/proxy/auth/models'
import ActionLink from '@/components/shared/ActionLink'
import Captcha from '@/components/shared/Captcha'
import PasswordInput from '@/components/shared/PasswordInput'
import Alert from '@/components/ui/Alert'
import Button from '@/components/ui/Button'
import Checkbox from '@/components/ui/Checkbox'
import { FormContainer, FormItem } from '@/components/ui/Form'
import Input from '@/components/ui/Input'
import PlatformLoginResultType from '@/constants/login.result.enum'
import { ROUTES_ENUM } from '@/routes/route.constant'
import { getTenantByNameDetail } from '@/services/tenant.service'
import { useStoreActions, useStoreState } from '@/store'
import useAuth from '@/utils/hooks/useAuth'
import { useLocalization } from '@/utils/hooks/useLocalization'
import useTimeOutMessage from '@/utils/hooks/useTimeOutMessage'
import { TurnstileInstance } from '@marsidev/react-turnstile'
import { Field, Form, Formik } from 'formik'
import { motion } from 'framer-motion'
import { useEffect, useRef, useState } from 'react'
import { useNavigate } from 'react-router-dom'
import * as Yup from 'yup'
import { defaultDomain, getSubdomain } from '@/utils/subdomain'
import { Helmet } from 'react-helmet'
import { APP_NAME } from '@/constants/app.constant'

type SignInFormSchema = {
  userName: string
  password: string
  rememberMe: boolean
  twoFactorCode: string
  captchaResponse: string
}

const validationSchema = Yup.object().shape({
  userName: Yup.string().required('Please enter your user name'),
  password: Yup.string().required('Please enter your password'),
  rememberMe: Yup.bool(),
  twoFactor: Yup.boolean(),
  twoFactorCode: Yup.string().when('twoFactor', {
    is: true,
    then: (schema) => schema.required('Mail adresinize gönderilen doğrulama kodunu giriniz'),
    otherwise: (schema) => schema.notRequired(),
  }),
})

const Login = () => {
  const navigate = useNavigate()
  const isMultiTenant = useStoreState((a) => a.abpConfig.config?.multiTenancy.isEnabled)
  const { setTenant } = useStoreActions((a) => a.auth.tenant)

  const UiVersion = useStoreState((state) => state.locale.currentUiVersion)
  const { setUiVersion } = useStoreActions((a) => a.locale)

  const tenantName = useStoreState((state) => state.locale.currentTenantName)
  const { setTenantName } = useStoreActions((actions) => actions.locale)

  const [message, setMessage] = useState('')
  const [error, setError] = useTimeOutMessage(300000)
  const [twoFactor, setTwoFactor] = useState(false)
  const [showCaptcha, setShowCaptcha] = useState(false)

  const captchaRef = useRef<TurnstileInstance>(null)
  const { setWarning } = useStoreActions((actions) => actions.base.messages)
  const setWarningTimeout = (message: string) => {
    setTimeout(() => {
      setWarning(message)
    }, 100)
  }

  const { signIn } = useAuth()
  const { translate } = useLocalization()

  const onSignIn = async (
    values: SignInFormSchema,
    { setSubmitting, isSubmitting, setFieldValue, setFieldTouched }: any,
  ) => {
    if (isSubmitting) {
      return
    }

    setSubmitting(true)
    const { userName, password, twoFactorCode, captchaResponse } = values

    const result = await signIn({
      userName,
      password,
      twoFactorCode,
      captchaResponse,
    })

    if (result.status === 'error') {
      setError(result.message)
    } else {
      setError('')

      //Tenant belirlenmişse
      fetchDataByName(tenantName || '')
    }

    if (result.status === 'failed') {
      const data = result.data as FailedSignInResponse
      setError(data.description)

      if (data.pResult === PlatformLoginResultType.NotAllowed) {
        setWarningTimeout(data.description)
        navigate(ROUTES_ENUM.authenticated.sendConfirmationCode)
      } else {
        setWarning('')
      }

      if (
        data.pResult === PlatformLoginResultType.RequiresTwoFactor ||
        data.pResult === PlatformLoginResultType.WrongTwoFactorCode
      ) {
        if (data.pResult === PlatformLoginResultType.RequiresTwoFactor) {
          setError(undefined)
          setMessage('Mail adresinize gönderilen doğrulama kodunu giriniz')
        } else {
          setMessage('')
        }
        setTwoFactor(true)
        setFieldValue('twoFactor', true)
        setFieldTouched('twoFactorCode', false)
      } else {
        setMessage('')
        setTwoFactor(false)
        setFieldValue('twoFactor', false)
      }

      setShowCaptcha(data.pResult === PlatformLoginResultType.ShowCaptcha)
      if (data.pResult === PlatformLoginResultType.ShowCaptcha) {
        captchaRef.current?.reset()
      }

      if (
        data.pResult === PlatformLoginResultType.ShouldChangePasswordOnNextLogin ||
        data.pResult === PlatformLoginResultType.ShouldChangePasswordPeriodic
      ) {
        setWarningTimeout(data.description)
        navigate(ROUTES_ENUM.authenticated.forgotPassword)
      } else {
        setWarning('')
      }

      if (data.pResult === PlatformLoginResultType.LoginEndDateDue) {
        setWarningTimeout(data.description)
        navigate(ROUTES_ENUM.authenticated.sendExtendLogin)
      } else {
        setWarning('')
      }
    } else {
      // Temizlik
      setTwoFactor(false)
      setFieldValue('twoFactorCode', '')
      setFieldValue('twoFactor', false)
      setShowCaptcha(false)
      setError('')
      setMessage('')

      // Versiyon kontrolü
      findUiVersion()
    }

    setSubmitting(false)
  }

  const fetchDataByName = async (name: string, isSubdomain = false) => {
    if (name) {
      try {
        const response = await getTenantByNameDetail(name)

        if (response.data) {
          setTenant({ tenantId: response.data.id, tenantName: response.data.name, menuGroup: response.data.menuGroup });
        } else {
          setTenant(undefined)
          if (isSubdomain) redirectToMainDomain(name)
        }
      } catch {
        setTenant(undefined)
        if (isSubdomain) redirectToMainDomain(name)
      }
    } else {
      setTenant(undefined)
    }
  }

  const redirectToMainDomain = (name: string) => {
    setTenantName(undefined)
    const parts = window.location.hostname.split('.')
    const mainDomain = parts.length >= 3 ? parts.slice(1).join('.') : window.location.hostname
    setWarningTimeout(`"${name}" kurumuna ait kayıt bulunamadı. Ana sayfaya yönlendiriliyorsunuz...`)
    setTimeout(() => {
      window.location.href = `${window.location.protocol}//${mainDomain}`
    }, 3000)
  }

  const subDomainName = getSubdomain()
  useEffect(() => {
    if (subDomainName) {
      setTenantName(subDomainName)
      fetchDataByName(subDomainName, true)
    }
  }, [subDomainName])

  const tenantStyle: React.CSSProperties | undefined =
    subDomainName && subDomainName !== defaultDomain
      ? {
          opacity: 0,
          position: 'absolute',
          pointerEvents: 'none',
          height: 0,
          margin: 0,
          padding: 0,
          border: 'none',
        }
      : undefined

  const findUiVersion = async () => {
    try {
      const res = await fetch(`/version.json?ts=${Date.now()}`)
      const latest = (await res.json())?.releases?.[0]?.version
      if (latest && UiVersion !== latest) {
        setUiVersion(latest)
        navigate(ROUTES_ENUM.protected.admin.changeLog)
      }
    } catch (e) {
      console.warn('Versiyon okunamadı', e)
    }
  }

  return (
    <>
      <Helmet
        titleTemplate={`%s | ${APP_NAME}`}
        title={translate('AbpAccount::' + 'Login')}
        defaultTitle={APP_NAME}
      ></Helmet>
      <motion.div
        initial={{ opacity: 0, x: 100 }}
        animate={{ opacity: 1, x: 0 }}
        transition={{ duration: 0.5, origin: 1 }}
      >
        <div className="mb-8 relative text-center">
          <h3 className="mb-1 m-5">{translate('::Abp.Account.WelcomeBack')}</h3>
          <p>{translate('::Abp.Account.WelcomeBack.Message')}</p>
        </div>

        {isMultiTenant && (
          <>
            <label className="form-label mb-2" style={tenantStyle}>
              {translate('::Organization')}
            </label>
            <div className="mb-4">
              <Input
                placeholder={translate('::Organization')}
                value={tenantName}
                onChange={(e) => setTenantName(e.target.value)}
                style={tenantStyle}
                aria-hidden={subDomainName && subDomainName !== defaultDomain ? 'true' : 'false'}
              />
            </div>
          </>
        )}
        <div>
          <Formik
            initialValues={{
              userName: '',
              password: '',
              twoFactorCode: '',
              rememberMe: true,
              captchaResponse: '',
            }}
            validationSchema={validationSchema}
            onSubmit={onSignIn}
          >
            {({ touched, errors, isSubmitting, setFieldValue }) => (
              <Form>
                <FormContainer>
                  {!twoFactor && (
                    <FormItem
                      label={translate('::Abp.Account.EmailAddress')}
                      invalid={errors.userName && touched.userName}
                      errorMessage={errors.userName}
                    >
                      <Field
                        type="text"
                        autoComplete="off"
                        name="userName"
                        placeholder={translate('::Abp.Account.EmailAddress')}
                        component={Input}
                      />
                    </FormItem>
                  )}
                  {!twoFactor && (
                    <FormItem
                      label={translate('::Abp.Identity.Password')}
                      invalid={errors.password && touched.password}
                      errorMessage={errors.password}
                    >
                      <Field
                        autoComplete="off"
                        name="password"
                        placeholder={translate('::Abp.Identity.Password')}
                        component={PasswordInput}
                      />
                    </FormItem>
                  )}
                  {twoFactor && (
                    <FormItem
                      label={translate('::Abp.Account.2FACode')}
                      invalid={errors.twoFactorCode && touched.twoFactorCode}
                      errorMessage={errors.twoFactorCode}
                    >
                      <Field
                        autoComplete="off"
                        name="twoFactorCode"
                        placeholder={translate('::Abp.Account.2FACode')}
                        component={Input}
                      />
                    </FormItem>
                  )}

                  <div className="flex justify-between mb-6">
                    <Field className="mb-0" name="rememberMe" component={Checkbox}>
                      {translate('::Abp.Account.RememberMe')}
                    </Field>
                    <ActionLink to={ROUTES_ENUM.authenticated.forgotPassword}>
                      {translate('::Abp.Account.ForgotPassword')}
                    </ActionLink>
                  </div>
                  {showCaptcha && (
                    <Captcha
                      ref={captchaRef}
                      onError={() => setFieldValue('captchaResponse', '')}
                      onExpire={() => setFieldValue('captchaResponse', '')}
                      onSuccess={(token: string) => setFieldValue('captchaResponse', token)}
                    />
                  )}

                  {message && (
                    <Alert showIcon className="mb-4" type="success">
                      {message}
                    </Alert>
                  )}
                  {error && (
                    <Alert showIcon className="mb-4" type="danger">
                      {error}
                    </Alert>
                  )}

                  <Button block loading={isSubmitting} variant="solid" type="submit">
                    {isSubmitting ? 'Signing in...' : 'Sign In'}
                  </Button>
                  <div className="mt-4 text-center">
                    <span>{translate('::Abp.Account.SignUp.Message')} </span>
                    <ActionLink to={ROUTES_ENUM.authenticated.register}>
                      {translate('::Abp.Account.Register')}
                    </ActionLink>
                  </div>
                </FormContainer>
              </Form>
            )}
          </Formik>
        </div>
      </motion.div>
    </>
  )
}

export default Login
