import React, { useEffect } from 'react'

import { Tooltip, Badge, createStyles } from '@mantine/core'
import { useLocalStorage } from '@mantine/hooks'
import { showNotification } from '@mantine/notifications'
import { IconSwitchHorizontal } from '@tabler/icons-react'
import jwtDecode from 'jwt-decode'

import { LoginValidation } from '@clinic/client'
import { validateOAuth } from '~/api'
import { ClinicIcon } from '~/components/Icons'
import {
  getBaseURL,
  getRedirectURL,
  isSSOCallback,
  setCsrfToken,
  clearLoginFrom,
  getLoginFrom,
  setLoginFrom,
  clearCsrfToken,
  clearOAuthCallbackSearchParams
} from '~/utils/auth'
import auth0Auth from '~/utils/auth0-auth'
import {
  getCiamTidbAuth,
  initCiamTidbAuth,
  type CiamTidbAuthConfig
} from '~/utils/ciam-tidb-auth'
import envConfig, {
  isCNRegion,
  allowPingKai,
  shouldShowPingKaiCloud
} from '~/utils/env-config'
import { getOtherRegionRes, getRegionRes } from '~/utils/region-res'

// https://esbuild.github.io/content-types/#file
// need to set `loader: {'.jpeg': 'file'` in the builder.js
// need to set `declare module '*.jpeg' {}` in types.d.ts as well
// source: https://unsplash.com/photos/MFSEP2g4YS0
import clinicCover from './clinic-cover.jpeg'
import LoginButton, { AuthProviderUnion } from './components/LoginButton'

const regionRes = getRegionRes()
const otherRegionRes = getOtherRegionRes()

let callbackProcessing = false

function oauthErrorMessage(err: unknown): string {
  if (typeof err === 'object' && err !== null && 'response' in err) {
    const d = (err as { response?: { data?: unknown } }).response?.data
    if (typeof d === 'string') return d.slice(0, 400)
    if (d && typeof d === 'object') {
      const o = d as { message?: string; error?: string }
      if (o.message) return String(o.message)
      if (o.error) return String(o.error)
    }
  }
  if (err instanceof Error) return err.message
  return 'Sign in failed'
}

function getPingKaiCloudRedirectUri() {
  const uri = envConfig.pingkaicloudCiam.redirectUri.trim()
  return uri || getRedirectURL()
}

function shouldEnablePingKaiCloud() {
  return isCNRegion() && shouldShowPingKaiCloud()
}

function ensureCiamClient() {
  if (!shouldEnablePingKaiCloud()) return null
  let c = getCiamTidbAuth()
  if (!c) {
    const cfg: CiamTidbAuthConfig = {
      issuer: envConfig.pingkaicloudCiam.issuer,
      clientId: envConfig.pingkaicloudCiam.clientId,
      scope: envConfig.pingkaicloudCiam.scope,
      loginDomain: envConfig.pingkaicloudCiam.loginDomain,
      authorizationEndpoint: envConfig.pingkaicloudCiam.authorizationEndpoint,
      tokenProxyEndpoint: envConfig.pingkaicloudCiam.tokenProxyEndpoint,
      tokenProxySource: envConfig.pingkaicloudCiam.tokenProxySource,
      redirectUri: envConfig.pingkaicloudCiam.redirectUri
    }
    c = initCiamTidbAuth(cfg)
  }
  return c
}

const useStyles = createStyles((_theme) => ({
  image: {
    position: 'relative',
    flex: '1 1 0%',
    backgroundPosition: 'center',
    backgroundSize: 'cover',
    backgroundImage: `url(${clinicCover})`
  }
}))

