"use client";

import Link from "next/link";
import { useRouter } from "next/navigation";
import { usePathname } from "next/navigation";
import { useEffect, useState } from "react";
import {
  LayoutDashboard,
  User,
  MapPin,
  ShoppingBag,
  FileText,
  Wallet,
  LogOut,
  Bookmark,
  CreditCard,
  PlusCircle,
  Truck,
  Package,
  Users,
  AlertTriangle,
  Route,
  Loader2,
  X,
  MoreHorizontal,
  PanelLeftOpen,
  ChevronDown,
  ChevronRight,
  Store,
  ShoppingCart,
  type LucideIcon,
} from "lucide-react";
import { useAuth } from "@/lib/auth/AuthContext";
import { clientCookies } from "@/lib/auth/cookies";
import { DASHBOARD_MODE_COOKIE, type DashboardMode } from "@/lib/dashboardMode";
import { DashboardModeContext } from "./DashboardMode";
import ConfirmDialog from "@/components/ui/ConfirmDialog";
import { toast } from "sonner";

type NavItem = { href: string; label: string; icon: LucideIcon };

const COMMON_TOP: NavItem[] = [
  { href: "/dashboard", label: "Dashboard", icon: LayoutDashboard },
];

const CUSTOMER_NAV: NavItem[] = [
  // One name for the RFQ flow (4.5): "Post Requirement" creates (catalog
  // live quotes or anything else), "My Requirements" lists. It leads because
  // it is the shortest path from "I need steel" to a price.
  { href: "/rfq/new", label: "Post Requirement", icon: PlusCircle },
  { href: "/orders", label: "Orders", icon: ShoppingBag },
  { href: "/rfq", label: "My Requirements", icon: FileText },
  { href: "/watchlist", label: "Watchlist", icon: Bookmark },
  { href: "/wallet", label: "Wallet", icon: Wallet },
  { href: "/credit-request", label: "Credit Requests", icon: CreditCard },
];

const SELLER_NAV: NavItem[] = [
  { href: "/seller/orders", label: "Orders", icon: ShoppingBag },
  { href: "/seller/quotations", label: "RFQs", icon: FileText },
  { href: "/seller/products", label: "My Products", icon: Package },
  { href: "/seller/commodity-products", label: "Commodity Catalog", icon: Package },
  { href: "/wallet", label: "Wallet", icon: Wallet },
];

const TRANSPORTER_NAV: NavItem[] = [
  { href: "/transporter/enquiries", label: "Enquiries", icon: FileText },
  { href: "/transporter/orders", label: "Trips", icon: Truck },
  { href: "/transporter/vehicles", label: "Vehicles", icon: Truck },
  { href: "/transporter/products", label: "Products", icon: Package },
  { href: "/transporter/belts", label: "Belts", icon: Route },
  { href: "/wallet", label: "Wallet", icon: Wallet },
];

const COMMON_BOTTOM: NavItem[] = [
  { href: "/profile", label: "Profile", icon: User },
  { href: "/profile/addresses", label: "Addresses", icon: MapPin },
];

const STAFF_LINK: NavItem = { href: "/staff", label: "Staff", icon: Users };

/** Grouped under "Account" in the mobile menu; everything else is the side's own work. */
const ACCOUNT_HREFS = new Set([STAFF_LINK.href, ...COMMON_BOTTOM.map((n) => n.href)]);

type Mode = DashboardMode;
const MODE_COOKIE_MAX_AGE = 60 * 60 * 24 * 365;

/** Pages that belong to one side; everything else (wallet, profile…) is shared. */
function modeForPath(pathname: string): Mode | null {
  if (pathname.startsWith("/seller")) return "sell";
  if (["/rfq", "/orders", "/watchlist", "/credit-request", "/enquiry"].some((p) => pathname === p || pathname.startsWith(p + "/"))) {
    return "buy";
  }
  return null;
}

function navForRole(
  type: string | null | undefined,
  isStaff: boolean | undefined,
  bothRoles: boolean | undefined,
  mode: Mode
): NavItem[] {
  const owner = !isStaff;
  const tail = owner ? [STAFF_LINK, ...COMMON_BOTTOM] : COMMON_BOTTOM;
  /* A promoted buyer works both sides. One long mixed menu (and a bottom bar
     that always showed buying tabs, even on selling pages) is replaced by a
     Buying / Selling switch: each mode shows its own items (4.6). */
  if (bothRoles) {
    return [...COMMON_TOP, ...(mode === "sell" ? SELLER_NAV : CUSTOMER_NAV), ...tail];
  }
  if (type === "seller") return [...COMMON_TOP, ...SELLER_NAV, ...tail];
  if (type === "transporter") return [...COMMON_TOP, ...TRANSPORTER_NAV, ...tail];
  return [...COMMON_TOP, ...CUSTOMER_NAV, ...tail];
}

