import { Link } from "@inertiajs/react";
import {
    ArchiveRestore,
    BookOpen,
    Building2,
    DatabaseBackup,
    FileSpreadsheet,
    History,
    KeyRound,
    Layers,
    Link2,
    LogIn,
    Mail,
    MessageSquare,
    Monitor,
    Rocket,
    ShieldAlert,
    UserPlus,
} from "lucide-react";
import type { LucideIcon } from "lucide-react";
import type { PropsWithChildren } from "react";
import { PageHeader } from "@/components/crm/page-header";
import { useCurrentUrl } from "@/hooks/use-current-url";
import { usePermissions } from "@/hooks/use-permissions";
import { cn } from "@/lib/utils";
import { edit as editAppearance } from "@/routes/appearance";
import { index as backupsIndex } from "@/routes/backups";
import { edit as editBranding } from "@/routes/branding";
import { edit as editMail } from "@/routes/mail";
import { edit as editMessaging } from "@/routes/messaging";
import { edit as editPortal } from "@/routes/portal";
import { edit as editSheetImport } from "@/routes/sheet-import";
import { edit as editStatusLinks } from "@/routes/ticket-status-links";
import { edit as editSecurity } from "@/routes/security";

type SettingsTab = {
    title: string;
    href: string;
    icon: LucideIcon;
    description: string;
    /**
     * Only offered to the people the backend would let in anyway. The route
     * authorises again, so this is a convenience rather than the control.
     */
    permission?: string;
    /**
     * A setting the owner of the system controls, not one that can be granted
     * from the Roles screen. Super Admin only, and the route checks the role
     * again.
     */
    superAdminOnly?: boolean;
    /**
     * Roles that may see the tab, for a screen that is closed by role rather
     * than by permission. The backend checks the same roles again.
     */
    roles?: string[];
};

/**
 * Settings, grouped by what a person came here to change rather than listed as
 * one long column.
 *
 * Three questions, in the order they are usually asked: who am I on this system
 * (my own account); what does the company look like to everybody else (its
 * details, mail and portal); and what comes in and goes out of it (the sheets
 * it reads and the backups that protect it). A group with nothing visible in it
 * is not shown at all, so a staff member without settings.manage sees a short,
 * honest list instead of a wall of locked doors.
 */
type SettingsGroup = {
    title: string;
    description: string;
    tabs: SettingsTab[];
};

