import { Link, usePage } from "@inertiajs/react";
import {
    Boxes,
    BriefcaseBusiness,
    Building2,
    ClipboardCheck,
    ClipboardList,
    FileCheck2,
    FileSignature,
    FolderTree,
    HardHat,
    Inbox,
    KeyRound,
    LayoutGrid,
    LifeBuoy,
    Plus,
    Receipt,
    Scale,
    Settings,
    ShieldCheck,
    Target,
    Truck,
    Users,
    UsersRound,
    Wallet,
    Warehouse,
} from "lucide-react";
import AppLogoIcon from "@/components/app-logo-icon";
import { NavMain } from "@/components/nav-main";
import { Button } from "@/components/ui/button";
import {
    Sidebar,
    SidebarContent,
    SidebarFooter,
    SidebarHeader,
    SidebarMenu,
    SidebarMenuButton,
    SidebarMenuItem,
} from "@/components/ui/sidebar";
import { usePermissions } from "@/hooks/use-permissions";
import { useRelease } from "@/hooks/use-release";
import { dashboard } from "@/routes";
import { index as customersIndex } from "@/routes/customers";
import { index as inspectionsIndex } from "@/routes/inspections";
import { index as installersIndex } from "@/routes/installers";
import { create as jobsCreate, index as jobsIndex } from "@/routes/jobs";
import { index as messagesIndex } from "@/routes/messages";
import { index as rolesIndex } from "@/routes/roles";
import { index as ticketsIndex } from "@/routes/tickets";
import { index as usersIndex } from "@/routes/users";
import { index as vaultIndex } from "@/routes/vault";
import { index as invoicesIndex } from "@/routes/finance/invoices";
import { index as lodgementsIndex } from "@/routes/finance/lodgements";
import { index as reimbursementsIndex } from "@/routes/finance/reimbursements";
import { index as tasksIndex } from "@/routes/operations/tasks";
import { index as leadsIndex } from "@/routes/sales/leads";
import { index as quotationsIndex } from "@/routes/sales/quotations";
import {
    dashboard as warehouseDashboard,
    inventory as warehouseInventory,
} from "@/routes/warehouse";
import { index as warehouseMovements } from "@/routes/warehouse/movements";
import { index as categoriesIndex } from "@/routes/warehouse/categories";
import { index as productsIndex } from "@/routes/warehouse/products";
import { index as suppliersIndex } from "@/routes/warehouse/suppliers";
import type { AppVersion, Branding, NavItem } from "@/types";

const mainNavItems: NavItem[] = [
    {
        title: "Dashboard",
        href: dashboard(),
        icon: LayoutGrid,
    },
    {
        // Conversations between staff, one click from anywhere. The count is
        // filled in below from the shared inbox prop.
        title: "Inbox",
        href: messagesIndex(),
        icon: Inbox,
        part: "inbox",
    },
    {
        title: "Customers",
        href: customersIndex(),
        icon: Building2,
        part: "customers",
    },
    {
        title: "Jobs",
        href: jobsIndex(),
        icon: BriefcaseBusiness,
        part: "jobs",
    },
    {
        title: "Installers",
        href: installersIndex(),
        icon: HardHat,
        part: "installers",
    },
    {
        title: "Inspections",
        href: inspectionsIndex(),
        icon: ClipboardCheck,
        part: "inspections",
    },
    {
        title: "Tickets",
        href: ticketsIndex(),
        icon: LifeBuoy,
        part: "tickets",
    },
    {
        // The monitoring-portal logins. Gated on its own permission: this is
        // the one screen in the app where a password can be read.
        title: "Vault",
        href: vaultIndex(),
        icon: KeyRound,
        part: "vault",
    },
];

/**
 * The revenue side: the pipeline before an install, and the quotes that close
 * it. Both are hidden behind the sales view permissions.
 */
const salesNavItems: NavItem[] = [
    {
        title: "Leads",
        href: leadsIndex(),
        icon: Target,
        part: "sales",
    },
    {
        title: "Quotations",
        href: quotationsIndex(),
        icon: FileSignature,
        part: "sales",
    },
];