function roleLabel(
  type: string | null | undefined,
  isStaff: boolean | undefined,
  role: string | null | undefined,
  bothRoles?: boolean
) {
  const base = bothRoles
    ? "Buyer & Seller"
    : type === "transporter"
      ? "Transporter"
      : type === "seller"
        ? "Seller"
        : type === "customer"
          ? "Buyer"
          : "";
  if (!base) return "";
  return isStaff ? `${base} Staff${role ? ` · ${role}` : ""}` : base;
}

export default function DashboardLayout({
  children,
  initialMode,
}: {
  children: React.ReactNode;
  /** The saved Buying / Selling choice, read from the cookie on the server. */
  initialMode: Mode;
}) {
  const pathname = usePathname();
  const { user, logout } = useAuth();
  const router = useRouter();
  const [confirmOpen, setConfirmOpen] = useState(false);
  const [busyLogout, setBusyLogout] = useState(false);
  const [drawerOpen, setDrawerOpen] = useState(false);
  const bothRoles = !!user?.is_buyer_and_seller;
  // The side of the marketplace the menu and dashboard show: the page decides
  // when it belongs to one side; shared pages (dashboard, wallet, profile…)
  // keep the last choice.
  const [mode, setMode] = useState<Mode>(() => modeForPath(pathname ?? "") ?? initialMode);
  function rememberMode(next: Mode) {
    setMode(next);
    clientCookies.set(DASHBOARD_MODE_COOKIE, next, MODE_COOKIE_MAX_AGE);
  }
  useEffect(() => {
    const fromPath = modeForPath(pathname ?? "");
    if (fromPath) rememberMode(fromPath);
  }, [pathname]);
  // Each side opens on its own dashboard.
  function switchMode(next: Mode) {
    rememberMode(next);
    setDrawerOpen(false);
    if (pathname !== "/dashboard") router.push("/dashboard");
  }
  const NAV = navForRole(user?.type, user?.is_staff, bothRoles, mode);
  const activeHref =
    NAV.filter(({ href }) => pathname === href || pathname.startsWith(href + "/"))
      .sort((a, b) => b.href.length - a.href.length)[0]?.href ?? null;
  const displayName = user?.company_name?.trim() || user?.name || "Account";
  const showEmailWarning =
    user && (user.type === "customer" || user.type === "seller") && (!user.email || user.email === "");
  const activeItem = NAV.find((n) => n.href === activeHref);
  const navGroups = [
    { title: bothRoles ? (mode === "sell" ? "Selling" : "Buying") : "Menu", items: NAV.filter((n) => !ACCOUNT_HREFS.has(n.href)) },
    { title: "Account", items: NAV.filter((n) => ACCOUNT_HREFS.has(n.href)) },
  ].filter((g) => g.items.length > 0);

  // Primary items shown in the mobile bottom tab bar (first 4 nav entries).
  const bottomTabs = NAV.slice(0, 4);

  // Close the mobile drawer whenever the route changes.
  useEffect(() => {
    setDrawerOpen(false);
  }, [pathname]);

  // While the mobile drawer is open the page behind stays put (html and body
  // both, as either can be the scroller), and Escape closes it.
  useEffect(() => {
    if (!drawerOpen) return;
    const html = document.documentElement;
    const body = document.body;
    const prev = [html.style.overflow, body.style.overflow];
    html.style.overflow = "hidden";
    body.style.overflow = "hidden";
    const onKey = (e: KeyboardEvent) => {
      if (e.key === "Escape") setDrawerOpen(false);
    };
    document.addEventListener("keydown", onKey);
    return () => {
      html.style.overflow = prev[0];
      body.style.overflow = prev[1];
      document.removeEventListener("keydown", onKey);
    };
  }, [drawerOpen]);

  async function handleLogout() {
    setBusyLogout(true);
    try {
      await logout();
      toast.success("Logged out successfully.");
      router.replace("/");
      router.refresh();
    } catch {
      toast.error("Logout failed. Please try again.");
    } finally {
      setBusyLogout(false);
    }
  }

  const UserCard = (
    <div className="border-b border-gray-100 pb-3">
      <div className="flex items-center gap-2">
        <div className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-[#CC1414] text-xs font-bold text-white">
          {displayName.charAt(0).toUpperCase()}
        </div>
        <div className="min-w-0">
          <div title={displayName} className="truncate text-sm font-semibold text-gray-900 leading-tight">{displayName}</div>
          <div className="truncate text-[11px] text-gray-500">{user?.email ?? user?.phone ?? ""}</div>
          {user && (
            <div className="mt-0.5 text-[9px] font-semibold uppercase tracking-widest text-[#CC1414]">
              {roleLabel(user.type, user.is_staff, user.role, user.is_buyer_and_seller)}
            </div>
          )}
        </div>
      </div>
    </div>
  );

  const ModeSwitch = bothRoles ? (
    <div role="tablist" aria-label="Marketplace side" className="mt-3 grid grid-cols-2 rounded-lg bg-gray-100 p-0.5 text-xs font-semibold">
      {([
        ["sell", "Selling"],
        ["buy", "Buying"],
      ] as const).map(([value, label]) => (
        <button
          key={value}
          type="button"
          role="tab"
          aria-selected={mode === value}
          onClick={() => mode !== value && switchMode(value)}
          className={`rounded-md py-1.5 transition ${mode === value ? "bg-white text-[#CC1414] shadow-sm" : "text-gray-500 hover:text-gray-800"}`}
        >
          {label}
        </button>
      ))}
    </div>
  ) : null;

  const NavList = (
    <nav className="mt-2 space-y-0.5">
      {NAV.map(({ href, label, icon: Icon }) => {
        const active = activeHref === href;
        return (
          <Link
            key={href}
            href={href}
            onClick={() => setDrawerOpen(false)}
            className={`flex items-center gap-2.5 rounded-lg px-2.5 py-2.5 text-[13px] transition lg:py-1.5 ${
              active
                ? "bg-[#CC1414]/10 font-semibold text-[#CC1414]"
                : "text-gray-600 hover:bg-gray-50 hover:text-gray-900"
            }`}
          >
            <Icon className="h-4 w-4 shrink-0 lg:h-3.5 lg:w-3.5" />
            {label}
          </Link>
        );
      })}
      <button
        onClick={() => setConfirmOpen(true)}
        disabled={busyLogout}
        className="mt-2 flex w-full items-center gap-2.5 rounded-lg px-2.5 py-2.5 text-[13px] text-gray-500 hover:bg-red-50 hover:text-[#CC1414] disabled:opacity-60 lg:py-1.5"
      >
        {busyLogout ? <Loader2 className="h-4 w-4 animate-spin lg:h-3.5 lg:w-3.5" /> : <LogOut className="h-4 w-4 lg:h-3.5 lg:w-3.5" />}
        {busyLogout ? "Logging out…" : "Logout"}
      </button>
    </nav>
  );

  return (
    <div className="min-h-[calc(100dvh-160px)] bg-gray-50">
      {/* Mobile top bar: names the section and opens the dashboard menu. With
          the menu only behind "Menu" in the bottom bar, buyers did not find it
          at all. A sidebar icon and a chevron, not a second ☰, so it reads as
          this dashboard's menu and not the site header's. */}
      <div className="sticky top-16 z-30 flex items-center gap-3 border-b border-gray-100 bg-white/95 px-3 py-2 backdrop-blur lg:hidden">
        <button
          type="button"
          onClick={() => setDrawerOpen(true)}
          aria-label="Open dashboard menu"
          aria-expanded={drawerOpen}
          className="flex min-w-0 items-center gap-2 rounded-lg px-2 py-1.5 text-left transition hover:bg-gray-50 active:bg-gray-100"
        >
          <PanelLeftOpen className="h-5 w-5 shrink-0 text-[#CC1414]" />
          <span className="truncate text-sm font-semibold text-gray-900">{activeItem?.label ?? "Dashboard"}</span>
          <ChevronDown className="h-4 w-4 shrink-0 text-gray-400" />
        </button>
        {bothRoles && (
          <span className="ml-auto shrink-0 rounded-full bg-red-50 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-[#CC1414]">
            {mode === "sell" ? "Selling" : "Buying"}
          </span>
        )}
        {/* No avatar here: the site header's account dropdown sits directly
            above this bar and is the single interactive account entry point. */}
      </div>

      <div className="mx-auto max-w-7xl px-3 py-4 sm:px-4 lg:px-6 lg:py-6">
        <div className="grid grid-cols-12 items-start gap-4 lg:gap-5">
          {/*
            Desktop sidebar. `items-start` on the grid is what lets this stick:
            a stretched grid item is as tall as the row and has nowhere to
            travel. It parks 24px below the 64px site header, which is sticky
            too, so the two never overlap.

            The nav scrolls inside the card rather than the card growing past
            the fold — the height budget is the viewport minus the sticky offset
            and the user card above it.
          */}
          <aside className="hidden min-w-0 lg:col-span-2 lg:sticky lg:top-24 lg:block">
            <div className="rounded-xl bg-white p-3 shadow-sm ring-1 ring-gray-100 lg:p-4">
              {UserCard}
              {ModeSwitch}
              <div className="lg:max-h-[calc(100dvh-14rem)] lg:overflow-y-auto lg:overscroll-contain">
                {NavList}
              </div>
            </div>
          </aside>

          {/* min-w-0 is load-bearing: grid items default to `min-width:auto`, so
              without it this column refuses to shrink below its widest child and
              any wide content scrolls the entire document sideways. */}
          <main className="col-span-12 min-w-0 space-y-4 pb-[calc(6rem+env(safe-area-inset-bottom))] lg:col-span-10 lg:space-y-5 lg:pb-20">
            {showEmailWarning && !pathname.startsWith("/profile") && (
              <div className="flex items-start gap-3 rounded-xl bg-amber-50 p-4 ring-1 ring-amber-200">
                <AlertTriangle className="mt-0.5 h-5 w-5 shrink-0 text-amber-600" />
                <div className="flex-1 text-sm">
                  <p className="font-medium text-amber-900">Add your email address</p>
                  <p className="text-amber-800">
                    An email is required for invoices and order updates.{" "}
                    <Link href="/profile?edit=true" className="font-medium underline">
                      Update profile
                    </Link>
                  </p>
                </div>
              </div>
            )}
            <DashboardModeContext.Provider value={mode}>{children}</DashboardModeContext.Provider>
          </main>
        </div>
      </div>

      {/* Mobile off-canvas drawer: who is signed in, the Selling / Buying
          switch, the sections in two groups and Logout pinned to the bottom.
          Only the middle scrolls (`min-h-0` lets a flex child shrink enough
          to scroll); the page behind is locked by the effect above. */}
      <div
        className={`fixed inset-0 z-[60] lg:hidden ${drawerOpen ? "" : "pointer-events-none"}`}
        aria-hidden={!drawerOpen}
      >
        <div
          onClick={() => setDrawerOpen(false)}
          className={`absolute inset-0 touch-none bg-black/40 transition-opacity duration-300 ${
            drawerOpen ? "opacity-100" : "opacity-0"
          }`}
        />
        <div
          role="dialog"
          aria-modal="true"
          aria-label="Dashboard menu"
          className={`absolute inset-y-0 left-0 flex w-[86%] max-w-sm flex-col bg-white shadow-2xl transition-transform duration-300 ease-out ${
            drawerOpen ? "translate-x-0" : "-translate-x-full"
          }`}
        >
          <div className="flex items-center gap-3 border-b border-gray-100 bg-gradient-to-br from-red-50 to-white px-4 py-3">
            <div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-[#CC1414] text-base font-bold text-white">
              {displayName.charAt(0).toUpperCase()}
            </div>
            <div className="min-w-0 flex-1">
              <p className="truncate text-sm font-semibold text-gray-900">{displayName}</p>
              <p className="truncate text-xs text-gray-500">{user?.email ?? user?.phone ?? ""}</p>
              {user && (
                <p className="mt-0.5 text-[10px] font-semibold uppercase tracking-widest text-[#CC1414]">
                  {roleLabel(user.type, user.is_staff, user.role, user.is_buyer_and_seller)}
                </p>
              )}
            </div>
            <button
              type="button"
              onClick={() => setDrawerOpen(false)}
              className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full text-gray-500 hover:bg-white active:bg-gray-100"
              aria-label="Close menu"
            >
              <X className="h-5 w-5" />
            </button>
          </div>

          {/* No scrollbar: it is a touch list, and the site-wide red thumb
              showed as a thick red bar along the drawer's edge. */}
          <div className="min-h-0 flex-1 overflow-y-auto overscroll-contain px-3 pb-3 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden">
            {bothRoles && (
              <div role="tablist" aria-label="Marketplace side" className="mt-2.5 grid grid-cols-2 gap-1 rounded-xl bg-gray-100 p-1">
                {([
                  ["sell", "Selling", Store],
                  ["buy", "Buying", ShoppingCart],
                ] as const).map(([value, label, Icon]) => (
                  <button
                    key={value}
                    type="button"
                    role="tab"
                    aria-selected={mode === value}
                    onClick={() => mode !== value && switchMode(value)}
                    className={`flex items-center justify-center gap-1.5 rounded-lg py-1.5 text-sm font-semibold transition ${
                      mode === value ? "bg-white text-[#CC1414] shadow-sm" : "text-gray-500 active:bg-gray-200"
                    }`}
                  >
                    <Icon className="h-4 w-4" /> {label}
                  </button>
                ))}
              </div>
            )}

            {navGroups.map((group) => (
              <div key={group.title} className="mt-3">
                <p className="px-3 pb-1 text-[11px] font-semibold uppercase tracking-wider text-gray-400">{group.title}</p>
                <ul className="space-y-0.5">
                  {group.items.map(({ href, label, icon: Icon }) => {
                    const active = activeHref === href;
                    return (
                      <li key={href}>
                        <Link
                          href={href}
                          onClick={() => setDrawerOpen(false)}
                          aria-current={active ? "page" : undefined}
                          className={`flex items-center gap-3 rounded-xl px-3 py-2 text-sm transition ${
                            active ? "bg-red-50 font-semibold text-[#CC1414]" : "text-gray-700 active:bg-gray-100"
                          }`}
                        >
                          <span
                            className={`flex h-7 w-7 shrink-0 items-center justify-center rounded-lg ${
                              active ? "bg-[#CC1414] text-white" : "bg-gray-50 text-gray-500 ring-1 ring-gray-100"
                            }`}
                          >
                            <Icon className="h-4 w-4" />
                          </span>
                          <span className="min-w-0 flex-1 truncate">{label}</span>
                          <ChevronRight className={`h-4 w-4 shrink-0 ${active ? "text-[#CC1414]" : "text-gray-300"}`} />
                        </Link>
                      </li>
                    );
                  })}
                </ul>
              </div>
            ))}
          </div>

          <div className="border-t border-gray-100 px-3 py-2.5 pb-[calc(0.625rem+env(safe-area-inset-bottom))]">
            <button
              type="button"
              onClick={() => setConfirmOpen(true)}
              disabled={busyLogout}
              className="flex w-full items-center justify-center gap-2 rounded-xl border border-red-100 bg-red-50 py-2 text-sm font-semibold text-[#CC1414] transition active:bg-red-100 disabled:opacity-60"
            >
              {busyLogout ? <Loader2 className="h-4 w-4 animate-spin" /> : <LogOut className="h-4 w-4" />}
              {busyLogout ? "Logging out…" : "Logout"}
            </button>
          </div>
        </div>
      </div>

      {/* Mobile bottom tab bar — native app feel */}
      <nav className="fixed inset-x-0 bottom-0 z-40 flex items-stretch border-t border-gray-200 bg-white/95 pb-[env(safe-area-inset-bottom)] backdrop-blur lg:hidden">
        {bottomTabs.map(({ href, label, icon: Icon }) => {
          const active = activeHref === href;
          return (
            <Link
              key={href}
              href={href}
              className={`flex flex-1 flex-col items-center justify-center gap-0.5 py-2 text-[10px] font-medium transition ${
                active ? "text-[#CC1414]" : "text-gray-500"
              }`}
            >
              <Icon className={`h-5 w-5 ${active ? "text-[#CC1414]" : "text-gray-500"}`} />
              <span className="max-w-[64px] truncate">{label}</span>
            </Link>
          );
        })}
        <button
          onClick={() => setDrawerOpen(true)}
          className="flex flex-1 flex-col items-center justify-center gap-0.5 py-2 text-[10px] font-medium text-gray-500 transition"
        >
          <MoreHorizontal className="h-5 w-5" />
          <span>Menu</span>
        </button>
      </nav>

      <ConfirmDialog
        open={confirmOpen}
        title="Logout from your account?"
        description="You will need to login again to access your dashboard features."
        confirmLabel="Logout"
        loading={busyLogout}
        onCancel={() => setConfirmOpen(false)}
        onConfirm={async () => {
          setConfirmOpen(false);
          await handleLogout();
        }}
      />
    </div>
  );
}
