import type { ReactNode } from "react";
import type { AuthContext, DashboardKind } from "@/lib/authz/context";
import { availableDashboards, canAnywhere } from "@/lib/authz/context";
import { getActiveSiteId, listAccessibleSites } from "@/lib/data/sites";
import { db } from "@/lib/db";
import { siteContentTypes } from "@/lib/content/registry";
import { CORE_MODULE_BY_PATH, getSiteModuleKeys } from "@/lib/data/modules";
import { buttonClass } from "@/components/ui";
import Link from "next/link";
import { publicHref } from "@/lib/dashboard-urls";
import { signOutAction } from "./actions";
import { DASHBOARD_LABELS, NAV, type NavItem } from "./nav-config";
import { ShellFrame } from "./shell-frame";
import { SiteSwitcher } from "./site-switcher";

/** Order of a super admin's sidebar: platform setup first, the open website's tools after Websites & projects, then access and operations. */
const SUPER_ORDER = ["Dashboard", "Organizations", "Websites & projects", "Pages", "Panels", "Menus", "Libraries", "Reports", "Media Manager", "Approvals", "Settings", "Themes", "Feature modules", "Form templates", "Panel locations", "Integrations", "Security settings", "My profile", "Roles & permissions", "Users", "Maintenance", "System health", "Backup & recovery", "Audit logs", "Storage overview", "Platform configuration"];
const rank = (label: string) => { const i = SUPER_ORDER.indexOf(label); return i === -1 ? SUPER_ORDER.length : i; };

