import { Head } from '@inertiajs/react';
import {
    BookOpen,
    ChevronDown,
    Download,
    ListTree,
    Search,
} from 'lucide-react';
import { useMemo, useState } from 'react';
import { PageHeader } from '@/components/crm/page-header';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';

type Chapter = {
    id: string;
    title: string;
};

type Part = {
    /** null for chapters that sit before the first part. */
    title: string | null;
    chapters: Chapter[];
};

type Props = {
    html: string;
    contents: Part[];
    summary: {
        chapters: number;
        screenshots: number;
        updated: string | null;
    };
    pdfUrl: string;
};

/**
 * The chapter list, drawn either in the column beside the manual or inside the
 * disclosure that stands in for it on a narrow screen.
 */
function ChapterList({ parts, filter }: { parts: Part[]; filter: string }) {
    return (
        <div className="grid gap-4 pb-2">
            {parts.map((part, index) => (
                <div key={`${part.title ?? 'start'}-${index}`}>
                    {part.title ? (
                        <p className="mb-1.5 px-1 crm-label">{part.title}</p>
                    ) : null}

                    <ul className="grid gap-0.5">
                        {part.chapters.map((chapter) => (
                            <li key={chapter.id}>
                                <a
                                    href={`#${chapter.id}`}
                                    className="block rounded-md px-2 py-1.5 text-sm text-muted-foreground transition-colors hover:bg-accent/60 hover:text-foreground"
                                >
                                    {chapter.title}
                                </a>
                            </li>
                        ))}
                    </ul>
                </div>
            ))}

            {parts.length === 0 ? (
                <p className="px-1 text-sm text-muted-foreground">
                    No chapter matches “{filter}”.
                </p>
            ) : null}
        </div>
    );
}

/**
 * The user manual, in the application.
 *
 * The words are Markdown in the repository, converted on the server; this page
 * is the reading frame around them — a chapter list for when somebody knows
 * what they are looking for, and the PDF for somebody who wants it on paper or
 * on a phone with no signal.
 *
 * The card is given the full width of the settings area, because a screenshot
 * of a CRM screen is worthless at half size. The prose is not: `.manual-prose`
 * in app.css caps the words at a readable measure while letting the pictures,
 * tables and command examples use all of the room.
 *
 * The article is rendered as markup because it is generated from a file in
 * this repository, never from anything a user typed. That is the difference
 * between this and a ticket description, which has to be sanitised first.
 */
export default function Manual({ html, contents, summary, pdfUrl }: Props) {
    const [filter, setFilter] = useState('');

    const parts = useMemo(() => {
        const term = filter.trim().toLowerCase();

        if (term === '') {
            return contents;
        }

        return contents
            .map((part) => ({
                ...part,
                chapters: part.chapters.filter((chapter) =>
                    chapter.title.toLowerCase().includes(term),
                ),
            }))
            .filter((part) => part.chapters.length > 0);
    }, [contents, filter]);

    const searchInput = (
        <div className="relative">
            <Search className="pointer-events-none absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-foreground" />
            <Input
                value={filter}
                onChange={(event) => setFilter(event.target.value)}
                placeholder="Find a chapter"
                aria-label="Find a chapter"
                className="h-9 pl-8"
            />
        </div>
    );

    return (
        <>
            <Head title="User manual" />

            <PageHeader
                eyebrow={
                    <>
                        <BookOpen className="size-3.5" />
                        Help
                    </>
                }
                title="User manual"
                description={`${summary.chapters} chapters and ${summary.screenshots} screenshots covering every screen in the system, with step-by-step walkthroughs${
                    summary.updated ? ` · updated ${summary.updated}` : ''
                }.`}
                actions={
                    <Button asChild>
                        <a href={pdfUrl}>
                            <Download className="size-4" />
                            Download PDF
                        </a>
                    </Button>
                }
            />

            <div className="mt-6 grid gap-6 2xl:grid-cols-[15rem_minmax(0,1fr)] 2xl:items-start">
                {/* The settings tabs are already a column, so a second sticky
                    column below 2xl would leave the document narrower than on
                    a phone. The chapters fold away into one disclosure until
                    there is room for both. */}
                <details className="group rounded-xl bg-card shadow-card ring-1 ring-hairline 2xl:hidden">
                    <summary className="flex cursor-pointer list-none items-center gap-2 px-4 py-3 text-sm font-medium [&::-webkit-details-marker]:hidden">
                        <ListTree className="size-4 text-muted-foreground" />
                        Chapters
                        <span className="text-muted-foreground crm-num">
                            {summary.chapters}
                        </span>
                        <ChevronDown className="ml-auto size-4 text-muted-foreground transition-transform group-open:rotate-180" />
                    </summary>

                    <div className="border-t border-hairline p-3">
                        {searchInput}
                        <div className="mt-3">
                            <ChapterList parts={parts} filter={filter} />
                        </div>
                    </div>
                </details>

                <nav
                    aria-label="Manual chapters"
                    className="hidden crm-scroll 2xl:sticky 2xl:top-20 2xl:block 2xl:max-h-[calc(100vh-6rem)] 2xl:overflow-y-auto 2xl:pr-1"
                >
                    {searchInput}
                    <div className="mt-3">
                        <ChapterList parts={parts} filter={filter} />
                    </div>
                </nav>

                <article className="manual-prose min-w-0 rounded-xl bg-card p-5 text-card-foreground shadow-card ring-1 ring-hairline sm:p-6 lg:p-8">
                    <div dangerouslySetInnerHTML={{ __html: html }} />

                    <p className="mt-10 max-w-[48rem] border-t border-hairline pt-4 text-xs text-muted-foreground">
                        Something here out of date? Tell an administrator, so
                        the paragraph and the screen change together.
                    </p>
                </article>
            </div>
        </>
    );
}

Manual.layout = {
    breadcrumbs: [
        {
            title: 'User manual',
            href: '/settings/manual',
        },
    ],
};
