"use client";

import * as React from "react";
import {
  AlertTriangle,
  BarChart3,
  CheckCircle2,
  Image as ImageIcon,
  Link2,
  ListChecks,
  ListTree,
  Sparkles,
  TableProperties,
} from "lucide-react";

import { Button } from "@/components/ui/button";
import { ScrollArea } from "@/components/ui/scroll-area";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
  Tabs,
  TabsContent,
  TabsList,
  TabsTrigger,
} from "@/components/ui/tabs";
import {
  type AdvancedStats,
  type Heading,
  type LintIssue,
  computeAdvancedStats,
  extractLinks,
  extractOutline,
  formatMarkdown,
  generateChecklist,
  generateTable,
  generateTableOfContents,
  lintMarkdown,
} from "@/lib/markdown";
import { formatNumber } from "@/lib/utils";

type Props = {
  value: string;
  onChange: (next: string) => void;
  onInsert: (snippet: string) => void;
  onJumpToLine: (line: number) => void;
};

export function ToolsSidebar({ value, onChange, onInsert, onJumpToLine }: Props) {
  const outline = React.useMemo(() => extractOutline(value), [value]);
  const lint = React.useMemo(() => lintMarkdown(value), [value]);
  const { links, images } = React.useMemo(() => extractLinks(value), [value]);
  const advanced = React.useMemo(() => computeAdvancedStats(value), [value]);

  return (
    <aside
      aria-label="Markdown tools"
      className="hidden h-full w-80 shrink-0 flex-col border-l border-border/60 bg-background lg:flex"
    >
      <Tabs defaultValue="outline" className="flex h-full flex-col">
        <div className="border-b border-border/60 p-2">
          <TabsList className="grid w-full grid-cols-5">
            <TabsTrigger value="outline" aria-label="Outline">
              <ListTree className="h-4 w-4" />
            </TabsTrigger>
            <TabsTrigger value="format" aria-label="Format and lint">
              <Sparkles className="h-4 w-4" />
            </TabsTrigger>
            <TabsTrigger value="insert" aria-label="Insert helpers">
              <TableProperties className="h-4 w-4" />
            </TabsTrigger>
            <TabsTrigger value="links" aria-label="Links and images">
              <Link2 className="h-4 w-4" />
            </TabsTrigger>
            <TabsTrigger value="stats" aria-label="Statistics">
              <BarChart3 className="h-4 w-4" />
            </TabsTrigger>
          </TabsList>
        </div>

        <ScrollArea className="flex-1">
          <TabsContent value="outline" className="m-0 p-3">
            <OutlinePanel
              headings={outline}
              onJump={onJumpToLine}
              onInsertToc={() => onInsert(`\n${generateTableOfContents(value)}\n`)}
            />
          </TabsContent>
          <TabsContent value="format" className="m-0 p-3">
            <FormatPanel value={value} onChange={onChange} issues={lint} onJump={onJumpToLine} />
          </TabsContent>
          <TabsContent value="insert" className="m-0 p-3">
            <InsertPanel onInsert={onInsert} />
          </TabsContent>
          <TabsContent value="links" className="m-0 p-3">
            <LinksPanel links={links} images={images} onJump={onJumpToLine} />
          </TabsContent>
          <TabsContent value="stats" className="m-0 p-3">
            <StatsPanel stats={advanced} />
          </TabsContent>
        </ScrollArea>
      </Tabs>
    </aside>
  );
}