/** One shared application shell; navigation and widgets differ per dashboard kind. */
export async function AppShell({ ctx, kind, children }: { ctx: AuthContext; kind: DashboardKind; children: ReactNode }) {
  const sites = await listAccessibleSites(ctx);
  const activeSiteId = await getActiveSiteId(sites);
  const dashboards = availableDashboards(ctx);
  // A website that is not licensed for Pages, Media, Events or Forms does not see them in the menu (super admins see everything).
  const licensed = activeSiteId && !ctx.isSuperAdmin ? await getSiteModuleKeys(activeSiteId) : null;
  const allowedByLicence = (path: string) => !licensed || !(path in CORE_MODULE_BY_PATH) || licensed.includes(CORE_MODULE_BY_PATH[path]!);
  // Libraries expands like ShowOff's: Manage, Add New Library (super admin), then one item per content module this website has.
  const libraryTypes = activeSiteId ? await siteContentTypes(activeSiteId) : [];
  // Menus expands like ShowOff's: one item per menu of the open website (org admins; super admins use the all-websites page).
  const siteMenus = activeSiteId && canAnywhere(ctx, "navigation.manage")
    ? await db.navigationMenu.findMany({ where: { siteId: activeSiteId }, orderBy: { createdAt: "asc" }, take: 30, select: { id: true, name: true } }).catch(() => [])
    : [];
  // A super admin inside a website stays in that website's tree (their /dashboard/menus address is the all-websites page).
  const menuHref = (tail: string) => (ctx.isSuperAdmin ? `/dashboard/admin/menus${tail}` : undefined);
  const withMenus = (it: NavItem): NavItem => it.label !== "Menus" ? it : {
    ...it,
    ...(menuHref("") ? { href: menuHref("") } : {}),
    ...(siteMenus.length === 0 ? {} : { children: siteMenus.map((m): NavItem => ({ label: m.name, path: `/menus/${m.id}`, ...(menuHref(`/${m.id}`) ? { href: menuHref(`/${m.id}`) } : {}), icon: "menu", ready: true })) }),
  };
  const withLibraries = (it: NavItem): NavItem => it.label !== "Libraries" ? it : {
    ...it,
    children: [
      { label: "Manage", path: "/libraries", icon: "library", ready: true },
      ...(ctx.isSuperAdmin ? [{ label: "Add New Library", path: "/modules/new", href: "/dashboard/modules/new", icon: "library" as const, ready: true }] : []),
      ...libraryTypes.map((t): NavItem => ({ label: t.plural, path: `/libraries/${t.key}`, icon: "library", ready: true })),
    ],
  };
  // One "cmsadmin" sidebar for everyone: it lists the sections the signed-in user's roles allow, so there is nothing to toggle.
  // A super admin always sees the platform menu; once inside a particular website the website menu (Pages, Panels, Libraries ...) is appended below it.
  const kinds: DashboardKind[] = ctx.isSuperAdmin ? (kind === "admin" ? ["super-admin", "admin"] : ["super-admin"]) : dashboards;
  const groups = kinds.map((k, i) => ({
    // Only the Website section of an admin carries a title; a super admin's single sidebar has none.
    heading: ctx.isSuperAdmin ? undefined : kinds.length > 1 || k === "admin" ? DASHBOARD_LABELS[k] : undefined,
    kind: k,
    items: NAV[k].map(withLibraries).map((it) => (k === "admin" ? withMenus(it) : it)).flatMap((it): NavItem[] => {
      const hiddenForSuper: string[] = [];
      if (!allowedByLicence(it.path) || (it.perm && !canAnywhere(ctx, it.perm)) || hiddenForSuper.includes(it.label)) return [];
      if (!(i === 0 || (it.path !== "" && it.label !== "My profile"))) return [];
      if (!it.children) return [it];
      const children = it.children.filter((c) => allowedByLicence(c.path) && (!c.perm || canAnywhere(ctx, c.perm)) && !(k === "admin" && ctx.isSuperAdmin && ["Users & permissions", "Activity history", "My profile"].includes(c.label)));
      // A group whose items are all out of reach disappears (Settings for a user with none of its permissions).
      return children.length === 0 ? [] : [{ ...it, children }];
    }),
  }));
  // A super admin gets one list in the platform's own workflow order: the website items (Pages ... Settings) sit among the platform items
  // and exist only inside a particular website. Each item keeps the address of the tree it came from.
  const withHrefs = (g: (typeof groups)[number]): NavItem[] => g.items.map((it) => ({
    ...it,
    href: it.href ?? publicHref(g.kind, it.path),
    ...(it.children ? { children: it.children.map((c) => ({ ...c, href: c.href ?? publicHref(g.kind, c.path) })) } : {}),
  }));
  const inWebsite = groups.some((g) => g.kind === "admin");
  const merged = ctx.isSuperAdmin
    ? [{
        heading: undefined, kind: "super-admin" as DashboardKind,
        // Inside a website: its Menus (with that website's menus) replaces the platform "Menus", and the website "Modules" is left out (Feature modules covers it).
        items: groups.flatMap((g) => withHrefs(g).filter((it) => !(inWebsite && ((g.kind === "super-admin" && it.label === "Menus") || (g.kind === "admin" && it.label === "Modules")))))
          .map((it, i) => ({ it, i }))
          .sort((a, b) => (rank(a.it.label) - rank(b.it.label)) || a.i - b.i)
          .map((x) => x.it),
      }]
    : groups;
  // Org admins and maintenance users start from their project list and can return to it any time.
  const showProjects = !ctx.isSuperAdmin && (dashboards.includes("admin") || dashboards.includes("maintenance"));

  const topbar = (
    <>
      {showProjects ? <Link href="/dashboard/projects" className={buttonClass("ghost", "h-8 text-xs")}>All projects</Link> : null}
      {/* Super admins, org admins and maintenance users pick a website from their list instead; only editors switch here. */}
      {ctx.isSuperAdmin || showProjects ? null : <SiteSwitcher sites={sites} activeSiteId={activeSiteId} />}
      {ctx.isSuperAdmin && kind !== "super-admin" ? (
        <Link href="/dashboard/sites" className={buttonClass("secondary", "h-8 text-xs")}>Back to All Websites</Link>
      ) : null}
      <div className="hidden text-right text-xs leading-tight sm:block">
        <p className="font-medium">{ctx.name}</p>
        <p className="text-muted-foreground">{ctx.email}</p>
      </div>
      <form action={signOutAction}>
        <button className={buttonClass("secondary")} type="submit">
          Sign out
        </button>
      </form>
    </>
  );

  return (
    <ShellFrame groups={merged} roleLabel="cmsadmin" topbar={topbar}>
      {children}
    </ShellFrame>
  );
}
