import type { FormComponentRef } from '@inertiajs/core';
import { Form, Head, router } from '@inertiajs/react';
import { Eye, EyeOff, Info, Loader2, Lock } from 'lucide-react';
import { useRef, useState } from 'react';
import { Button } from '@/components/ui/button';
import {
    Field,
    FieldError,
    FieldGroup,
    FieldLabel,
} from '@/components/ui/field';
import { Input } from '@/components/ui/input';
import { Separator } from '@/components/ui/separator';
import {
    PASSWORD_LOWER_REGEX,
    PASSWORD_MAX,
    PASSWORD_MIN,
    PASSWORD_NUMBER_REGEX,
    PASSWORD_SPECIAL_REGEX,
    PASSWORD_UPPER_REGEX,
} from '@/lib/constants';
import { route } from '@/lib/route';
import { cn } from '@/lib/utils';

function passwordChangeClientErrors(data: Record<string, unknown>): Record<string, string> {
    const errors: Record<string, string> = {};
    const password = String(data.password ?? '');
    const confirmation = String(data.password_confirmation ?? '');

    if (!password) {
        errors.password = 'The password field is required.';
    } else if (password.length < PASSWORD_MIN) {
        errors.password = `The password field must be at least ${PASSWORD_MIN} characters.`;
    } else if (password.length > PASSWORD_MAX) {
        errors.password = `The password field must not be greater than ${PASSWORD_MAX} characters.`;
    } else {
        const hasUpper = PASSWORD_UPPER_REGEX.test(password);
        const hasLower = PASSWORD_LOWER_REGEX.test(password);
        const hasNumber = PASSWORD_NUMBER_REGEX.test(password);
        const hasSpecial = PASSWORD_SPECIAL_REGEX.test(password);

        if (!hasUpper || !hasLower || !hasNumber || !hasSpecial) {
            errors.password =
                'Password must include 1 uppercase, 1 lowercase, 1 number, and 1 special character.';
        }
    }

    if (!confirmation) {
        errors.password_confirmation = 'The password confirmation field is required.';
    } else if (password && confirmation !== password) {
        errors.password_confirmation = 'The password field confirmation does not match.';
    }

    return errors;
}

function RequiredMark() {
    return (
        <span className="text-destructive" aria-hidden>
            *
        </span>
    );
}

function PasswordRequirementsCallout() {
    return (
        <div
            role="note"
            className="flex gap-3 rounded-lg border border-amber-300/80 bg-amber-50 px-4 py-3.5 text-sm leading-relaxed text-amber-950"
        >
            <Info
                aria-hidden
                className="mt-0.5 size-4 shrink-0 text-amber-600"
            />
            <p>
                Min {PASSWORD_MIN} chars, max {PASSWORD_MAX} chars. Must include
                uppercase, lowercase, number, and special character.
            </p>
        </div>
    );
}

function PasswordInput({
    id,
    name,
    autoComplete,
    invalid,
    onInput,
}: {
    id: string;
    name: string;
    autoComplete: 'new-password';
    invalid?: boolean;
    onInput: () => void;
}) {
    const [visible, setVisible] = useState(false);

    return (
        <div className="relative">
            <Lock
                aria-hidden
                className="pointer-events-none absolute top-1/2 left-3.5 size-4 -translate-y-1/2 text-muted-foreground/70"
            />
            <Input
                id={id}
                name={name}
                type={visible ? 'text' : 'password'}
                autoComplete={autoComplete}
                maxLength={PASSWORD_MAX}
                placeholder="••••••••"
                aria-invalid={invalid || undefined}
                onInput={onInput}
                className="h-12 border-border/80 bg-muted/40 pr-11 pl-10 text-base shadow-none transition-colors focus-visible:bg-background"
            />
            <button
                type="button"
                aria-label={visible ? 'Hide password' : 'Show password'}
                aria-pressed={visible}
                onClick={() => setVisible((show) => !show)}
                className="absolute top-1/2 right-3.5 -translate-y-1/2 cursor-pointer text-muted-foreground/70 transition-colors hover:text-foreground"
            >
                {visible ? (
                    <EyeOff aria-hidden className="size-4" />
                ) : (
                    <Eye aria-hidden className="size-4" />
                )}
            </button>
        </div>
    );
}

