import { zodResolver } from '@hookform/resolvers/zod';
import { Eye, EyeOff, Lock, Mail, 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 { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import { useCaptcha } from '@/hooks/auth/useCaptcha';
import { useRegister } from '@/hooks/auth/useRegister';
import { useSendRegisterEmailCode } from '@/hooks/auth/useSendRegisterEmailCode';
import { encryptRsaOaep } from '@/lib/rsa';
import { cn } from '@/lib/utils';

const registerSchema = z
  .object({
    username: z
      .string()
      .min(3, 'Username must be at least 3 characters')
      .max(32, 'Username must be at most 32 characters')
      .regex(
        /^[a-zA-Z0-9_-]+$/,
        'Username can only contain letters, numbers, hyphens, and underscores',
      ),
    email: z.string().email('Invalid email address'),
    password: z
      .string()
      .min(8, 'Password must be at least 8 characters')
      .max(128, 'Password must be at most 128 characters'),
    confirmPassword: z.string(),
    captcha: z.string().min(1, 'Captcha is required'),
    emailCode: z.string().min(1, 'Email verification code is required'),
  })
  .refine((data) => data.password === data.confirmPassword, {
    message: 'Passwords do not match',
    path: ['confirmPassword'],
  });

type RegisterForm = z.infer<typeof registerSchema>;

function getPasswordStrength(password: string) {
  if (!password) return { score: 0, label: '' };
  let score = 0;
  if (password.length >= 8) score++;
  if (password.length >= 12) score++;
  if (/[A-Z]/.test(password) && /[a-z]/.test(password)) score++;
  if (/\d/.test(password)) score++;
  if (/[^A-Za-z0-9]/.test(password)) score++;
  const clamped = Math.min(score, 4);
  const labels = ['', 'Weak', 'Fair', 'Good', 'Strong'];
  return { score: clamped, label: labels[clamped] };
}

const strengthColors = [
  'bg-border',
  'bg-destructive',
  'bg-orange-500',
  'bg-yellow-500',
  'bg-emerald-500',
];

export function RegisterPage() {
  const [showPassword, setShowPassword] = useState(false);
  const [showConfirmPassword, setShowConfirmPassword] = useState(false);

  const captchaQuery = useCaptcha({ w: 150, h: 50, rsa: true });
  const registerMutation = useRegister();
  const sendCodeMutation = useSendRegisterEmailCode();

  const {
    register,
    handleSubmit,
    setValue,
    getValues,
    watch,
    formState: { errors },
  } = useForm<RegisterForm>({
    resolver: zodResolver(registerSchema),
  });

  const captchaData = captchaQuery.data;
  const rsaKey = captchaData?.rsa?.public_key;
  const watchedPassword = watch('password');
  const strength = getPasswordStrength(watchedPassword || '');

  const handleSendCode = async () => {
    const email = getValues('email');
    const captcha = getValues('captcha');
    if (!email || !captcha) return;
    sendCodeMutation.mutate(
      { email, captcha },
      {
        onSuccess: () => {
          captchaQuery.refetch();
          setValue('captcha', '');
        },
      },
    );
  };

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

    try {
      const encryptedPassword = await encryptRsaOaep(data.password, rsaKey);
      await registerMutation.mutateAsync({
        username: data.username,
        email: data.email,
        password: encryptedPassword,
        captcha: data.captcha,
        email_code: data.emailCode,
      });
    } catch {
      captchaQuery.refetch();
      setValue('captcha', '');
    }
  };

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

  return (
    <>
      <div className="mb-8">
        <h1 className="text-[24px] font-semibold tracking-tight text-foreground">
          Create your account
        </h1>
        <p className="mt-1.5 text-[14px] text-muted-foreground">
          Fill in the details below to get started
        </p>
      </div>

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

        {/* Password */}
        <div className="space-y-5">
          <div className="space-y-2">
            <Label htmlFor="password">Password</Label>
            <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="At least 8 characters"
                autoComplete="new-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>
            {watchedPassword && (
              <div className="flex items-center gap-2.5">
                <div className="flex flex-1 gap-1">
                  <div
                    className={cn(
                      'h-1 flex-1 rounded-full transition-colors',
                      strength.score >= 1 ? strengthColors[strength.score] : 'bg-border',
                    )}
                  />
                  <div
                    className={cn(
                      'h-1 flex-1 rounded-full transition-colors',
                      strength.score >= 2 ? strengthColors[strength.score] : 'bg-border',
                    )}
                  />
                  <div
                    className={cn(
                      'h-1 flex-1 rounded-full transition-colors',
                      strength.score >= 3 ? strengthColors[strength.score] : 'bg-border',
                    )}
                  />
                  <div
                    className={cn(
                      'h-1 flex-1 rounded-full transition-colors',
                      strength.score >= 4 ? strengthColors[strength.score] : 'bg-border',
                    )}
                  />
                </div>
                {strength.label && (
                  <span className="text-[12px] text-muted-foreground">{strength.label}</span>
                )}
              </div>
            )}
            {errors.password && (
              <p className="text-[13px] text-destructive">{errors.password.message}</p>
            )}
          </div>

          <div className="space-y-2">
            <Label htmlFor="confirmPassword">Confirm Password</Label>
            <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="confirmPassword"
                type={showConfirmPassword ? 'text' : 'password'}
                {...register('confirmPassword')}
                placeholder="Confirm your password"
                autoComplete="new-password"
                className="h-11 pl-11 pr-11 text-[15px]"
              />
              <button
                type="button"
                onClick={() => setShowConfirmPassword(!showConfirmPassword)}
                className="absolute right-3 top-1/2 -translate-y-1/2 text-muted-foreground transition-colors hover:text-foreground"
                tabIndex={-1}
                aria-label={showConfirmPassword ? 'Hide password' : 'Show password'}
              >
                {showConfirmPassword ? (
                  <EyeOff className="size-[18px]" />
                ) : (
                  <Eye className="size-[18px]" />
                )}
              </button>
            </div>
            {errors.confirmPassword && (
              <p className="text-[13px] text-destructive">{errors.confirmPassword.message}</p>
            )}
          </div>
        </div>

        {/* Verification */}
        <div className="space-y-5">
          <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>

          <div className="space-y-2">
            <Label htmlFor="emailCode">Email Verification</Label>
            <div className="flex gap-2">
              <Input
                id="emailCode"
                {...register('emailCode')}
                placeholder="6-digit code"
                maxLength={6}
                className="h-11 flex-1 text-[15px]"
                autoComplete="one-time-code"
              />
              <Button
                type="button"
                variant="outline"
                onClick={handleSendCode}
                disabled={sendCodeMutation.isPending}
                className="h-11 shrink-0 px-4"
              >
                {sendCodeMutation.isPending ? 'Sending...' : 'Send Code'}
              </Button>
            </div>
            {errors.emailCode && (
              <p className="text-[13px] text-destructive">{errors.emailCode.message}</p>
            )}
            {sendCodeMutation.isSuccess && (
              <p className="text-[13px] text-emerald-600 dark:text-emerald-400">
                Verification code sent! Please check your email.
              </p>
            )}
          </div>
        </div>

        {(registerMutation.isError || sendCodeMutation.isError) && (
          <div className="rounded-lg bg-destructive/8 px-3.5 py-3 text-[13px] text-destructive">
            {(() => {
              const err = registerMutation.error ?? sendCodeMutation.error;
              if (err instanceof ApiError) {
                return err.body?.error ?? err.message;
              }
              return err instanceof Error ? err.message : 'An error occurred. Please try again.';
            })()}
          </div>
        )}

        <button
          type="submit"
          disabled={registerMutation.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',
          )}
        >
          {registerMutation.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>
              Creating account...
            </>
          ) : (
            'Create account'
          )}
        </button>
      </form>

      <p className="mt-8 text-center text-[14px] text-muted-foreground">
        Already have an account?{' '}
        <Link
          to="/auth/login"
          className="font-medium text-foreground transition-colors hover:text-primary"
        >
          Sign in
        </Link>
      </p>
    </>
  );
}
