import React, { useEffect, useMemo, useState } from "react";

import {
  AppBar,
  Avatar,
  Badge,
  Box,
  Breadcrumbs,
  Button,
  ButtonGroup,
  Chip,
  Divider,
  Drawer,
  IconButton,
  List,
  ListItemButton,
  ListItemIcon,
  ListItemText,
  Menu,
  MenuItem,
  Toolbar,
  Tooltip,
  Typography,
} from "@mui/material";
import useMediaQuery from "@mui/material/useMediaQuery";

import MenuIcon from "@mui/icons-material/Menu";
import MenuOpenIcon from "@mui/icons-material/MenuOpen";
import NotificationsNoneIcon from "@mui/icons-material/NotificationsNone";
import SettingsOutlinedIcon from "@mui/icons-material/SettingsOutlined";

import JobbjaktMark from "../assets/JobbjaktMark";
import { useI18n } from "../i18n/I18nProvider";

export type NavItem = {
  to: string;
  label: string;
  icon: React.ReactNode;
  hidden?: boolean;
  section?: string;
  badgeCount?: number;
};

function initialsFrom(s?: string) {
  const v = (s ?? "").trim();
  if (!v) return "?";
  const parts = v.split(/[\s@._-]+/).filter(Boolean);
  if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
  return (parts[0][0] + parts[1][0]).toUpperCase();
}

const DESKTOP_SIDEBAR_KEY = "appShellDesktopSidebarCollapsed";

// Which single nav item owns the current path. A child route must not light up its parent:
// /career/builder/5 belongs to "CV Builder" (/career/builder), not "Career Workspace" (/career),
// even though the old `pathname.startsWith(to + "/")` test matched both. Explicit ownership =
// the LONGEST `to` that the path is at or under wins; everything else is inactive. Exported so the
// rule is unit-testable without rendering the shell.
export function activeNavTo(pathname: string, tos: string[]): string | null {
  let best: string | null = null;
  for (const to of tos) {
    const owns = pathname === to || pathname.startsWith(to + "/");
    if (owns && (best === null || to.length > best.length)) best = to;
  }
  return best;
}

// The nav rail stays a fixed dark navy regardless of the app's light/dark theme toggle --
// a deliberate signature element, not derived from theme tokens.
const SIDEBAR_BG = "#0f172a";
const SIDEBAR_BORDER = "rgba(255,255,255,0.08)";
const SIDEBAR_TEXT_MUTED = "#94a3b8";
const SIDEBAR_TEXT = "#e2e8f0";
const SIDEBAR_SELECTED_BG = "rgba(99,102,241,0.18)";
const SIDEBAR_SELECTED_TEXT = "#ffffff";
const SIDEBAR_SELECTED_ICON = "#a5b4fc";