export default function ForcePasswordChange() {
    const formRef = useRef<FormComponentRef | null>(null);

    return (
        <>
            <Head title="Update password" />

            <main className="login-form-shell relative flex min-h-svh flex-col justify-center px-6 py-12 sm:px-10 lg:px-16">
                <div
                    className={cn(
                        'mx-auto w-full max-w-[520px]',
                        'motion-safe:animate-in motion-safe:fade-in motion-safe:slide-in-from-bottom-2 motion-safe:duration-500',
                    )}
                >
                    <div className="rounded-2xl border border-border/70 bg-card shadow-[0_1px_2px_oklch(0_0_0/4%),0_12px_40px_-12px_oklch(0_0_0/12%)]">
                        <div className="space-y-10 p-10 sm:p-12">
                            <header className="space-y-2">
                                <h1 className="font-heading text-3xl font-semibold tracking-tight text-foreground">
                                    Update password
                                </h1>
                                <p className="text-base leading-relaxed text-muted-foreground">
                                    For security, you must set a new password before continuing.
                                </p>
                            </header>

                            <Form
                                ref={formRef}
                                action={route('password.force.update')}
                                method="post"
                                resetOnSuccess={['password', 'password_confirmation']}
                                noValidate
                                onBefore={() => {
                                    const errors = passwordChangeClientErrors(
                                        formRef.current?.getData() ?? {},
                                    );

                                    if (Object.keys(errors).length > 0) {
                                        formRef.current?.setError(errors);

                                        return false;
                                    }

                                    formRef.current?.clearErrors();
                                }}
                            >
                                {({ errors, processing, clearErrors }) => (
                                    <FieldGroup className="gap-6">
                                        <Field data-invalid={!!errors.password || undefined}>
                                            <FieldLabel
                                                htmlFor="password"
                                                className="text-xs font-medium uppercase tracking-wider text-muted-foreground"
                                            >
                                                New password <RequiredMark />
                                            </FieldLabel>
                                            <PasswordInput
                                                id="password"
                                                name="password"
                                                autoComplete="new-password"
                                                invalid={!!errors.password}
                                                onInput={() => clearErrors('password')}
                                            />
                                            <FieldError>{errors.password}</FieldError>
                                        </Field>

                                        <Field data-invalid={!!errors.password_confirmation || undefined}>
                                            <FieldLabel
                                                htmlFor="password_confirmation"
                                                className="text-xs font-medium uppercase tracking-wider text-muted-foreground"
                                            >
                                                Confirm password <RequiredMark />
                                            </FieldLabel>
                                            <PasswordInput
                                                id="password_confirmation"
                                                name="password_confirmation"
                                                autoComplete="new-password"
                                                invalid={!!errors.password_confirmation}
                                                onInput={() => clearErrors('password_confirmation')}
                                            />
                                            <FieldError>{errors.password_confirmation}</FieldError>
                                        </Field>

                                        <PasswordRequirementsCallout />

                                        <Separator className="bg-border/60" />

                                        <Button
                                            type="submit"
                                            size="lg"
                                            disabled={processing}
                                            className="h-12 w-full cursor-pointer gap-2 text-base font-semibold shadow-[0_1px_2px_oklch(0_0_0/8%)] transition-all duration-200 hover:brightness-110 active:translate-y-px disabled:opacity-70"
                                        >
                                            {processing && (
                                                <Loader2
                                                    aria-hidden
                                                    className="size-4 animate-spin"
                                                />
                                            )}
                                            {processing ? 'Updating…' : 'Update password'}
                                        </Button>

                                        <Button
                                            type="button"
                                            variant="ghost"
                                            className="h-11 w-full cursor-pointer text-muted-foreground"
                                            onClick={() => router.post(route('logout'))}
                                        >
                                            Sign out
                                        </Button>
                                    </FieldGroup>
                                )}
                            </Form>
                        </div>
                    </div>
                </div>
            </main>
        </>
    );
}
