import { zodResolver } from '@hookform/resolvers/zod';
import { Eye, EyeOff, Lock, User } from 'lucide-react';
import { useState } from 'react';
import { useForm } from 'react-hook-form';
import { Link } from 'react-router-dom';
import { z } from 'zod';
import { ApiError } from '@/client/core/ApiError';
import { CaptchaImage } from '@/components/CaptchaImage';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { useCaptcha } from '@/hooks/auth/useCaptcha';
import { useLogin } from '@/hooks/auth/useLogin';
import { encryptRsaOaep } from '@/lib/rsa';
import { cn } from '@/lib/utils';

const loginSchema = z.object({
  username: z.string().min(1, 'Username or email is required'),
  password: z.string().min(1, 'Password is required'),
  captcha: z.string().min(1, 'Captcha is required'),
  totp_code: z.string().optional(),
});

type LoginForm = z.infer<typeof loginSchema>;

export function LoginPage() {
  const [showPassword, setShowPassword] = useState(false);
  const [requiresTotp, setRequiresTotp] = useState(false);

  const captchaQuery = useCaptcha({ w: 150, h: 50, rsa: true });
  const loginMutation = useLogin();

  const {
    register,
    handleSubmit,
    setValue,
    formState: { errors },
  } = useForm<LoginForm>({
    resolver: zodResolver(loginSchema),
  });

  const captchaData = captchaQuery.data;
  const rsaKey = captchaData?.rsa?.public_key;

  const onSubmit = async (data: LoginForm) => {
    if (!rsaKey) return;

    try {
      const encryptedPassword = await encryptRsaOaep(data.password, rsaKey);
      await loginMutation.mutateAsync({
        username: data.username,
        password: encryptedPassword,
        captcha: data.captcha,
        totp_code: requiresTotp ? data.totp_code || undefined : undefined,
      });
    } catch (err) {
      if (err instanceof ApiError && err.body?.error === 'two-factor authentication required') {
        setRequiresTotp(true);
        return;
      }
      if (!requiresTotp) {
        captchaQuery.refetch();
        setValue('captcha', '');
      }
      if (requiresTotp) {
        setValue('totp_code', '');
      }
    }
  };

  const handleRefreshCaptcha = () => {
    captchaQuery.refetch();
    setValue('captcha', '');
  };

  return (
    <>
      <div className="mb-8">
        <h1 className="text-[24px] font-semibold tracking-tight text-foreground">Sign in</h1>
        <p className="mt-1.5 text-[14px] text-muted-foreground">
          Enter your credentials to access your account
        </p>
      </div>

      <form onSubmit={handleSubmit(onSubmit)} className="space-y-5">
        <div className="space-y-2">
          <Label htmlFor="username">Username or Email</Label>
          <div className="relative">
            <User className="pointer-events-none absolute left-3 top-1/2 size-[18px] -translate-y-1/2 text-muted-foreground" />
            <Input
              id="username"
              {...register('username')}
              placeholder="username or email@example.com"
              autoComplete="username"
              className="h-11 pl-11 text-[15px]"
            />
          </div>
          {errors.username && (
            <p className="text-[13px] text-destructive">{errors.username.message}</p>
          )}
        </div>

        <div className="space-y-2">
          <div className="flex items-center justify-between">
            <Label htmlFor="password">Password</Label>
            <Link
              to="/auth/forgot-password"
              className="text-[13px] text-muted-foreground transition-colors hover:text-foreground"
            >
              Forgot password?
            </Link>
          </div>
          <div className="relative">
            <Lock className="pointer-events-none absolute left-3 top-1/2 size-[18px] -translate-y-1/2 text-muted-foreground" />
            <Input
              id="password"
              type={showPassword ? 'text' : 'password'}
              {...register('password')}
              placeholder="Enter your password"
              autoComplete="current-password"
              className="h-11 pl-11 pr-11 text-[15px]"
            />
            <button
              type="button"
              onClick={() => setShowPassword(!showPassword)}
              className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground transition-colors hover:text-foreground"
              tabIndex={-1}
              aria-label={showPassword ? 'Hide password' : 'Show password'}
            >
              {showPassword ? <EyeOff className="size-[18px]" /> : <Eye className="size-[18px]" />}
            </button>
          </div>
          {errors.password && (
            <p className="text-[13px] text-destructive">{errors.password.message}</p>
          )}
        </div>

        {requiresTotp && (
          <div className="space-y-2">
            <Label htmlFor="totp_code">Two-Factor Code</Label>
            <Input
              id="totp_code"
              {...register('totp_code')}
              placeholder="6-digit code"
              maxLength={6}
              autoComplete="one-time-code"
              className="h-11 text-[15px]"
            />
          </div>
        )}

        <div className="space-y-2">
          <Label htmlFor="captcha">Security Check</Label>
          <div className="flex items-start gap-3">
            <div className="flex-1 space-y-2">
              <Input
                id="captcha"
                {...register('captcha')}
                placeholder="Enter captcha code"
                autoComplete="off"
                className="h-11 text-[15px]"
              />
              {errors.captcha && (
                <p className="text-[13px] text-destructive">{errors.captcha.message}</p>
              )}
            </div>
            <CaptchaImage
              base64={captchaData?.base64 ?? ''}
              width={captchaData?.req.w ?? 240}
              height={captchaData?.req.h ?? 80}
              isLoading={captchaQuery.isLoading}
              onRefresh={handleRefreshCaptcha}
            />
          </div>
        </div>

        {loginMutation.isError && (
          <div className="rounded-lg bg-destructive/8 px-3.5 py-3 text-[13px] text-destructive">
            {(() => {
              const err = loginMutation.error;
              if (err instanceof ApiError) {
                return err.body?.error ?? err.message;
              }
              return err instanceof Error
                ? err.message
                : 'Login failed. Please check your credentials.';
            })()}
          </div>
        )}

        <button
          type="submit"
          disabled={loginMutation.isPending}
          className={cn(
            'flex h-11 w-full items-center justify-center gap-2 rounded-lg bg-primary text-[15px] font-medium text-primary-foreground',
            'transition-all hover:bg-primary/90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40',
            'disabled:pointer-events-none disabled:opacity-50',
          )}
        >
          {loginMutation.isPending ? (
            <>
              <svg
                className="size-[18px] animate-spin"
                viewBox="0 0 24 24"
                fill="none"
                role="status"
                aria-label="Loading"
              >
                <title>Loading</title>
                <circle
                  cx="12"
                  cy="12"
                  r="10"
                  stroke="currentColor"
                  strokeWidth="3"
                  className="opacity-25"
                />
                <path
                  d="M12 2a10 10 0 0 1 10 10"
                  stroke="currentColor"
                  strokeWidth="3"
                  strokeLinecap="round"
                  className="opacity-75"
                />
              </svg>
              Signing in...
            </>
          ) : (
            'Sign in'
          )}
        </button>
      </form>

      <p className="mt-8 text-center text-[14px] text-muted-foreground">
        Don&apos;t have an account?{' '}
        <Link
          to="/auth/register"
          className="font-medium text-foreground transition-colors hover:text-primary"
        >
          Create account
        </Link>
      </p>
    </>
  );
}