function OutlinePanel({
  headings,
  onJump,
  onInsertToc,
}: {
  headings: Heading[];
  onJump: (line: number) => void;
  onInsertToc: () => void;
}) {
  if (headings.length === 0) {
    return (
      <p className="text-sm text-muted-foreground">
        Add headings to your document and they'll appear here as a navigable outline.
      </p>
    );
  }
  return (
    <div className="space-y-3">
      <Button size="sm" variant="outline" className="w-full" onClick={onInsertToc}>
        <ListTree className="h-4 w-4" /> Insert table of contents
      </Button>
      <nav aria-label="Document outline">
        <ul className="space-y-0.5 text-sm">
          {headings.map((h) => (
            <li key={`${h.line}-${h.id}`} style={{ paddingLeft: `${(h.level - 1) * 12}px` }}>
              <button
                type="button"
                onClick={() => onJump(h.line)}
                className="w-full truncate rounded-md px-2 py-1 text-left hover:bg-accent"
                title={h.text}
              >
                <span className="mr-1 text-xs text-muted-foreground">H{h.level}</span>
                {h.text}
              </button>
            </li>
          ))}
        </ul>
      </nav>
    </div>
  );
}

function FormatPanel({
  value,
  onChange,
  issues,
  onJump,
}: {
  value: string;
  onChange: (next: string) => void;
  issues: LintIssue[];
  onJump: (line: number) => void;
}) {
  const issueCount = issues.length;
  return (
    <div className="space-y-3">
      <div className="rounded-lg border bg-card p-3">
        <div className="mb-2 text-sm font-medium">Beautify</div>
        <p className="mb-2 text-xs text-muted-foreground">
          Normalize whitespace, headings, list bullets, and task markers.
        </p>
        <Button size="sm" className="w-full" onClick={() => onChange(formatMarkdown(value))}>
          <Sparkles className="h-4 w-4" /> Format markdown
        </Button>
      </div>

      <div className="rounded-lg border bg-card p-3">
        <div className="mb-2 flex items-center justify-between">
          <div className="text-sm font-medium">Lint</div>
          {issueCount === 0 ? (
            <span className="inline-flex items-center gap-1 text-xs text-emerald-500">
              <CheckCircle2 className="h-3.5 w-3.5" /> All good
            </span>
          ) : (
            <span className="inline-flex items-center gap-1 text-xs text-amber-500">
              <AlertTriangle className="h-3.5 w-3.5" /> {issueCount} issue{issueCount > 1 ? "s" : ""}
            </span>
          )}
        </div>
        <ul className="space-y-1 text-xs">
          {issues.map((issue, i) => (
            <li key={i}>
              <button
                type="button"
                onClick={() => onJump(issue.line)}
                className="w-full rounded-md px-2 py-1 text-left hover:bg-accent"
              >
                <span className="mr-1 font-mono text-muted-foreground">L{issue.line}</span>
                <span className="text-foreground">{issue.message}</span>
                <span className="ml-1 text-muted-foreground">({issue.rule})</span>
              </button>
            </li>
          ))}
        </ul>
        {issueCount > 0 ? (
          <Button
            size="sm"
            variant="outline"
            className="mt-2 w-full"
            onClick={() => onChange(formatMarkdown(value))}
          >
            Auto-fix common issues
          </Button>
        ) : null}
      </div>
    </div>
  );
}

