import { useState } from "react";
import { useTranslation } from "react-i18next";
import { NavLink, Outlet, useLocation, useNavigate } from "react-router-dom";
import { useAuth } from "../features/auth/AuthContext";
import "./AppLayout.scss";
import {
  AccountIcon,
  ChevronLeftIcon,
  CreditsIcon,
  DietPreferencesIcon,
  HouseholdIcon,
  PlanningIcon,
  RecipesIcon,
  SettingsIcon,
  ShoppingListIcon,
  UserPreferencesIcon,
} from "./nav-icons";

/** `localStorage` key persisting {@link AppLayout}'s collapsed/expanded sidebar state across reloads. */
const SIDEBAR_COLLAPSED_KEY = "batchcooking:sidebarCollapsed";

/**
 * One entry in the sidebar's main nav. `key` maps to `layout.nav.<key>` in
 * `locales/fr/translation.json` — adding a section is one array entry plus
 * one locale key, no other file to touch.
 */
const NAV_ITEMS = [
  { to: "/", key: "planning", Icon: PlanningIcon },
  { to: "/recettes", key: "recipes", Icon: RecipesIcon },
  { to: "/liste-de-courses", key: "shoppingList", Icon: ShoppingListIcon },
] as const;

/**
 * One entry in the "Paramètres" nav, revealed by {@link SettingsMenu}. `key`
 * maps to `layout.settings.nav.<key>`.
 */
const SETTINGS_ITEMS = [
  { to: "/parametres/compte", key: "account", Icon: AccountIcon },
  { to: "/parametres/preferences", key: "preferences", Icon: DietPreferencesIcon },
  { to: "/parametres/foyer", key: "household", Icon: HouseholdIcon },
  { to: "/parametres/preferences-utilisateur", key: "userPreferences", Icon: UserPreferencesIcon },
  { to: "/parametres/credits", key: "credits", Icon: CreditsIcon },
] as const;

/**
 * Shell for every authenticated page: a sidebar (brand, section nav, a
 * collapsible "Paramètres" nav, and the account menu at the bottom) plus a
 * main content area rendering the matched child route via `<Outlet />`.
 *
 * The sidebar itself can be collapsed to an icon-only rail (see
 * `isCollapsed`/`SIDEBAR_COLLAPSED_KEY`) — every nav item keeps its icon
 * and gains a `title` tooltip, its label just hides via CSS
 * (`.app-sidebar.collapsed .label`, see AppLayout.scss), so collapsing is a
 * single class toggle on the `<aside>`, not something each child component
 * needs to know about.
 *
 * Mounted once as the parent element of the whole authenticated route
 * group, itself wrapped in {@link RequireAuth} (see `App.tsx`) — `user` is
 * therefore guaranteed non-null by the time this renders.
 */
export function AppLayout() {
  const { t } = useTranslation();
  const [isCollapsed, setIsCollapsed] = useState(
    () => localStorage.getItem(SIDEBAR_COLLAPSED_KEY) === "true",
  );

  function toggleCollapsed() {
    setIsCollapsed((collapsed) => {
      const next = !collapsed;
      localStorage.setItem(SIDEBAR_COLLAPSED_KEY, String(next));
      return next;
    });
  }

  return (
    <div className="app-layout">
      <aside className={isCollapsed ? "app-sidebar collapsed" : "app-sidebar"}>
        <div className="app-sidebar__top">
          <div className="app-sidebar__brand">
            {/* Collapsed: a short monogram instead of the full wordmark — clearer than an arbitrary icon standing in for the brand itself. */}
            <span className="app-sidebar__brand-full">batchCooking</span>
            <span className="app-sidebar__brand-mark">bC</span>
          </div>
          <button
            type="button"
            className="app-sidebar__collapse-toggle"
            onClick={toggleCollapsed}
            title={t(isCollapsed ? "layout.sidebar.expand" : "layout.sidebar.collapse")}
          >
            <ChevronLeftIcon aria-hidden="true" />
          </button>
        </div>

        <nav className="app-sidebar__nav">
          {NAV_ITEMS.map(({ to, key, Icon }) => (
            <NavLink
              key={to}
              to={to}
              // Only the home ("/") entry needs exact matching — every
              // other path is a leaf with nothing nested under it (yet),
              // so NavLink's default prefix matching already behaves the
              // same way `end` would.
              end={to === "/"}
              className={({ isActive }) => (isActive ? "active" : undefined)}
              title={t(`layout.nav.${key}`)}
            >
              <Icon aria-hidden="true" />
              <span className="label">{t(`layout.nav.${key}`)}</span>
            </NavLink>
          ))}
        </nav>

        <SettingsMenu />
        <AccountMenu />
        <p className="app-sidebar__version" aria-hidden="true">
          v{__APP_VERSION__}
        </p>
      </aside>

      <main className="app-content">
        <Outlet />
      </main>
    </div>
  );
}