export default function AppShell({
  pageTitle,
  pageSubtitle,
  breadcrumbs,
  pathname,
  nav,
  navBottom,
  onNavigate,
  onToggleDrawer,
  drawerOpen,
  user,
  buildMetadata,
  notificationsCount,
  onOpenNotifications,
  onOpenSettings,
  onOpenProfile,
  onSignOut,
  rightActions,
  children,
}: {
  pageTitle: string;
  pageSubtitle?: string;
  breadcrumbs: string[];
  pathname: string;
  nav: NavItem[];
  navBottom: NavItem[];
  onNavigate: (to: string) => void;
  onToggleDrawer: (open: boolean) => void;
  drawerOpen: boolean;
  user?: { email?: string; userName?: string; displayName?: string; avatarImageDataUrl?: string; roleLabel?: string };
  buildMetadata?: { version: string; commitSha?: string };
  notificationsCount?: number;
  onOpenNotifications?: (anchorEl: HTMLElement) => void;
  onOpenSettings?: () => void;
  onOpenProfile?: () => void;
  onSignOut?: () => void;
  rightActions?: React.ReactNode;
  children: React.ReactNode;
}) {
  const { language, setLanguage, t } = useI18n();
  const isMobile = useMediaQuery("(max-width:767.95px)");
  const [desktopNavCollapsed, setDesktopNavCollapsed] = useState(() => {
    try {
      return window.localStorage.getItem(DESKTOP_SIDEBAR_KEY) === "1";
    } catch {
      return false;
    }
  });
  const drawerWidth = isMobile ? 254 : desktopNavCollapsed ? 84 : 254;

  useEffect(() => {
    try {
      window.localStorage.setItem(DESKTOP_SIDEBAR_KEY, desktopNavCollapsed ? "1" : "0");
    } catch {
      // ignore storage failures
    }
  }, [desktopNavCollapsed]);

  const grouped = useMemo(() => {
    const groupItems = (items: NavItem[]) => {
      const map = new Map<string, NavItem[]>();
      for (const it of items.filter((x) => !x.hidden)) {
        const key = it.section || "";
        map.set(key, [...(map.get(key) ?? []), it]);
      }
      return Array.from(map.entries());
    };

    return {
      top: groupItems(nav),
      bottom: groupItems(navBottom),
    };
  }, [nav, navBottom]);

  // Compute the one active destination across BOTH nav lists, so the most specific route wins.
  const activeTo = useMemo(
    () => activeNavTo(pathname, [...nav, ...navBottom].map((i) => i.to)),
    [pathname, nav, navBottom],
  );

  const renderNavList = (groups: Array<[string, NavItem[]]>) => (
    <Box sx={{ px: desktopNavCollapsed ? 0.75 : 1.25, pt: 1 }}>
      {groups.map(([section, rows]) => (
        <Box key={section || "_"} sx={{ mb: desktopNavCollapsed ? 1 : 1.25 }}>
          {section && !desktopNavCollapsed ? (
            <Typography variant="caption" sx={{ px: 1.25, color: SIDEBAR_TEXT_MUTED, fontWeight: 600, textTransform: "uppercase" }}>
              {section}
            </Typography>
          ) : null}
          <List sx={{ px: desktopNavCollapsed ? 0.25 : 0.75, pt: desktopNavCollapsed ? 0.25 : 0.75 }}>
            {rows.map((item) => {
              const selected = item.to === activeTo;
              return (
                <ListItemButton
                  key={item.to}
                  selected={selected}
                  onClick={() => onNavigate(item.to)}
                  title={desktopNavCollapsed ? item.label : undefined}
                  sx={{
                    borderRadius: 2,
                    mb: 0.5,
                    minHeight: 44,
                    px: desktopNavCollapsed ? 1 : 1.5,
                    justifyContent: desktopNavCollapsed ? "center" : "flex-start",
                    border: "1px solid transparent",
                    color: SIDEBAR_TEXT_MUTED,
                    "&:hover": { backgroundColor: "rgba(255,255,255,0.06)", color: SIDEBAR_TEXT },
                    "&.Mui-selected": {
                      backgroundColor: SIDEBAR_SELECTED_BG,
                      color: SIDEBAR_SELECTED_TEXT,
                    },
                    "&.Mui-selected:hover": {
                      backgroundColor: SIDEBAR_SELECTED_BG,
                    },
                  }}
                >
                  <ListItemIcon sx={{ minWidth: desktopNavCollapsed ? 0 : 36, justifyContent: "center", color: selected ? SIDEBAR_SELECTED_ICON : SIDEBAR_TEXT_MUTED }}>
                    {item.badgeCount && item.badgeCount > 0 ? (
                      <Badge color="error" badgeContent={item.badgeCount > 99 ? "99+" : item.badgeCount}>
                        {item.icon}
                      </Badge>
                    ) : item.icon}
                  </ListItemIcon>
                  {!desktopNavCollapsed ? <ListItemText primary={item.label} primaryTypographyProps={{ fontWeight: 600 }} /> : null}
                </ListItemButton>
              );
            })}
          </List>
        </Box>
      ))}
    </Box>
  );

  const drawerContent = (
    <Box sx={{ height: "100%", display: "flex", flexDirection: "column", backgroundColor: SIDEBAR_BG }}>
      <Box sx={{ px: desktopNavCollapsed ? 1.5 : 2.25, py: desktopNavCollapsed ? 2 : 2.5, display: "flex", justifyContent: desktopNavCollapsed ? "center" : "flex-start" }}>
        <Box sx={{ display: "flex", alignItems: "center", gap: 1, justifyContent: desktopNavCollapsed ? "center" : "flex-start" }}>
          <JobbjaktMark style={{ width: 30, height: 30, flexShrink: 0 }} />
          {!desktopNavCollapsed ? (
            <Box>
              <Typography variant="h6" sx={{ fontWeight: 700, color: SIDEBAR_SELECTED_TEXT }}>
                Jobbjakt
              </Typography>
              <Typography variant="caption" sx={{ color: SIDEBAR_TEXT_MUTED }}>
                {t("appTagline")}
              </Typography>
            </Box>
          ) : null}
        </Box>
      </Box>

      <Divider sx={{ borderColor: SIDEBAR_BORDER }} />

      {renderNavList(grouped.top)}

      <Box sx={{ flex: 1 }} />

      <Divider sx={{ borderColor: SIDEBAR_BORDER }} />

      {renderNavList(grouped.bottom)}
    </Box>
  );

  const nameForAvatar = user?.userName || user?.displayName || user?.email;
  const initials = initialsFrom(nameForAvatar);
  const buildVersion = buildMetadata?.version.trim();
  const buildCommit = buildMetadata?.commitSha?.trim();
  const buildBadge = buildVersion ? (
    <Tooltip title={buildCommit ? `Version ${buildVersion} • commit ${buildCommit}` : `Version ${buildVersion}`}>
      <Chip
        data-testid="admin-version-badge"
        aria-label={`Application version ${buildVersion}${buildCommit ? `, commit ${buildCommit}` : ""}`}
        label={`v${buildVersion}`}
        size="small"
        variant="outlined"
        sx={{
          maxWidth: 150,
          fontWeight: 700,
          fontVariantNumeric: "tabular-nums",
          bgcolor: "background.paper",
          "& .MuiChip-label": { overflow: "hidden", textOverflow: "ellipsis" },
        }}
      />
    </Tooltip>
  ) : null;

  const [userMenuAnchor, setUserMenuAnchor] = useState<null | HTMLElement>(null);
  const userMenuOpen = Boolean(userMenuAnchor);

  return (
    <Box sx={{ display: "flex", minHeight: "100vh" }}>
      <AppBar
        position="fixed"
        color="inherit"
        elevation={0}
        sx={(muiTheme: any) => ({
          borderBottom: `1px solid ${muiTheme.vars.palette.grey[300]}`,
          backgroundColor: muiTheme.vars.palette.background.default,
          backgroundImage: "none",
          zIndex: muiTheme.zIndex.drawer + 1,
        })}
      >
        <Toolbar
          sx={{
            gap: 1.25,
            px: { xs: 2, md: 3 },
            py: { xs: 1.25, md: 0 },
            minHeight: { xs: 68, md: 76 },
            alignItems: { xs: "stretch", md: "center" },
            flexWrap: { xs: "wrap", md: "nowrap" },
          }}
        >
          {isMobile ? (
            <>
              <Box sx={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 1, width: "100%", minWidth: 0 }}>
                <Box sx={{ display: "flex", alignItems: "center", gap: 1, minWidth: 0 }}>
                  <IconButton
                    edge="start"
                    size="small"
                    color="secondary"
                    aria-label={t("openNavigation")}
                    onClick={() => onToggleDrawer(true)}
                    sx={{ border: "1px solid", borderColor: "divider", borderRadius: 2.5, width: 42, height: 42 }}
                  >
                    <MenuIcon fontSize="small" />
                  </IconButton>

                  <Box sx={{ display: "flex", alignItems: "center", gap: 0.9, minWidth: 0, pl: 0.25 }}>
                    <JobbjaktMark style={{ width: 18, height: 18, flex: "0 0 auto" }} />
                    <Typography variant="subtitle1" sx={{ fontWeight: 800, letterSpacing: -0.2 }} noWrap>
                      Jobbjakt
                    </Typography>
                  </Box>
                  {buildBadge}
                </Box>

                <StackLanguageToggle language={language} setLanguage={setLanguage} />
                {user ? (
                  <IconButton
                    size="small"
                    aria-label={t("user")}
                    onClick={(e) => setUserMenuAnchor(e.currentTarget)}
                    sx={{ borderRadius: 2.5, border: "1px solid", borderColor: "divider", width: 42, height: 42, flex: "0 0 auto" }}
                  >
                    <Avatar src={user.avatarImageDataUrl || undefined} sx={{ width: 28, height: 28, fontWeight: 900 }}>{initials}</Avatar>
                  </IconButton>
                ) : <Box sx={{ width: 42, height: 42 }} />}
              </Box>

              <Box sx={{ display: "flex", alignItems: "center", gap: 1, width: "100%" }}>
                <Box sx={{ display: "flex", alignItems: "center", gap: 1, flex: "0 0 auto" }}>
                  <IconButton
                    color="secondary"
                    size="small"
                    title={t("notifications")}
                    aria-label={t("notifications")}
                    onClick={(event) => onOpenNotifications?.(event.currentTarget)}
                    sx={{ border: "1px solid", borderColor: "divider", borderRadius: 2.5, width: 42, height: 42 }}
                  >
                    <Badge color="primary" badgeContent={notificationsCount || 0} max={99}>
                      <NotificationsNoneIcon fontSize="small" />
                    </Badge>
                  </IconButton>
                  <IconButton
                    color="secondary"
                    size="small"
                    title={t("settings")}
                    aria-label={t("settings")}
                    onClick={onOpenSettings}
                    sx={{ border: "1px solid", borderColor: "divider", borderRadius: 2.5, width: 42, height: 42 }}
                  >
                    <SettingsOutlinedIcon fontSize="small" />
                  </IconButton>
                </Box>

                <Box
                  sx={{
                    display: "flex",
                    alignItems: "center",
                    gap: 1,
                    flex: 1,
                    minWidth: 0,
                    '& > *': { minWidth: 0 },
                  }}
                >
                  {rightActions}
                </Box>
              </Box>
            </>
          ) : (
            <>
              <Box sx={{ display: "flex", alignItems: "center", gap: 1, minWidth: 0, flex: 1 }}>
                <IconButton
                  size="small"
                  color="secondary"
                  onClick={() => setDesktopNavCollapsed((value) => !value)}
                  title={desktopNavCollapsed ? t("expandSidebar") : t("collapseSidebar")}
                  aria-label={desktopNavCollapsed ? t("expandSidebar") : t("collapseSidebar")}
                  sx={{ border: "1px solid", borderColor: "divider", borderRadius: 2, width: 40, height: 40 }}
                >
                  <MenuOpenIcon fontSize="small" sx={{ transform: desktopNavCollapsed ? "scaleX(-1)" : "none" }} />
                </IconButton>
              </Box>

              <Box
                sx={{
                  display: "flex",
                  alignItems: "center",
                  justifyContent: "flex-end",
                  gap: 1,
                  flexWrap: "wrap",
                  width: { xs: "100%", md: "auto" },
                  flex: { xs: "1 1 100%", md: "0 1 auto" },
                }}
              >
                {buildBadge}
                <StackLanguageToggle language={language} setLanguage={setLanguage} />
                <IconButton
                  color="secondary"
                  size="small"
                  title={t("notifications")}
                  aria-label={t("notifications")}
                  onClick={(event) => onOpenNotifications?.(event.currentTarget)}
                  sx={{ border: "1px solid", borderColor: "divider", borderRadius: 2 }}
                >
                  <Badge color="primary" badgeContent={notificationsCount || 0} max={99}>
                    <NotificationsNoneIcon fontSize="small" />
                  </Badge>
                </IconButton>
                <IconButton
                  color="secondary"
                  size="small"
                  title={t("settings")}
                  aria-label={t("settings")}
                  onClick={onOpenSettings}
                  sx={{ border: "1px solid", borderColor: "divider", borderRadius: 2 }}
                >
                  <SettingsOutlinedIcon fontSize="small" />
                </IconButton>

                <Box sx={{ display: "flex", alignItems: "center", gap: 1, flexWrap: "wrap", flex: { xs: "1 1 auto", md: "0 1 auto" }, justifyContent: "flex-end" }}>
                  {rightActions}
                </Box>

                {user ? (
                  <Box sx={{ display: "flex", alignItems: "center", gap: 1.25, pl: { xs: 0, sm: 1 } }}>
                    <IconButton
                      size="small"
                      aria-label={t("user")}
                      onClick={(e) => setUserMenuAnchor(e.currentTarget)}
                      sx={{ borderRadius: 2, border: "1px solid", borderColor: "divider" }}
                    >
                      <Avatar src={user.avatarImageDataUrl || undefined} sx={{ width: 30, height: 30, fontWeight: 900 }}>{initials}</Avatar>
                    </IconButton>
                    <Box sx={{ display: { xs: "none", sm: "block" }, minWidth: 0 }}>
                      <Typography sx={{ fontWeight: 600, lineHeight: 1.2 }} noWrap>
                        {user.userName || user.displayName || user.email || t("user")}
                      </Typography>
                      <Typography variant="caption" sx={{ color: "text.secondary" }}>
                        {user.roleLabel || ""}
                      </Typography>
                    </Box>
                  </Box>
                ) : null}
              </Box>
            </>
          )}
          <Menu
            anchorEl={userMenuAnchor}
            open={userMenuOpen}
            onClose={() => setUserMenuAnchor(null)}
            anchorOrigin={{ vertical: "bottom", horizontal: "right" }}
            transformOrigin={{ vertical: "top", horizontal: "right" }}
          >
            <MenuItem
              onClick={() => {
                setUserMenuAnchor(null);
                onOpenProfile?.();
              }}
            >
              {t("profileMenu")}
            </MenuItem>
            <MenuItem
              onClick={() => {
                setUserMenuAnchor(null);
                onOpenSettings?.();
              }}
            >
              {t("settingsMenu")}
            </MenuItem>
            <Divider />
            <MenuItem
              onClick={() => {
                setUserMenuAnchor(null);
                onSignOut?.();
              }}
            >
              {t("signOut")}
            </MenuItem>
          </Menu>
        </Toolbar>
      </AppBar>

      <Drawer
        variant="permanent"
        sx={{
          display: { xs: "none", md: "block" },
          width: drawerWidth,
          flexShrink: 0,
          [`& .MuiDrawer-paper`]: {
            width: drawerWidth,
            boxSizing: "border-box",
            borderRight: `1px solid ${SIDEBAR_BORDER}`,
            backgroundColor: SIDEBAR_BG,
            backgroundImage: "none",
            boxShadow: "none",
          },
        }}
        open
      >
        <Toolbar sx={{ minHeight: { xs: 68, md: 76 } }} />
        {drawerContent}
      </Drawer>

      <Drawer
        variant="temporary"
        open={drawerOpen}
        onClose={() => onToggleDrawer(false)}
        ModalProps={{ keepMounted: true }}
        sx={{
          display: { xs: "block", md: "none" },
          [`& .MuiDrawer-paper`]: {
            width: drawerWidth,
            borderRight: `1px solid ${SIDEBAR_BORDER}`,
            backgroundColor: SIDEBAR_BG,
            backgroundImage: "none",
          },
        }}
      >
        {drawerContent}
      </Drawer>

      <Box
        component="main"
        sx={{
          flex: 1,
          p: "var(--app-page-gutter)",
          bgcolor: "background.default",
          minHeight: "100vh",
          minWidth: 0,
        }}
      >
        <Box sx={{ mx: "auto", maxWidth: 1320, width: "100%", minWidth: 0 }}>
          <Toolbar sx={{ minHeight: { xs: isMobile ? 124 : 68, md: 76 } }} />
          <Box sx={{ display: "flex", flexDirection: "column", gap: 0.75, mb: "var(--app-section-gap)", minWidth: 0 }}>
            <Box sx={{ minWidth: 0 }}>
              <Breadcrumbs sx={{ color: "text.secondary", mb: 0.5, '& .MuiBreadcrumbs-ol': { flexWrap: 'wrap' } }}>
                {breadcrumbs.map((c) => (
                  <Typography key={c} variant="caption" sx={{ color: "text.secondary", fontWeight: 600, overflowWrap: "anywhere" }}>
                    {c}
                  </Typography>
                ))}
              </Breadcrumbs>
              <Typography variant="h5" sx={{ fontWeight: 600, overflowWrap: "anywhere" }}>
                {pageTitle}
              </Typography>
              {pageSubtitle ? (
                <Typography variant="body2" sx={{ color: "text.secondary", mt: 0.25, overflowWrap: "anywhere" }}>
                  {pageSubtitle}
                </Typography>
              ) : null}
            </Box>
          </Box>

          {children}
        </Box>
      </Box>
    </Box>
  );
}

export function StackLanguageToggle({ language, setLanguage }: { language: "en" | "nb"; setLanguage: (language: "en" | "nb") => void }) {
  const { t } = useI18n();
  return (
    <ButtonGroup size="small" variant="outlined" aria-label={t("applicationLanguage")} sx={{ flex: "0 0 auto", "& .MuiButton-root": { minWidth: 36, px: 0.6, fontWeight: 800 } }}>
      <Button aria-label="English" aria-pressed={language === "en"} variant={language === "en" ? "contained" : "outlined"} onClick={() => setLanguage("en")}>EN</Button>
      <Button aria-label="Norsk" aria-pressed={language === "nb"} variant={language === "nb" ? "contained" : "outlined"} onClick={() => setLanguage("nb")}>NO</Button>
    </ButtonGroup>
  );
}