function InsertPanel({ onInsert }: { onInsert: (snippet: string) => void }) {
  const [rows, setRows] = React.useState(3);
  const [cols, setCols] = React.useState(3);
  const [items, setItems] = React.useState("Plan project\nWrite draft\nReview and ship");

  return (
    <div className="space-y-3">
      <div className="rounded-lg border bg-card p-3">
        <div className="mb-2 flex items-center gap-2 text-sm font-medium">
          <TableProperties className="h-4 w-4" /> Table generator
        </div>
        <div className="mb-3 grid grid-cols-2 gap-2">
          <div className="space-y-1">
            <Label htmlFor="rows" className="text-xs">
              Rows
            </Label>
            <Input
              id="rows"
              type="number"
              min={1}
              max={50}
              value={rows}
              onChange={(e) => setRows(Math.max(1, Math.min(50, Number(e.target.value) || 1)))}
            />
          </div>
          <div className="space-y-1">
            <Label htmlFor="cols" className="text-xs">
              Columns
            </Label>
            <Input
              id="cols"
              type="number"
              min={1}
              max={10}
              value={cols}
              onChange={(e) => setCols(Math.max(1, Math.min(10, Number(e.target.value) || 1)))}
            />
          </div>
        </div>
        <Button
          size="sm"
          className="w-full"
          onClick={() => onInsert(`\n${generateTable(rows, cols)}\n`)}
        >
          Insert table
        </Button>
      </div>

      <div className="rounded-lg border bg-card p-3">
        <div className="mb-2 flex items-center gap-2 text-sm font-medium">
          <ListChecks className="h-4 w-4" /> Checklist generator
        </div>
        <Label htmlFor="checklist" className="sr-only">
          One item per line
        </Label>
        <textarea
          id="checklist"
          value={items}
          onChange={(e) => setItems(e.target.value)}
          rows={4}
          className="scrollbar-thin mb-2 w-full rounded-md border border-input bg-background p-2 text-xs"
          placeholder="One item per line"
        />
        <Button
          size="sm"
          className="w-full"
          onClick={() => onInsert(`\n${generateChecklist(items.split("\n"))}\n`)}
        >
          Insert checklist
        </Button>
      </div>
    </div>
  );
}

function LinksPanel({
  links,
  images,
  onJump,
}: {
  links: { url: string; line: number; label?: string }[];
  images: { url: string; line: number; label?: string }[];
  onJump: (line: number) => void;
}) {
  const [running, setRunning] = React.useState(false);
  const [results, setResults] = React.useState<Record<string, "ok" | "bad" | "skip">>({});

  async function check(urls: string[]) {
    setRunning(true);
    const next: Record<string, "ok" | "bad" | "skip"> = {};
    await Promise.all(
      urls.map(async (url) => {
        if (!/^https?:\/\//i.test(url)) {
          next[url] = "skip";
          return;
        }
        try {
          await fetch(url, { mode: "no-cors", cache: "no-store" });
          next[url] = "ok";
        } catch {
          next[url] = "bad";
        }
      }),
    );
    setResults((prev) => ({ ...prev, ...next }));
    setRunning(false);
  }

  return (
    <div className="space-y-3 text-sm">
      <Section
        title="Links"
        icon={<Link2 className="h-4 w-4" />}
        empty="No links in this document."
        items={links}
        results={results}
        onJump={onJump}
        onCheck={() => check(links.map((l) => l.url))}
        running={running}
      />
      <Section
        title="Images"
        icon={<ImageIcon className="h-4 w-4" />}
        empty="No images in this document."
        items={images}
        results={results}
        onJump={onJump}
        onCheck={() => check(images.map((l) => l.url))}
        running={running}
      />
    </div>
  );
}

function Section({
  title,
  icon,
  empty,
  items,
  results,
  onJump,
  onCheck,
  running,
}: {
  title: string;
  icon: React.ReactNode;
  empty: string;
  items: { url: string; line: number; label?: string }[];
  results: Record<string, "ok" | "bad" | "skip">;
  onJump: (line: number) => void;
  onCheck: () => void;
  running: boolean;
}) {
  return (
    <div className="rounded-lg border bg-card p-3">
      <div className="mb-2 flex items-center justify-between">
        <div className="flex items-center gap-2 text-sm font-medium">
          {icon} {title}{" "}
          <span className="text-muted-foreground">({items.length})</span>
        </div>
        <Button
          size="sm"
          variant="outline"
          disabled={running || items.length === 0}
          onClick={onCheck}
        >
          {running ? "Checking…" : "Check"}
        </Button>
      </div>
      {items.length === 0 ? (
        <p className="text-xs text-muted-foreground">{empty}</p>
      ) : (
        <ul className="space-y-1">
          {items.map((item, i) => {
            const status = results[item.url];
            return (
              <li key={`${item.url}-${i}`}>
                <button
                  type="button"
                  onClick={() => onJump(item.line)}
                  className="w-full rounded-md px-2 py-1 text-left hover:bg-accent"
                >
                  <div className="flex items-center justify-between gap-2">
                    <span className="truncate text-xs">{item.url}</span>
                    {status === "ok" ? (
                      <CheckCircle2 className="h-3.5 w-3.5 shrink-0 text-emerald-500" />
                    ) : status === "bad" ? (
                      <AlertTriangle className="h-3.5 w-3.5 shrink-0 text-amber-500" />
                    ) : null}
                  </div>
                  {item.label ? (
                    <div className="truncate text-[11px] text-muted-foreground">
                      {item.label} · L{item.line}
                    </div>
                  ) : (
                    <div className="text-[11px] text-muted-foreground">L{item.line}</div>
                  )}
                </button>
              </li>
            );
          })}
        </ul>
      )}
    </div>
  );
}

