import { useEffect, useState } from 'react';
import { AlertCircle, CheckCircle2, Loader2, Lock, Mail } from 'lucide-react';
import { useNavigate } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { toast } from 'sonner';

import langbotIcon from '@/app/assets/langbot-logo.webp';
import { Button } from '@/components/ui/button';
import {
  Card,
  CardContent,
  CardDescription,
  CardHeader,
  CardTitle,
} from '@/components/ui/card';
import { Input } from '@/components/ui/input';
import { LanguageSelector } from '@/components/ui/language-selector';
import { ThemeToggle } from '@/components/ui/theme-toggle';
import type {
  Workspace,
  WorkspaceInvitation,
} from '@/app/infra/entities/workspace';
import {
  backendClient,
  bootstrapWorkspaceSession,
  clearPendingInvitationToken,
  clearUserInfo,
  getPendingInvitationToken,
  setPendingInvitationToken,
} from '@/app/infra/http';

type InvitationView = {
  invitation: WorkspaceInvitation;
  workspace: Workspace;
};

const TERMINAL_INVITATION_ERROR_CODES = new Set([
  'invitation_invalid',
  'invitation_expired',
  'invitation_revoked',
  'invitation_used',
  'invitation_email_mismatch',
]);

function invitationErrorKey(
  code: string | null | undefined,
  fallback: 'workspace.invitationInvalid' | 'workspace.invitationAcceptFailed',
) {
  switch (code) {
    case 'invitation_invalid':
      return 'workspace.invitationInvalid';
    case 'invitation_expired':
      return 'workspace.invitationExpired';
    case 'invitation_revoked':
      return 'workspace.invitationAlreadyRevoked';
    case 'invitation_used':
      return 'workspace.invitationAlreadyUsed';
    case 'invitation_email_mismatch':
      return 'workspace.invitationEmailMismatch';
    default:
      return fallback;
  }
}

function captureInvitationTokenFromFragment(): string | null {
  if (typeof window === 'undefined') return null;
  const fragment = new URLSearchParams(window.location.hash.slice(1));
  const token = fragment.get('token')?.trim();
  if (!token) return getPendingInvitationToken();

  setPendingInvitationToken(token);
  window.history.replaceState(
    null,
    document.title,
    `${window.location.pathname}${window.location.search}`,
  );
  return token;
}

