"use client";

import Link from "next/link";
import {
  useCallback,
  useId,
  useState,
  type ComponentProps,
  type FormEventHandler,
  type ReactNode,
} from "react";
import { Eye, EyeOff, Lock, Mail, User as UserIcon, X } from "lucide-react";

import { Button } from "@/components/ui/button";
import { Alert, Input } from "@/components/ui/form";
import { Modal } from "@/components/ui/modal";
import { useAuthSubmit, type AuthMode } from "@/components/auth/use-auth-submit";
import { cn } from "@/lib/utils";

/**
 * Header authentication modal.
 *
 * A single dialog owns both modes: the tab strip swaps the field set in place,
 * so moving between Login and Sign up never unmounts the dialog or loses the
 * backdrop, and switching tabs clears the previous attempt's errors rather than
 * stranding them next to fields that are no longer there. `/login` and
 * `/register` remain as standalone routes for deep links — this is an additional
 * entry point, not a replacement, and the requests it sends are identical.
 *
 * The dialog is the shared `Modal` primitive, which already provides the portal
 * above the `z-[550]` header, the blurred backdrop, the focus trap, Escape and
 * click-outside dismissal, and the body scroll lock.
 */

const TABS: { id: AuthMode; label: string }[] = [
  { id: "login", label: "Login" },
  { id: "register", label: "Sign up" },
];

/**
 * The `?next=` target, if the current URL carries a safe one.
 *
 * Only same-origin, non-protocol-relative paths are honoured, so a crafted link
 * cannot bounce a freshly authenticated visitor off-site. Mirrors the check in
 * `auth-form.tsx`.
 */
function readNextPath(): string | null {
  const raw = new URLSearchParams(window.location.search).get("next");
  return raw && raw.startsWith("/") && !raw.startsWith("//") ? raw : null;
}