/**
 * The money: what is owed in both directions, what staff have spent, and the
 * rebate paperwork that holds a payment up.
 */
const financeNavItems: NavItem[] = [
    {
        title: "Invoices",
        href: invoicesIndex(),
        icon: Receipt,
        part: "finance",
    },
    {
        title: "Reimbursements",
        href: reimbursementsIndex(),
        icon: Wallet,
        part: "finance",
    },
    {
        title: "Export lodgements",
        href: lodgementsIndex(),
        icon: FileCheck2,
        part: "finance",
    },
];

/**
 * Work moving between departments, which is what operations actually runs on.
 */
const operationsNavItems: NavItem[] = [
    {
        title: "Department tasks",
        href: tasksIndex(),
        icon: ClipboardList,
        part: "operations",
    },
];

/**
 * Administration links, each gated by the permission the backend requires.
 * Hiding a link is a convenience only: every route is authorised again server
 * side by the policies.
 */
const adminNavItems: NavItem[] = [
    {
        title: "Staff",
        href: usersIndex(),
        icon: Users,
    },
    {
        // Customers who signed up to the ticket portal. The Staff screen
        // deliberately lists staff only; this is the other half of the table.
        title: "Customer accounts",
        href: "/customer-accounts",
        icon: UsersRound,
    },
    {
        title: "Roles & permissions",
        href: rolesIndex(),
        icon: ShieldCheck,
    },
    // The settings area. It points at /settings rather than at one section,
    // because the first section differs by role: the company profile for the
    // office, the backups for whoever runs the system, and a person's own
    // security otherwise — which is every role, since the manual lives here too.
    {
        title: "Settings",
        href: "/settings",
        icon: Settings,
    },
];

/**
 * The warehouse's own menu. Hidden behind stock.view, which is the permission
 * every route in that module checks again on the server.
 */
const warehouseNavItems: NavItem[] = [
    {
        title: "Warehouse",
        href: warehouseDashboard(),
        icon: Warehouse,
        part: "warehouse",
    },
    {
        title: "Products",
        href: productsIndex(),
        icon: Boxes,
        part: "warehouse",
    },
    {
        title: "Stock levels",
        href: warehouseInventory(),
        icon: Scale,
        part: "warehouse",
    },
    {
        title: "Stock ledger",
        href: warehouseMovements(),
        icon: ClipboardList,
        part: "warehouse",
    },
    {
        title: "Pick lists",
        href: "/warehouse/picking",
        icon: ClipboardCheck,
        part: "warehouse",
    },
    {
        title: "Suppliers",
        href: suppliersIndex(),
        icon: Truck,
        part: "warehouse",
    },
    {
        title: "Categories",
        href: categoriesIndex(),
        icon: FolderTree,
        part: "warehouse",
    },
];