export default function AcceptInvitationPage() {
  const { t } = useTranslation();
  const navigate = useNavigate();
  const [invitationHash, setInvitationHash] = useState(() =>
    typeof window === 'undefined' ? '' : window.location.hash,
  );
  const [token, setToken] = useState<string | null>(null);
  const [view, setView] = useState<InvitationView | null>(null);
  const [status, setStatus] = useState<
    'loading' | 'ready' | 'submitting' | 'success' | 'error'
  >('loading');
  const [errorMessage, setErrorMessage] = useState('');
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [passwordRegistrationEnabled, setPasswordRegistrationEnabled] =
    useState(false);
  const [
    authenticatedInvitationAcceptanceEnabled,
    setAuthenticatedInvitationAcceptanceEnabled,
  ] = useState(false);

  useEffect(() => {
    const handleHashChange = () => setInvitationHash(window.location.hash);
    window.addEventListener('hashchange', handleHashChange);
    return () => window.removeEventListener('hashchange', handleHashChange);
  }, []);

  useEffect(() => {
    setStatus('loading');
    setView(null);
    setErrorMessage('');
    const invitationToken = captureInvitationTokenFromFragment();
    const deferredErrorCode = new URLSearchParams(window.location.search).get(
      'error',
    );
    setToken(invitationToken);
    backendClient
      .getAccountInfo()
      .then((info) => {
        setPasswordRegistrationEnabled(info.password_login_enabled !== false);
        setAuthenticatedInvitationAcceptanceEnabled(
          info.authenticated_invitation_acceptance_enabled === true,
        );
      })
      .catch(() => setPasswordRegistrationEnabled(false));
    if (!invitationToken) {
      setErrorMessage(t('workspace.invitationMissing'));
      setStatus('error');
      return;
    }

    let cancelled = false;
    backendClient
      .inspectWorkspaceInvitation(invitationToken)
      .then((response) => {
        if (cancelled) return;
        setView(response);
        if (deferredErrorCode) {
          setErrorMessage(
            t(
              invitationErrorKey(
                deferredErrorCode,
                'workspace.invitationAcceptFailed',
              ),
            ),
          );
          setStatus('error');
        } else {
          setStatus('ready');
        }
      })
      .catch((error: { code?: string; msg?: string }) => {
        if (cancelled) return;
        clearPendingInvitationToken();
        setErrorMessage(
          t(invitationErrorKey(error.code, 'workspace.invitationInvalid')),
        );
        setStatus('error');
      });

    return () => {
      cancelled = true;
    };
  }, [invitationHash, t]);

  async function finishAcceptance(registration?: {
    email: string;
    password: string;
  }) {
    if (!token) return;
    setStatus('submitting');
    setErrorMessage('');
    try {
      const response = await backendClient.acceptWorkspaceInvitation(
        token,
        registration,
      );
      if (registration) {
        clearPendingInvitationToken();
        toast.success(t('workspace.invitationAccepted'));
        navigate('/login?invitation=1', { replace: true });
        return;
      }
      clearPendingInvitationToken();
      const workspaceResult = await bootstrapWorkspaceSession({
        preferredWorkspaceUuid: response.workspace_uuid,
      });
      if (workspaceResult.status !== 'ready') {
        throw new Error('Accepted Workspace could not be initialized');
      }
      setStatus('success');
      toast.success(t('workspace.invitationAccepted'));
      window.setTimeout(() => navigate('/home', { replace: true }), 600);
    } catch (error) {
      const apiError = error as { code?: string; msg?: string };
      if (apiError.code === 'account_exists_login_required') {
        setStatus('ready');
        setErrorMessage(t('workspace.existingAccountLoginRequired'));
        return;
      }
      setErrorMessage(
        t(
          invitationErrorKey(apiError.code, 'workspace.invitationAcceptFailed'),
        ),
      );
      setStatus(
        apiError.code && TERMINAL_INVITATION_ERROR_CODES.has(apiError.code)
          ? 'error'
          : 'ready',
      );
    }
  }

  function registerAndAccept() {
    if (!view) return;
    if (password.length < 8) {
      setErrorMessage(t('workspace.passwordMinimum'));
      return;
    }
    if (password !== confirmPassword) {
      setErrorMessage(t('workspace.passwordMismatch'));
      return;
    }
    void finishAcceptance({
      email: view.invitation.normalized_email,
      password,
    });
  }

  function logoutAndReturn() {
    if (token) setPendingInvitationToken(token);
    clearUserInfo();
    if (typeof window !== 'undefined') {
      localStorage.removeItem('token');
      localStorage.removeItem('userEmail');
    }
    navigate('/login?invitation=1', { replace: true });
  }

  function returnToLogin() {
    clearUserInfo();
    if (typeof window !== 'undefined') {
      localStorage.removeItem('token');
      localStorage.removeItem('userEmail');
    }
    navigate('/login', { replace: true });
  }

  const hasLoginToken =
    typeof window !== 'undefined' && Boolean(localStorage.getItem('token'));

  return (
    <div className="flex min-h-screen items-center justify-center bg-gray-50 p-4 dark:bg-neutral-900">
      <Card className="w-full max-w-md shadow-lg dark:shadow-white/10">
        <CardHeader>
          <div className="mb-4 flex items-center justify-between">
            <ThemeToggle />
            <LanguageSelector />
          </div>
          <img
            src={langbotIcon}
            alt="LangBot"
            className="mx-auto mb-3 size-14"
          />
          <CardTitle className="text-center">
            {t('workspace.acceptInvitation')}
          </CardTitle>
          <CardDescription className="text-center">
            {view
              ? t('workspace.invitedToWorkspace', {
                  workspace: view.workspace.name,
                })
              : t('workspace.checkingInvitation')}
          </CardDescription>
        </CardHeader>
        <CardContent className="space-y-4">
          {status === 'loading' && (
            <div className="flex justify-center py-8">
              <Loader2 className="size-6 animate-spin" />
            </div>
          )}

          {status === 'success' && (
            <div className="flex flex-col items-center gap-3 py-8 text-center">
              <CheckCircle2 className="size-9 text-green-600" />
              <p>{t('workspace.invitationAccepted')}</p>
            </div>
          )}

          {status === 'error' && (
            <div className="space-y-4">
              <div className="flex items-start gap-2 rounded-lg border border-destructive/20 bg-destructive/5 p-3 text-sm text-destructive">
                <AlertCircle className="mt-0.5 size-4 shrink-0" />
                <span>{errorMessage}</span>
              </div>
              <Button
                variant="outline"
                className="w-full"
                onClick={returnToLogin}
              >
                {t('workspace.backToLogin')}
              </Button>
            </div>
          )}

          {(status === 'ready' || status === 'submitting') && view && (
            <div className="space-y-4">
              {errorMessage && (
                <div className="flex items-start gap-2 rounded-lg border border-destructive/20 bg-destructive/5 p-3 text-sm text-destructive">
                  <AlertCircle className="mt-0.5 size-4 shrink-0" />
                  <span>{errorMessage}</span>
                </div>
              )}

              {hasLoginToken && authenticatedInvitationAcceptanceEnabled ? (
                <Button
                  className="w-full"
                  disabled={status === 'submitting'}
                  onClick={() => void finishAcceptance()}
                >
                  {status === 'submitting' ? (
                    <Loader2 className="mr-2 size-4 animate-spin" />
                  ) : null}
                  {t('workspace.acceptInvitation')}
                </Button>
              ) : hasLoginToken ? (
                <div className="space-y-3">
                  <div className="rounded-lg border border-amber-300 bg-amber-50 p-3 text-sm text-amber-900 dark:bg-amber-950/30 dark:text-amber-100">
                    {t('workspace.authenticatedInvitationNotice')}
                  </div>
                  <Button className="w-full" onClick={logoutAndReturn}>
                    {t('workspace.logoutAndReturn')}
                  </Button>
                </div>
              ) : passwordRegistrationEnabled ? (
                <>
                  <div className="space-y-2">
                    <label
                      className="text-sm font-medium"
                      htmlFor="invite-email"
                    >
                      {t('common.email')}
                    </label>
                    <div className="relative">
                      <Mail className="absolute left-3 top-3 size-4 text-muted-foreground" />
                      <Input
                        id="invite-email"
                        value={view.invitation.normalized_email}
                        readOnly
                        className="pl-10"
                      />
                    </div>
                  </div>
                  <div className="space-y-2">
                    <label
                      className="text-sm font-medium"
                      htmlFor="invite-password"
                    >
                      {t('common.password')}
                    </label>
                    <div className="relative">
                      <Lock className="absolute left-3 top-3 size-4 text-muted-foreground" />
                      <Input
                        id="invite-password"
                        type="password"
                        value={password}
                        onChange={(event) => setPassword(event.target.value)}
                        className="pl-10"
                        autoComplete="new-password"
                      />
                    </div>
                  </div>
                  <div className="space-y-2">
                    <label
                      className="text-sm font-medium"
                      htmlFor="invite-password-confirm"
                    >
                      {t('workspace.confirmPassword')}
                    </label>
                    <Input
                      id="invite-password-confirm"
                      type="password"
                      value={confirmPassword}
                      onChange={(event) =>
                        setConfirmPassword(event.target.value)
                      }
                      autoComplete="new-password"
                    />
                  </div>
                  <Button
                    className="w-full"
                    disabled={status === 'submitting'}
                    onClick={registerAndAccept}
                  >
                    {status === 'submitting' && (
                      <Loader2 className="size-4 animate-spin" />
                    )}
                    {t('workspace.registerAndAccept')}
                  </Button>
                  <Button
                    variant="ghost"
                    className="w-full"
                    disabled={status === 'submitting'}
                    onClick={() => navigate('/login?invitation=1')}
                  >
                    {t('workspace.alreadyHaveAccount')}
                  </Button>
                </>
              ) : (
                <Button
                  className="w-full"
                  onClick={() => navigate('/login?invitation=1&auto=space')}
                >
                  {t('common.loginWithSpace')}
                </Button>
              )}
            </div>
          )}
        </CardContent>
      </Card>
    </div>
  );
}