const groups: SettingsGroup[] = [
    {
        title: "Your account",
        description: "How you sign in and how the app looks to you.",
        tabs: [
            // A person's own profile is not here: it sits at /profile and is
            // reached from the account menu, so staff without access to these
            // company settings still have a place of their own.
            {
                title: "Security",
                href: editSecurity().url,
                icon: KeyRound,
                description: "Password, 2FA and passkeys.",
            },
            {
                title: "Appearance",
                href: editAppearance().url,
                icon: Monitor,
                description: "Light, dark or follow the system.",
            },
        ],
    },
    {
        // The manual is for everybody who can sign in, which is why this group
        // carries no permission: it is how a person learns what the screens
        // they cannot open are for, and who to ask.
        title: "Help",
        description: "How the system works, screen by screen.",
        tabs: [
            {
                title: "User manual",
                href: "/settings/manual",
                icon: BookOpen,
                description: "Every screen, with screenshots and a PDF.",
            },
        ],
    },
    {
        title: "Company",
        description:
            "What this installation is called and how it talks to people.",
        tabs: [
            // The company profile is what makes this installation one company's
            // rather than generic: who they legally are, where they are, how
            // they look, and what the staff sign-in screen says.
            {
                title: "Company profile",
                href: editBranding().url,
                icon: Building2,
                description: "Details, brand and sign-in page.",
                // Its own permission: the owner can give this out without
                // giving away the mail server or the backups.
                permission: "settings.company",
            },
            // The server this installation sends mail through: Gmail with an
            // app password, or any SMTP host by hand.
            {
                title: "Email delivery",
                href: editMail().url,
                icon: Mail,
                description: "The SMTP server that sends mail and resets.",
                permission: "settings.manage",
            },
            // The staff inbox's one company-wide decision: whether a reply may
            // be emailed to somebody outside the company.
            {
                title: "Messaging",
                href: editMessaging().url,
                icon: MessageSquare,
                description: "Whether the inbox may email outside.",
                superAdminOnly: true,
            },
            // How the customer portal behaves rather than how it looks: what
            // somebody signing up has to do before they see their own account.
            {
                title: "Customer portal",
                href: editPortal().url,
                icon: UserPlus,
                description: "What a new portal account must confirm first.",
                permission: "settings.manage",
            },
            // A way into the ticket queue without an account: a username and
            // password the office issues and can switch off again.
            {
                title: "Status links",
                href: editStatusLinks().url,
                icon: Link2,
                description: "Share the installer queue without a login.",
                permission: "settings.manage",
            },
            // The holding page a site wears until it is ready: one switch, and
            // the words on the page.
            {
                title: "Coming soon",
                href: "/settings/coming-soon",
                icon: Rocket,
                description: "A holding page while the site is finished.",
                permission: "settings.manage",
            },
        ],
    },
    {
        // The gradual release: which parts of the system this installation
        // shows, and the switch that finishes the handover. Closed by role,
        // like the oversight screens, because deciding what exists is the
        // owner's decision rather than a permission to give out.
        title: "Release",
        description: "What this installation shows, part by part.",
        tabs: [
            {
                title: "Release switches",
                href: "/settings/release",
                icon: Layers,
                description: "Switch parts on and off as they are handed over.",
                roles: ["Admin", "Super Admin"],
            },
        ],
    },
    {
        title: "Data",
        description: "What comes in, and the copies that keep it safe.",
        tabs: [
            // Reading a Google Sheet into jobs, and how often. The link is
            // pasted here rather than exported to a file and uploaded.
            {
                title: "Sheet import",
                href: editSheetImport().url,
                icon: FileSpreadsheet,
                description: "Read jobs from a Google Sheet link.",
                permission: "settings.manage",
            },
            // A one-off migration door for the old Client Information sales
            // workbook. It is closed by hand when the migration is finished,
            // so it sits beside the sheet import rather than in the sidebar.
            {
                title: "Client information import",
                href: "/settings/client-information-import",
                icon: FileSpreadsheet,
                description: "Temporary old sales-sheet import, opened and closed by hand.",
                permission: "settings.manage",
            },
            {
                title: "Backup & Restore",
                href: backupsIndex().url,
                icon: DatabaseBackup,
                description:
                    "Database and file backups, and how to restore them.",
                permission: "settings.manage",
            },
            // The account read for code that should not be there: web shells,
            // hidden payloads, scripts in upload folders. Read-only until
            // somebody asks for a file to be held, and never a deletion.
            {
                title: "Security scan",
                href: "/settings/security-scan",
                icon: ShieldAlert,
                description: "Find planted files, and hold them.",
                permission: "settings.manage",
            },
        ],
    },
    {
        // The owner's own view of the system, and not a setting at all: what
        // has happened, who came in, and what was hidden. Every tab is closed
        // to everyone but a Super Admin, which the routes check again.
        title: "Oversight",
        description: "What has happened, who came in, and what was hidden.",
        tabs: [
            {
                title: "Activity log",
                href: "/settings/audit",
                icon: History,
                description: "Every change, and who made it.",
                superAdminOnly: true,
            },
            {
                title: "Sign-in history",
                href: "/settings/audit/sign-ins",
                icon: LogIn,
                description: "Every attempt at every door.",
                superAdminOnly: true,
            },
            {
                title: "Recycle bin",
                href: "/settings/audit/deleted",
                icon: ArchiveRestore,
                description: "Hidden records, ready to restore.",
                superAdminOnly: true,
            },
        ],
    },
];