// gray colors: https://yeun.github.io/open-color/gray-color.html
// bg: bg-gray-50/100
// border: border-gray-200/300/400
// subtle text: text-gray-500/600
// main text: text-gray-700/800/900
const LoginPage: React.FC = () => {
  const { classes } = useStyles()

  const isAuthCallback = isSSOCallback()
  const [authProvider, setAuthProvider] = useLocalStorage<AuthProviderUnion>({
    key: 'clinic.auth.provider',
    defaultValue: 'internal',
    getInitialValueInEffect: false
  })

  useEffect(() => {
    if (!isAuthCallback) {
      const locationHash = window.location.hash
      const hashSearchPos = locationHash.indexOf('?')
      if (hashSearchPos > 0) {
        const search = locationHash.slice(hashSearchPos)
        const p = new URLSearchParams(search)
        const from = decodeURIComponent(p.get('next') || '')
        if (from) {
          setLoginFrom(from)
        }
      }
    }
  }, [isAuthCallback])

  useEffect(() => {
    function validate(authProvider: AuthProviderUnion, data: LoginValidation) {
      validateOAuth(authProvider, data)
        .then((res) => {
          clearOAuthCallbackSearchParams()
          const { session_key } = res.data
          const obj = jwtDecode(session_key!)
          const csrfToken = (obj as any).user.csrfToken
          setCsrfToken(csrfToken)

          const from = getLoginFrom()
          if (from.startsWith('http')) {
            window.location.assign(from)
          } else {
            window.location.assign(`${window.location.pathname}#${from}`)
          }
          clearLoginFrom()
        })
        .catch((err) => {
          clearOAuthCallbackSearchParams()
          showNotification({
            color: 'red',
            title: 'Sign in failed',
            message: oauthErrorMessage(err),
            autoClose: 8000
          })
          const loginUrl = `${getBaseURL()}#/login`
          if (authProvider === 'tidbcloud') {
            auth0Auth.logout(loginUrl)
            return
          }
          if (authProvider === 'pingkaicloud') {
            window.location.assign(loginUrl)
            return
          }
          setTimeout(() => {
            window.location.assign(loginUrl)
          }, 2000)
        })
    }

    if (isAuthCallback) {
      if (callbackProcessing) return
      callbackProcessing = true

      const sp = new URLSearchParams(window.location.search)
      const redirect_uri = getRedirectURL()

      // ─── pingkaicloud (CIAM): idaasAppId 或 provider 匹配 ───
      const isCiamCodeCallback =
        shouldEnablePingKaiCloud() &&
        sp.has('code') &&
        sp.has('state') &&
        (sp.has('idaasAppId') || authProvider === 'pingkaicloud')

      if (isCiamCodeCallback) {
        const ciam = ensureCiamClient()
        if (ciam) {
          ciam
            .exchangeCodeForIdToken()
            .then((token) =>
              validateOAuth('tidbcloud', {
                code: token,
                redirect_uri: getPingKaiCloudRedirectUri()
              })
            )
            .then((res) => {
              clearOAuthCallbackSearchParams()
              const { session_key } = res.data
              const obj = jwtDecode(session_key!)
              const csrfToken = (obj as any).user.csrfToken
              setCsrfToken(csrfToken)
              const from = getLoginFrom()
              if (from.startsWith('http')) {
                window.location.assign(from)
              } else {
                window.location.assign(`${window.location.pathname}#${from}`)
              }
              clearLoginFrom()
            })
            .catch((err) => {
              clearOAuthCallbackSearchParams()
              showNotification({
                color: 'red',
                title: 'Sign in failed',
                message: oauthErrorMessage(err),
                autoClose: 10000
              })
              window.location.replace(`${getBaseURL()}#/login`)
            })
          return
        }
      }

      // ─── tidbcloud (Auth0 implicit flow) ───
      if (authProvider === 'tidbcloud') {
        auth0Auth
          .parseToken()
          .then((token) => validate('tidbcloud', { code: token, redirect_uri }))
          .catch((err) => console.log('validate tidbcloud err: ', err))
        return
      }

      // ─── ask_tug / internal / pingkai (server-side OAuth) ───
      if (
        authProvider === 'ask_tug' ||
        authProvider === 'internal' ||
        authProvider === 'pingkai'
      ) {
        const code = sp.get('code') || ''
        const state = sp.get('state') || ''
        validate(authProvider, { code, state, redirect_uri })
      }
    }
  }, [isAuthCallback, authProvider])

  function login(authProvider: AuthProviderUnion, authUrl: string) {
    clearCsrfToken()
    setAuthProvider(authProvider)

    if (authProvider === 'tidbcloud') {
      auth0Auth.login()
      return
    }
    if (authProvider === 'pingkaicloud') {
      const ciam = ensureCiamClient()
      if (ciam) {
        void ciam.loginWithRedirect()
        return
      }
    }
    if (authUrl) {
      window.location.assign(authUrl)
    }
  }

  return (
    <div className='min-h-full flex'>
      <div className='w-full sm:max-w-lg bg-white flex flex-col'>
        <div className='flex-1 flex items-center justify-center p-8 pb-24'>
          <div className='flex flex-col'>
            <h1 className='text-cc-brand text-4xl mb-16 font-extrabold flex items-center gap-2'>
              <ClinicIcon />
              <Badge
                color='green'
                size='md'
                radius='sm'
                variant='outline'
                px={4}
              >
                {regionRes.regionText}
              </Badge>
            </h1>
            <h2 className='py-4 text-gray-800 font-bold'>Sign In</h2>

            {isAuthCallback && (
              <LoginButton authProvider={authProvider} loading={true} />
            )}

            {!isAuthCallback && (
              <>
                {isCNRegion() ? (
                  <>
                    <LoginButton authProvider='ask_tug' onClick={login} />
                    <div className='h-4' />
                    <LoginButton authProvider='internal' onClick={login} />
                  </>
                ) : (
                  <>
                    <LoginButton authProvider='tidbcloud' onClick={login} />
                    <div className='h-4' />
                    <LoginButton authProvider='internal' onClick={login} />
                  </>
                )}
                {shouldEnablePingKaiCloud() && (
                  <>
                    <div className='h-4' />
                    <LoginButton authProvider='pingkaicloud' onClick={login} />
                  </>
                )}
                {allowPingKai() ? (
                  <>
                    <div className='h-4' />
                    <LoginButton authProvider='pingkai' onClick={login} />
                  </>
                ) : (
                  <></>
                )}
              </>
            )}

            <p className='text-gray-600 text-xs mt-4'>
              When signing in to Clinic, you're agreeing to our{' '}
              <a
                href={regionRes.servicesAgreementLink}
                target='_blank'
                className='text-gray-600 font-medium'
              >
                TiDB Clinic Service Agreement
              </a>{' '}
              and{' '}
              <a
                href={regionRes.privacyLink}
                target='_blank'
                className='text-gray-600 font-medium'
              >
                Privacy Policy
              </a>
              .
            </p>
          </div>
        </div>

        <footer className='border-0 border-t border-gray-300 border-solid h-12 px-8 flex items-center'>
          <a
            href={regionRes.quickStartLink}
            className='text-gray-600 text-xs'
            target='_blank'
          >
            Quick Start
          </a>
          <a
            href={regionRes.releaseNoteLink}
            className='text-gray-600 text-xs ml-2'
            target='_blank'
          >
            Release Note
          </a>

          <div className='ml-auto'>
            <Tooltip
              withArrow
              label={`Switch to ${otherRegionRes.regionText.toUpperCase()} region`}
            >
              <a
                href={otherRegionRes.regionLink}
                className='border border-solid rounded p-1 border-gray-300 hover:border-cc-primary text-gray-600 text-xs font-light flex items-center'
              >
                <span>{regionRes.regionText.toUpperCase()}</span>
                <IconSwitchHorizontal size={14} />
                <span className='font-semibold'>
                  {otherRegionRes.regionText.toUpperCase()}
                </span>
              </a>
            </Tooltip>
          </div>
        </footer>
      </div>

      <div className={classes.image}></div>
    </div>
  )
}

export default LoginPage
