"use client";

import {
  useEffect,
  useRef,
  useState,
  type KeyboardEvent as ReactKeyboardEvent,
} from "react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { IconCheck, IconLanguage } from "@tabler/icons-react";

import { localeNames, locales, type Locale } from "@/lib/i18n";
import { cn } from "@/lib/utils";

type LanguageSwitcherProps = {
  lang: string;
  align?: "start" | "end";
  className?: string;
};

const buildLocaleHref = (pathname: string, target: Locale) => {
  const segments = pathname.split("/");
  // segments[0] is "" (leading slash). segments[1] is the current locale (if any).
  if (
    segments.length > 1 &&
    (locales as readonly string[]).includes(segments[1])
  ) {
    segments[1] = target;
    return segments.join("/") || "/";
  }
  // No locale segment present — prefix it, preserving the rest of the path.
  const rest = pathname === "/" ? "" : pathname;
  return `/${target}${rest}`;
};

export const LanguageSwitcher = ({
  lang,
  align = "start",
  className,
}: LanguageSwitcherProps) => {
  const pathname = usePathname() ?? "/";
  const [open, setOpen] = useState(false);
  const wrapperRef = useRef<HTMLDivElement>(null);
  const menuRef = useRef<HTMLDivElement>(null);
  const closeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);

  const cancelClose = () => {
    if (closeTimer.current) {
      clearTimeout(closeTimer.current);
      closeTimer.current = null;
    }
  };
  const openMenu = () => {
    cancelClose();
    setOpen(true);
  };
  // Delay close so moving the pointer across the small gap between the button
  // and the menu doesn't dismiss it before a selection (hover intent).
  const scheduleClose = () => {
    cancelClose();
    closeTimer.current = setTimeout(() => setOpen(false), 220);
  };
  useEffect(() => () => cancelClose(), []);

  // Close on outside click.
  useEffect(() => {
    if (!open) return;
    const handlePointer = (e: MouseEvent) => {
      if (
        wrapperRef.current &&
        !wrapperRef.current.contains(e.target as Node)
      ) {
        setOpen(false);
      }
    };
    document.addEventListener("mousedown", handlePointer);
    return () => document.removeEventListener("mousedown", handlePointer);
  }, [open]);

  // Close on Escape.
  useEffect(() => {
    if (!open) return;
    const handleKey = (e: KeyboardEvent) => {
      if (e.key === "Escape") setOpen(false);
    };
    document.addEventListener("keydown", handleKey);
    return () => document.removeEventListener("keydown", handleKey);
  }, [open]);

  // Roving focus among menu items (WAI-ARIA APG menu button pattern).
  const focusItemAt = (index: number) => {
    const items =
      menuRef.current?.querySelectorAll<HTMLElement>('[role="menuitem"]');
    if (!items || items.length === 0) return;
    const i = ((index % items.length) + items.length) % items.length;
    items[i]?.focus();
  };

  const handleMenuKeyDown = (e: ReactKeyboardEvent<HTMLDivElement>) => {
    const items = Array.from(
      menuRef.current?.querySelectorAll<HTMLElement>('[role="menuitem"]') ?? [],
    );
    if (items.length === 0) return;
    const currentIndex = items.indexOf(document.activeElement as HTMLElement);
    switch (e.key) {
      case "ArrowDown":
        e.preventDefault();
        focusItemAt(currentIndex + 1);
        break;
      case "ArrowUp":
        e.preventDefault();
        focusItemAt(currentIndex - 1);
        break;
      case "Home":
        e.preventDefault();
        focusItemAt(0);
        break;
      case "End":
        e.preventDefault();
        focusItemAt(items.length - 1);
        break;
    }
  };

  // ArrowDown on the trigger opens the menu and moves focus to the first item.
  const handleButtonKeyDown = (e: ReactKeyboardEvent<HTMLButtonElement>) => {
    if (e.key === "ArrowDown") {
      e.preventDefault();
      setOpen(true);
      requestAnimationFrame(() => focusItemAt(0));
    }
  };

  const changeLanguageLabel =
    lang === "fr"
      ? `Changer de langue (actuelle : ${lang.toUpperCase()})`
      : `Change language (current ${lang.toUpperCase()})`;

  return (
    <div
      ref={wrapperRef}
      className={cn("relative", className)}
      onMouseEnter={openMenu}
      onMouseLeave={scheduleClose}
      onFocus={openMenu}
      onBlur={(e) => {
        if (!e.currentTarget.contains(e.relatedTarget as Node)) setOpen(false);
      }}
    >
      <button
        type="button"
        aria-haspopup="menu"
        aria-expanded={open}
        aria-label={changeLanguageLabel}
        onClick={() => setOpen((v) => !v)}
        onKeyDown={handleButtonKeyDown}
        className="flex items-center gap-1 text-sm font-medium text-neutral-600 transition duration-200 hover:text-black dark:text-neutral-400 dark:hover:text-white"
      >
        <IconLanguage className="size-4" aria-hidden="true" />
        {lang.toUpperCase()}
      </button>

      {open && (
        <div
          ref={menuRef}
          role="menu"
          onKeyDown={handleMenuKeyDown}
          className={cn(
            "bg-background absolute top-full z-50 mt-2 min-w-36 rounded-md border border-neutral-200 p-1 shadow-md dark:border-neutral-800",
            align === "end" ? "right-0" : "left-0",
          )}
        >
          {locales.map((locale) => {
            const active = locale === lang;
            const label = localeNames[locale];
            const content = (
              <>
                <span className="flex-1">{label}</span>
                {active && <IconCheck className="size-4" aria-hidden="true" />}
              </>
            );
            const baseClass =
              "flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm w-full transition duration-200";
            if (active) {
              return (
                <div
                  key={locale}
                  role="menuitem"
                  tabIndex={-1}
                  aria-current="true"
                  className={cn(
                    baseClass,
                    "bg-neutral-100 font-medium text-black dark:bg-neutral-800 dark:text-white",
                  )}
                >
                  {content}
                </div>
              );
            }
            return (
              <Link
                key={locale}
                href={buildLocaleHref(pathname, locale)}
                prefetch={false}
                role="menuitem"
                tabIndex={-1}
                onClick={() => setOpen(false)}
                className={cn(
                  baseClass,
                  "text-neutral-600 hover:bg-neutral-100 hover:text-black dark:text-neutral-400 dark:hover:bg-neutral-800 dark:hover:text-white",
                )}
              >
                {content}
              </Link>
            );
          })}
        </div>
      )}
    </div>
  );
};
