import { useEffect, useState } from 'react'
import { Link, useNavigate, useLocation } from 'react-router-dom'
import ProviderIcon from '../../components/ProviderIcon.jsx'
import { useAuth } from '../../contexts/AuthContext.jsx'
import { api } from '../../api/client.js'
import PlayerShell, { honeypotStyle } from './PlayerShell.jsx'

// Friendly copy for the ?sso_error codes the SSO callback can bounce back with.
const SSO_ERRORS = {
  not_linked:
    'That account is not linked to a player. Enable SSO sign-up, or sign in with a password and link it under your account.',
  disabled: 'This account is not active. Contact an administrator.',
  denied: 'Sign-in was cancelled.',
  unavailable: 'That sign-in method is not available right now.',
  bad_state: 'Your sign-in session expired. Please try again.',
  error: 'Could not complete sign-in. Please try again.',
}

export default function PlayerLogin() {
  const { user, login, loginTotp, ssoLoginTotp } = useAuth()
  const navigate = useNavigate()
  const location = useLocation()
  const dest = location.state?.from?.pathname || '/player'
  // A staff member who signs in here belongs in the admin shell, not the portal.
  const destFor = (u) => (u && u.role !== 'player' ? '/admin' : dest)

  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')
  const [company, setCompany] = useState('') // honeypot — must stay empty
  const [error, setError] = useState('')
  const [busy, setBusy] = useState(false)

  const [stage, setStage] = useState('creds') // 'creds' | 'totp'
  const [challenge, setChallenge] = useState('')
  const [code, setCode] = useState('')
  const [ssoTotp, setSsoTotp] = useState(false)

  const [providers, setProviders] = useState([])
  const [canRegister, setCanRegister] = useState(false)
  const ssoError = SSO_ERRORS[new URLSearchParams(location.search).get('sso_error')] || ''

  // Already signed in → go straight to the right home for the role.
  useEffect(() => {
    if (user) navigate(destFor(user), { replace: true })
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [user, dest, navigate])

  // The SSO callback bounces 2FA accounts back here with ?sso_totp=1.
  useEffect(() => {
    if (new URLSearchParams(location.search).get('sso_totp')) {
      setStage('totp')
      setSsoTotp(true)
    }
  }, [location.search])

  // SSO providers (for buttons) + whether password registration is open.
  useEffect(() => {
    let active = true
    api
      .authProviders()
      .then((list) => active && setProviders(Array.isArray(list) ? list : []))
      .catch(() => active && setProviders([]))
    api
      .publicSettings()
      .then((s) => active && setCanRegister(Boolean(s?.registration?.password)))
      .catch(() => {})
    return () => {
      active = false
    }
  }, [])

  function startSso(provider) {
    // Always return into the player portal so the callback lands on /account*.
    const q = `?returnTo=${encodeURIComponent(dest.startsWith('/account') ? dest : '/account')}`
    window.location.assign(provider.loginUrl + q)
  }

  async function onSubmit(e) {
    e.preventDefault()
    setError('')
    setBusy(true)
    try {
      const data = await login(username, password, { company })
      if (data.totpRequired) {
        setChallenge(data.challenge)
        setStage('totp')
        setBusy(false)
        return
      }
      navigate(destFor(data.user), { replace: true })
    } catch (err) {
      if (err.status === 403) setError('This account is not active. Contact an administrator.')
      else setError(err.status === 401 ? 'Incorrect username or password.' : 'Could not sign in right now.')
      setBusy(false)
    }
  }

  async function onSubmitTotp(e) {
    e.preventDefault()
    setError('')
    setBusy(true)
    try {
      if (ssoTotp) {
        const { returnTo, redirect } = await ssoLoginTotp(code)
        // Native SSO bridge (M9): a mobile 2FA completion returns an absolute
        // deep link (e.g. runicgateway://…) to hand the app its one-time code.
        // React Router can't navigate a custom scheme, so leave the SPA for it.
        if (redirect) {
          window.location.href = redirect
          return
        }
        navigate(returnTo || '/account', { replace: true })
      } else {
        const u = await loginTotp(challenge, code)
        navigate(destFor(u), { replace: true })
      }
    } catch (err) {
      const expired = err.status === 401 && /expired/i.test(err.message)
      setError(expired ? 'Your verification session expired. Please sign in again.' : 'Invalid verification code.')
      setBusy(false)
      if (expired) {
        setStage('creds')
        setSsoTotp(false)
      }
    }
  }

  return (
    <PlayerShell
      subtitle="Player sign-in"
      footer={
        <div style={{ margin: '16px 0 0', textAlign: 'center' }}>
          <p className="sans" style={{ margin: 0, color: 'var(--dim)', fontSize: '0.84rem' }}>
            <Link to="/account/forgot" style={{ color: 'var(--accent)', textDecoration: 'none' }}>
              Forgot your password?
            </Link>
          </p>
          {canRegister && (
            <p className="sans" style={{ margin: '8px 0 0', color: 'var(--dim)', fontSize: '0.84rem' }}>
              New here?{' '}
              <Link to="/account/register" style={{ color: 'var(--accent)', textDecoration: 'none' }}>
                Create an account
              </Link>
            </p>
          )}
        </div>
      }
    >
      <form onSubmit={stage === 'totp' ? onSubmitTotp : onSubmit}>
        {stage === 'creds' ? (
          <>
            <label style={{ display: 'block', marginBottom: 16 }}>
              <span className="field-label">Username</span>
              <input type="text" autoComplete="username" autoFocus value={username} onChange={(e) => setUsername(e.target.value)} className="input" />
            </label>
            <label style={{ display: 'block', marginBottom: 22 }}>
              <span className="field-label">Password</span>
              <input type="password" autoComplete="current-password" value={password} onChange={(e) => setPassword(e.target.value)} className="input" />
            </label>
            <div style={honeypotStyle} aria-hidden="true">
              <label>
                Company
                <input type="text" name="company" tabIndex={-1} autoComplete="off" value={company} onChange={(e) => setCompany(e.target.value)} />
              </label>
            </div>
          </>
        ) : (
          <label style={{ display: 'block', marginBottom: 22 }}>
            <span className="field-label">Authentication code</span>
            <input type="text" inputMode="numeric" autoComplete="one-time-code" autoFocus placeholder="6-digit code" value={code} onChange={(e) => setCode(e.target.value)} className="input" />
            <span className="sans" style={{ display: 'block', marginTop: 8, color: 'var(--dim)', fontSize: '0.76rem' }}>
              Enter the code from your authenticator app.
            </span>
          </label>
        )}

        {(error || (stage === 'creds' && ssoError)) && (
          <p className="sans" style={{ margin: '0 0 14px', color: '#d98b84', fontSize: '0.85rem', textAlign: 'center', lineHeight: 1.5 }}>
            {error || ssoError}
          </p>
        )}

        <button type="submit" disabled={busy} className="btn btn-primary" style={{ display: 'block', width: '100%', borderRadius: 8, padding: 12, textAlign: 'center' }}>
          {busy ? 'Signing in…' : stage === 'totp' ? 'Verify' : 'Sign in'}
        </button>

        {stage === 'creds' && providers.length > 0 && (
          <div style={{ marginTop: 20 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 12, margin: '0 0 16px', color: 'var(--dim)' }}>
              <span style={{ flex: 1, height: 1, background: 'var(--line)' }} />
              <span className="sans" style={{ fontSize: '0.72rem', letterSpacing: '0.14em', textTransform: 'uppercase' }}>or</span>
              <span style={{ flex: 1, height: 1, background: 'var(--line)' }} />
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
              {providers.map((p) => (
                <button key={p.id} type="button" onClick={() => startSso(p)} className="btn" style={ssoBtnStyle}>
                  <span style={{ display: 'inline-flex', width: 18, height: 18 }}>
                    <ProviderIcon icon={p.icon} size={18} />
                  </span>
                  Continue with {p.name}
                </button>
              ))}
            </div>
          </div>
        )}
      </form>
    </PlayerShell>
  )
}

const ssoBtnStyle = {
  display: 'flex',
  alignItems: 'center',
  justifyContent: 'center',
  gap: 10,
  width: '100%',
  borderRadius: 8,
  padding: 11,
  border: '1px solid var(--line)',
  background: 'rgba(255,255,255,0.04)',
  color: 'var(--ink)',
}