export default function SettingsLayout({ children }: PropsWithChildren) {
    const { isCurrentOrParentUrl } = useCurrentUrl();
    const { can, hasRole, hasAnyRole } = usePermissions();

    const visibleGroups = groups
        .map((group) => ({
            ...group,
            tabs: group.tabs.filter(
                (tab) =>
                    (tab.permission === undefined || can(tab.permission)) &&
                    (!tab.superAdminOnly || hasRole("Super Admin")) &&
                    (tab.roles === undefined || hasAnyRole(tab.roles)),
            ),
        }))
        .filter((group) => group.tabs.length > 0);

    return (
        <div className="flex flex-col gap-5">
            <PageHeader
                title="Settings"
                description="Your account, the company this installation is sold under, and the data that keeps the business running — grouped by what you came here to change."
            />

            <div className="flex flex-col gap-6 lg:flex-row lg:gap-8">
                <nav
                    aria-label="Settings"
                    className="flex crm-scroll gap-1 overflow-x-auto pb-1 lg:w-60 lg:shrink-0 lg:flex-col lg:overflow-visible lg:pb-0"
                >
                    {visibleGroups.map((group, index) => (
                        <div
                            key={group.title}
                            className={cn(
                                "flex shrink-0 items-center gap-1 lg:flex-col lg:items-stretch",
                                index > 0 &&
                                    "border-l border-hairline pl-1 lg:border-t lg:border-l-0 lg:pt-3 lg:pl-0",
                            )}
                        >
                            <p
                                className="hidden px-2.5 pb-1 text-[10px] font-semibold tracking-[0.14em] text-muted-foreground/70 uppercase lg:block"
                                title={group.description}
                            >
                                {group.title}
                            </p>

                            {group.tabs.map((tab) => {
                                const isActive = isCurrentOrParentUrl(tab.href);
                                const Icon = tab.icon;

                                return (
                                    <Link
                                        key={tab.href}
                                        href={tab.href}
                                        aria-current={
                                            isActive ? "page" : undefined
                                        }
                                        className={cn(
                                            "group flex shrink-0 items-center gap-2.5 rounded-lg px-2.5 py-2 text-sm transition-colors lg:items-start lg:py-2.5",
                                            isActive
                                                ? "bg-solar-soft text-solar-ink ring-1 ring-solar/25 ring-inset"
                                                : "text-muted-foreground hover:bg-accent/50 hover:text-foreground",
                                        )}
                                    >
                                        <span
                                            className={cn(
                                                "flex size-7 shrink-0 items-center justify-center rounded-md transition-colors",
                                                isActive
                                                    ? "bg-solar/15 text-solar-ink"
                                                    : "bg-muted text-muted-foreground group-hover:text-foreground",
                                            )}
                                        >
                                            <Icon className="size-3.5" />
                                        </span>
                                        <span className="min-w-0">
                                            <span className="font-medium whitespace-nowrap">
                                                {tab.title}
                                            </span>
                                            <span className="mt-0.5 hidden text-xs leading-snug opacity-75 lg:block">
                                                {tab.description}
                                            </span>
                                        </span>
                                    </Link>
                                );
                            })}
                        </div>
                    ))}
                </nav>

                <div className="min-w-0 flex-1">
                    <section
                        className={cn(
                            "flex flex-col gap-5",
                            // Backup & Restore, the oversight pages and the
                            // user manual lay their own cards, tables and
                            // screenshots out side by side, so they take the
                            // room the other settings pages leave for
                            // comfortable line lengths. The manual caps its own
                            // prose instead, which is why it asks for the width
                            // without turning into one long line.
                            isCurrentOrParentUrl(backupsIndex().url) ||
                                isCurrentOrParentUrl("/settings/security-scan") ||
                                isCurrentOrParentUrl("/settings/audit") ||
                                isCurrentOrParentUrl("/settings/manual")
                                ? "max-w-none"
                                : "max-w-3xl",
                        )}
                    >
                        {children}
                    </section>
                </div>
            </div>
        </div>
    );
}