export function AuthModal({ open, onClose }: { open: boolean; onClose: () => void }) {
  const uid = useId();
  const [tab, setTab] = useState<AuthMode>("login");
  const [showPassword, setShowPassword] = useState(false);

  /*
    `null` keeps the visitor where they are — dismissing the dialog is the whole
    interaction, unlike `/login`, which is a page that has to navigate. The
    `?next=` target is read off the live URL at submit time, deliberately without
    `useSearchParams()`: this component mounts inside the root layout, and a
    `useSearchParams()` there would opt every prerendered route into client
    rendering to support a parameter only the deep-linked pages carry.
  */
  const { pending, formError, fieldErrors, reset, onSubmit } = useAuthSubmit({
    mode: tab,
    nextPath: readNextPath,
  });

  const selectTab = useCallback(
    (next: AuthMode) => {
      setTab(next);
      setShowPassword(false);
      reset();
    },
    [reset],
  );

  /* On success the session is already refreshed — the dialog just steps aside. */
  const handleSubmit = useCallback<FormEventHandler<HTMLFormElement>>(
    async (event) => {
      if (await onSubmit(event)) onClose();
    },
    [onClose, onSubmit],
  );

  return (
    <Modal
      open={open}
      onClose={onClose}
      ariaLabel="Sign in to FlixTV"
      size="sm"
      bodyClassName="max-h-[85vh] overflow-y-auto p-0"
    >
      <div className="px-5 pb-5 pt-4 sm:px-6 sm:pb-6">
        <div className="flex items-start gap-3">
          <div role="tablist" aria-label="Login or sign up" className="grid flex-1 grid-cols-2 gap-6">
            {TABS.map(({ id, label }) => {
              const active = tab === id;

              return (
                <button
                  key={id}
                  type="button"
                  role="tab"
                  id={`${uid}-tab-${id}`}
                  aria-selected={active}
                  aria-controls={`${uid}-panel`}
                  tabIndex={active ? 0 : -1}
                  onClick={() => selectTab(id)}
                  className={cn(
                    "-mb-px border-b-2 pb-2.5 text-sm font-semibold transition-colors duration-300",
                    active
                      ? "border-brand-500 text-ink"
                      : "border-transparent text-ink-muted hover:text-ink-soft",
                  )}
                >
                  {label}
                </button>
              );
            })}
          </div>

          <button
            type="button"
            onClick={onClose}
            aria-label="Close"
            className="-mt-1.5 grid size-8 shrink-0 place-items-center rounded-full text-ink-muted transition-colors hover:bg-white/8 hover:text-ink"
          >
            <X className="size-4" />
          </button>
        </div>

        <div role="tabpanel" id={`${uid}-panel`} aria-labelledby={`${uid}-tab-${tab}`} className="pt-4">
          <form onSubmit={handleSubmit} noValidate className="space-y-3">
            {formError ? <Alert tone="error">{formError}</Alert> : null}

            {tab === "register" ? (
              <IconField
                key="username"
                label="Username"
                name="username"
                icon={<UserIcon className="size-4" />}
                placeholder="Username"
                error={fieldErrors.username}
                inputProps={{
                  autoComplete: "username",
                  minLength: 3,
                  maxLength: 32,
                  required: true,
                  invalid: Boolean(fieldErrors.username),
                }}
              />
            ) : null}

            <IconField
              key="email"
              label="Email"
              name={tab === "login" ? "identifier" : "email"}
              icon={<Mail className="size-4" />}
              placeholder="Email"
              error={fieldErrors.email}
              inputProps={{
                /*
                  Plain text, not `type="email"`: the login route accepts an email
                  address *or* a username, and an email input would reject a
                  username before the request is ever made.
                */
                type: "text",
                inputMode: "email",
                autoComplete: tab === "login" ? "username" : "email",
                required: true,
                invalid: Boolean(fieldErrors.email),
              }}
            />

            <IconField
              key="password"
              label="Password"
              name="password"
              icon={<Lock className="size-4" />}
              placeholder="Password"
              error={fieldErrors.password}
              className="pr-12"
              inputProps={{
                type: showPassword ? "text" : "password",
                autoComplete: tab === "login" ? "current-password" : "new-password",
                required: true,
                invalid: Boolean(fieldErrors.password),
              }}
              trailing={
                <button
                  type="button"
                  onClick={() => setShowPassword((v) => !v)}
                  aria-label={showPassword ? "Hide password" : "Show password"}
                  aria-pressed={showPassword}
                  className="absolute inset-y-0 right-0 grid w-12 place-items-center text-ink-muted transition-colors hover:text-ink"
                >
                  {showPassword ? <EyeOff className="size-4" /> : <Eye className="size-4" />}
                </button>
              }
            />

            <div className="grid grid-cols-2 gap-2.5 pt-1">
              <Button type="submit" variant="brand" loading={pending} className="w-full">
                {tab === "login" ? "Login" : "Sign up"}
              </Button>
              <Button type="button" variant="secondary" onClick={onClose} className="w-full">
                Cancel
              </Button>
            </div>

            {/* `registerSchema` requires `acceptTerms: true`; the notice is below. */}
            {tab === "register" ? <input type="hidden" name="acceptTerms" value="on" /> : null}
          </form>

          {tab === "register" ? (
            <p className="mt-3.5 text-center text-[11px] leading-relaxed text-ink-faint">
              By signing up you agree to our{" "}
              <Link
                href="/terms"
                className="text-ink-muted underline underline-offset-2 transition-colors hover:text-ink-soft"
              >
                Terms
              </Link>{" "}
              and{" "}
              <Link
                href="/privacy"
                className="text-ink-muted underline underline-offset-2 transition-colors hover:text-ink-soft"
              >
                Privacy Policy
              </Link>
              .
            </p>
          ) : null}
        </div>
      </div>
    </Modal>
  );
}

/* ── helpers ──────────────────────────────────────────────────────────────── */

type IconFieldProps = {
  /** Visible to screen readers; the placeholder is the on-screen label. */
  label: string;
  name: string;
  icon: ReactNode;
  placeholder: string;
  error?: string;
  className?: string;
  trailing?: ReactNode;
  inputProps?: ComponentProps<typeof Input>;
};

/** Icon-led input with the icon inset to the left of the control. */
function IconField({
  label,
  name,
  icon,
  placeholder,
  error,
  className,
  trailing,
  inputProps,
}: IconFieldProps) {
  const id = useId();

  return (
    <div>
      <label htmlFor={id} className="sr-only">
        {label}
      </label>
      <div className="relative">
        <span
          aria-hidden
          className="pointer-events-none absolute inset-y-0 left-0 z-10 grid w-11 place-items-center text-ink-muted"
        >
          {icon}
        </span>
        <Input
          id={id}
          name={name}
          placeholder={placeholder}
          className={cn("pl-11", className)}
          {...inputProps}
        />
        {trailing}
      </div>
      {error ? (
        <p className="mt-1.5 text-[12px] font-medium text-brand-400" role="alert">
          {error}
        </p>
      ) : null}
    </div>
  );
}