export function AppSidebar() {
    const { can } = usePermissions();
    // What this installation has released. A part that is switched off is not
    // offered here, because its routes answer 404; the server decides, and this
    // only keeps the menu honest.
    const { enabled } = useRelease();
    // The company's own name and logo, so the most prominent name in the app is
    // the one the client set in Settings -> Company profile rather than a
    // constant.
    const { branding, inbox, version } = usePage().props as unknown as {
        branding?: Branding;
        inbox?: { unread: number };
        version?: AppVersion;
    };

    // Tickets and the installer register are gated by their own permissions, so
    // a role that cannot open either does not get a link that only ever 403s.
    const visibleMainItems = mainNavItems
        .filter((item) => {
            switch (item.title) {
                case "Inbox":
                    return can("messages.view");
                case "Tickets":
                    return can("tickets.view");
                case "Installers":
                    return can("installers.view");
                case "Inspections":
                    return can("inspections.view");
                case "Vault":
                    return can("vault.view");
                default:
                    return true;
            }
        })
        .filter((item) => enabled(item.part))
        // The count comes from the shared inbox prop, so it is right on every
        // page rather than only when the inbox itself has been opened.
        .map((item) =>
            item.title === "Inbox"
                ? { ...item, badge: inbox?.unread ?? 0 }
                : item,
        );

    const adminItems = adminNavItems
        .filter((item) => {
            switch (item.title) {
                case "Staff":
                case "Customer accounts":
                    return can("users.view");
                case "Roles & permissions":
                    // The route behind this link requires roles.manage, so
                    // showing it to anyone else would only lead to a 403.
                    return can("roles.manage");
                case "Settings":
                    // Everybody has settings of their own — password and
                    // passkeys, appearance, and the manual. The page shows only
                    // the tabs a person may open, so it is safe to offer the
                    // link to every role.
                    return true;
                default:
                    return false;
            }
        });

    return (
        <Sidebar collapsible="icon" variant="inset">
            <SidebarHeader className="gap-3 pt-3">
                <SidebarMenu>
                    <SidebarMenuItem>
                        <SidebarMenuButton size="lg" asChild>
                            <Link
                                href={dashboard()}
                                prefetch
                                className="gap-2.5 group-data-[collapsible=icon]:justify-center"
                            >
                                {branding?.logo_url ? (
                                    <img
                                        src={branding.logo_url}
                                        alt=""
                                        className="size-8 shrink-0 rounded-lg object-cover ring-1 ring-hairline"
                                    />
                                ) : (
                                    <span className="flex size-8 shrink-0 items-center justify-center rounded-lg bg-solar-soft text-solar-ink ring-1 ring-solar/25">
                                        <AppLogoIcon className="size-4.5 fill-current" />
                                    </span>
                                )}
                                <span className="grid min-w-0 flex-1 text-left">
                                    <span className="truncate text-sm leading-tight font-semibold">
                                        {branding?.name ?? "Solar CRM"}
                                    </span>
                                    {branding?.tagline ? (
                                        <span className="truncate text-[11px] leading-tight text-muted-foreground">
                                            {branding.tagline}
                                        </span>
                                    ) : null}
                                </span>
                            </Link>
                        </SidebarMenuButton>
                    </SidebarMenuItem>
                </SidebarMenu>

                {can("jobs.create") && enabled("jobs") ? (
                    <div className="px-1 group-data-[collapsible=icon]:hidden">
                        <Button
                            asChild
                            size="sm"
                            className="w-full justify-start gap-2"
                        >
                            <Link href={jobsCreate()}>
                                <Plus className="size-4" />
                                New job
                            </Link>
                        </Button>
                    </div>
                ) : null}
            </SidebarHeader>

            <SidebarContent className="gap-4 pt-2">
                <NavMain items={visibleMainItems} label="CRM" />
                {enabled("sales") &&
                (can("leads.view") || can("quotations.view")) ? (
                    <NavMain
                        items={salesNavItems.filter((item) =>
                            item.title === "Leads"
                                ? can("leads.view")
                                : can("quotations.view"),
                        )}
                        label="Sales"
                    />
                ) : null}
                {enabled("finance") &&
                (can("invoices.view") ||
                    can("reimbursements.view") ||
                    can("lodgements.view")) ? (
                    <NavMain
                        items={financeNavItems.filter((item) => {
                            switch (item.title) {
                                case "Invoices":
                                    return can("invoices.view");
                                case "Reimbursements":
                                    return can("reimbursements.view");
                                default:
                                    return can("lodgements.view");
                            }
                        })}
                        label="Finance"
                    />
                ) : null}
                {enabled("operations") && can("tasks.view") ? (
                    <NavMain items={operationsNavItems} label="Operations" />
                ) : null}
                {enabled("warehouse") && can("stock.view") ? (
                    <NavMain items={warehouseNavItems} label="Warehouse" />
                ) : null}
                {adminItems.length > 0 ? (
                    <NavMain items={adminItems} label="Administration" />
                ) : null}
            </SidebarContent>

            {/* The version this installation is running. Small, quiet, and
                always in the same place, so "which build is on that server?"
                is answered by looking rather than by asking. */}
            <SidebarFooter className="px-3 pb-3 group-data-[collapsible=icon]:hidden">
                <p
                    className="text-[10px] font-medium tracking-wide text-muted-foreground/70"
                    title="Version of this installation"
                >
                    {version?.label ?? "v1.0.0"}
                </p>
            </SidebarFooter>
        </Sidebar>
    );
}