/**
 * Collapsible "Paramètres" section revealing the settings pages (Compte /
 * Préférences alimentaires / Foyer / Préférences utilisateur — see
 * `pages/settings/`). Starts open whenever the current route is already
 * under `/parametres`, so following a link there (e.g. from
 * {@link AccountMenu}) doesn't land on a collapsed menu; otherwise starts
 * closed to keep the sidebar's main focus on the primary nav above it.
 *
 * Independent of the whole-sidebar collapse toggle in {@link AppLayout} —
 * this menu's own open/closed state persists across that (a rail-collapsed
 * sidebar can still have "Paramètres" expanded, just showing icons).
 */
function SettingsMenu() {
  const { t } = useTranslation();
  const location = useLocation();
  const [isOpen, setIsOpen] = useState(location.pathname.startsWith("/parametres"));

  return (
    <div className="app-sidebar__settings">
      <button
        type="button"
        className="app-sidebar__settings-toggle"
        aria-expanded={isOpen}
        onClick={() => setIsOpen((open) => !open)}
        title={t("layout.settings.toggle")}
      >
        <span className="app-sidebar__settings-toggle-left">
          <SettingsIcon aria-hidden="true" />
          <span className="label">{t("layout.settings.toggle")}</span>
        </span>
        <span className="chevron" aria-hidden="true">
          {isOpen ? "▾" : "▸"}
        </span>
      </button>

      {isOpen && (
        <nav className="app-sidebar__nav app-sidebar__settings-nav">
          {SETTINGS_ITEMS.map(({ to, key, Icon }) => (
            <NavLink
              key={to}
              to={to}
              className={({ isActive }) => (isActive ? "active" : undefined)}
              title={t(`layout.settings.nav.${key}`)}
            >
              <Icon aria-hidden="true" />
              <span className="label">{t(`layout.settings.nav.${key}`)}</span>
            </NavLink>
          ))}
        </nav>
      )}
    </div>
  );
}

/**
 * Account menu — a small dropdown opened from the signed-in user's name at
 * the very bottom of the sidebar, replacing what used to be a plain
 * greeting + logout button. Offers a shortcut straight to `/parametres/compte`
 * plus the logout action; closes itself after either action so it never
 * lingers open across a navigation.
 */
function AccountMenu() {
  const { user, logout } = useAuth();
  const navigate = useNavigate();
  const { t } = useTranslation();
  const [isOpen, setIsOpen] = useState(false);

  /** Ends the session and returns to the login page. */
  async function handleLogout() {
    setIsOpen(false);
    try {
      await logout();
      void navigate("/login");
    } catch (err) {
      // Rethrown as-is — `AuthContext`'s `logout` already documents itself
      // as throwing `ApiError` on failure; this handler just isn't allowed
      // a bare `await` per the repo's async/try-catch convention.
      throw err;
    }
  }

  const initial = user?.firstName?.charAt(0).toUpperCase() ?? "";

  return (
    <div className="app-sidebar__footer">
      <button
        type="button"
        className="app-sidebar__account-toggle"
        aria-expanded={isOpen}
        onClick={() => setIsOpen((open) => !open)}
        title={t("layout.greeting", { firstName: user?.firstName })}
      >
        <span className="app-sidebar__avatar" aria-hidden="true">
          {initial}
        </span>
        <span className="label">{t("layout.greeting", { firstName: user?.firstName })}</span>
      </button>

      {isOpen && (
        <div className="app-sidebar__account-menu">
          <NavLink to="/parametres/compte" onClick={() => setIsOpen(false)}>
            {t("layout.accountMenu.myAccount")}
          </NavLink>
          <button type="button" onClick={handleLogout}>
            {t("layout.logout")}
          </button>
        </div>
      )}
    </div>
  );
}