function StatsPanel({ stats }: { stats: AdvancedStats }) {
  return (
    <div className="space-y-3 text-sm">
      <div className="rounded-lg border bg-card p-3">
        <div className="mb-2 flex items-center gap-2 font-medium">
          <BarChart3 className="h-4 w-4" /> Readability
        </div>
        <div className="mb-2 flex items-end justify-between">
          <div className="text-3xl font-semibold tabular-nums">{stats.readabilityScore}</div>
          <div className="text-xs text-muted-foreground">{stats.readabilityLabel}</div>
        </div>
        <div
          className="h-1.5 w-full overflow-hidden rounded-full bg-muted"
          aria-hidden
          role="presentation"
        >
          <div
            className="h-full bg-primary transition-all"
            style={{ width: `${stats.readabilityScore}%` }}
          />
        </div>
        <p className="mt-2 text-[11px] text-muted-foreground">
          Flesch reading ease — higher is easier to read. Aim for 60–80 for general audiences.
        </p>
      </div>

      <div className="rounded-lg border bg-card p-3">
        <div className="mb-2 text-sm font-medium">Document</div>
        <dl className="grid grid-cols-2 gap-y-1 text-xs">
          <dt className="text-muted-foreground">Sentences</dt>
          <dd className="text-right tabular-nums">{formatNumber(stats.sentences)}</dd>
          <dt className="text-muted-foreground">Unique words</dt>
          <dd className="text-right tabular-nums">{formatNumber(stats.uniqueWords)}</dd>
          <dt className="text-muted-foreground">Avg sentence length</dt>
          <dd className="text-right tabular-nums">{stats.avgSentenceLength} w</dd>
          <dt className="text-muted-foreground">Avg word length</dt>
          <dd className="text-right tabular-nums">{stats.avgWordLength} c</dd>
          <dt className="text-muted-foreground">Longest word</dt>
          <dd className="truncate text-right">{stats.longestWord || "—"}</dd>
        </dl>
      </div>

      <div className="rounded-lg border bg-card p-3">
        <div className="mb-2 text-sm font-medium">Top words</div>
        {stats.topWords.length === 0 ? (
          <p className="text-xs text-muted-foreground">Write more to see common terms.</p>
        ) : (
          <ul className="space-y-1.5">
            {stats.topWords.map((w) => {
              const max = stats.topWords[0]?.count ?? 1;
              return (
                <li key={w.word} className="text-xs">
                  <div className="flex items-center justify-between">
                    <span>{w.word}</span>
                    <span className="tabular-nums text-muted-foreground">{w.count}</span>
                  </div>
                  <div
                    className="mt-1 h-1 w-full overflow-hidden rounded-full bg-muted"
                    aria-hidden
                  >
                    <div
                      className="h-full bg-primary/60"
                      style={{ width: `${Math.round((w.count / max) * 100)}%` }}
                    />
                  </div>
                </li>
              );
            })}
          </ul>
        )}
      </div>
    </div>
  );
}
