"use client";

import * as React from "react";
import {
  AlignCenter,
  AlignLeft,
  AlignRight,
  ArrowLeftRight,
  Copy,
  Minus,
  Plus,
  RotateCcw,
} from "lucide-react";

import { Button } from "@/components/ui/button";
import { MarkdownPreview } from "@/components/editor/markdown-preview";
import { useToast } from "@/hooks/use-toast";
import { cn } from "@/lib/utils";

type Align = "left" | "center" | "right";

type State = {
  rows: number;
  cols: number;
  aligns: Align[];
  headers: string[];
  cells: string[][];
};

const DEFAULT: State = {
  rows: 3,
  cols: 3,
  aligns: ["left", "center", "left"],
  headers: ["Feature", "Status", "Notes"],
  cells: [
    ["Tables", "Stable", "Aligns left, center, right"],
    ["Task lists", "Stable", "GFM extension"],
    ["Math", "New", "Powered by KaTeX"],
  ],
};

function buildMarkdown(state: State): string {
  const align = (a: Align) =>
    a === "center" ? ":---:" : a === "right" ? "---:" : ":---";
  const headerRow = `| ${state.headers.join(" | ")} |`;
  const alignRow = `| ${state.aligns.map(align).join(" | ")} |`;
  const bodyRows = state.cells.map((row) => `| ${row.join(" | ")} |`);
  return [headerRow, alignRow, ...bodyRows].join("\n");
}

function resize(state: State, rows: number, cols: number): State {
  const headers = Array.from({ length: cols }, (_, c) => state.headers[c] ?? `Column ${c + 1}`);
  const aligns = Array.from({ length: cols }, (_, c) => state.aligns[c] ?? "left");
  const cells = Array.from({ length: rows }, (_, r) =>
    Array.from({ length: cols }, (_, c) => state.cells[r]?.[c] ?? ""),
  );
  return { rows, cols, headers, aligns, cells };
}

export function MarkdownTableBuilder() {
  const { toast } = useToast();
  const [state, setState] = React.useState<State>(DEFAULT);

  const markdown = React.useMemo(() => buildMarkdown(state), [state]);

  function updateHeader(index: number, value: string) {
    setState((prev) => {
      const headers = [...prev.headers];
      headers[index] = value;
      return { ...prev, headers };
    });
  }
  function updateCell(r: number, c: number, value: string) {
    setState((prev) => {
      const cells = prev.cells.map((row) => [...row]);
      const rowCopy = cells[r] ?? [];
      rowCopy[c] = value;
      cells[r] = rowCopy;
      return { ...prev, cells };
    });
  }
  function setAlign(c: number, align: Align) {
    setState((prev) => {
      const aligns = [...prev.aligns];
      aligns[c] = align;
      return { ...prev, aligns };
    });
  }
  function setSize(rows: number, cols: number) {
    setState((prev) => resize(prev, Math.max(1, Math.min(50, rows)), Math.max(1, Math.min(10, cols))));
  }

  async function copyMd() {
    await navigator.clipboard.writeText(markdown);
    toast({ title: "Markdown table copied" });
  }
  function reset() {
    setState(DEFAULT);
    toast({ title: "Reset to default table" });
  }
  function transpose() {
    setState((prev) => {
      const newRows = prev.cols;
      const newCols = prev.rows + 1; // header becomes a column
      const allRows = [prev.headers, ...prev.cells];
      const transposedCells: string[][] = Array.from({ length: newRows }, (_, r) =>
        Array.from({ length: newCols }, (_, c) => allRows[c]?.[r] ?? ""),
      );
      const headers = Array.from({ length: newCols }, (_, c) => (c === 0 ? "Field" : `Row ${c}`));
      const aligns: Align[] = Array.from({ length: newCols }, () => "left");
      return { rows: newRows, cols: newCols, headers, aligns, cells: transposedCells };
    });
  }

  return (
    <section className="container max-w-6xl py-10">
      <div className="mb-4 flex flex-wrap items-center justify-between gap-3">
        <div className="flex items-center gap-3 text-xs">
          <Stepper
            label="Rows"
            value={state.rows}
            min={1}
            max={50}
            onChange={(v) => setSize(v, state.cols)}
          />
          <Stepper
            label="Cols"
            value={state.cols}
            min={1}
            max={10}
            onChange={(v) => setSize(state.rows, v)}
          />
        </div>
        <div className="flex flex-wrap items-center gap-2">
          <Button size="sm" variant="outline" onClick={transpose}>
            <ArrowLeftRight className="h-3.5 w-3.5" /> Transpose
          </Button>
          <Button size="sm" variant="outline" onClick={reset}>
            <RotateCcw className="h-3.5 w-3.5" /> Reset
          </Button>
          <Button size="sm" onClick={copyMd}>
            <Copy className="h-3.5 w-3.5" /> Copy markdown
          </Button>
        </div>
      </div>

      <div className="overflow-x-auto rounded-xl border bg-card">
        <table className="w-full border-collapse text-sm">
          <thead>
            <tr className="border-b">
              {state.headers.map((header, c) => (
                <th key={c} className="min-w-[140px] border-r p-0 align-top last:border-r-0">
                  <div className="flex items-center gap-1 border-b border-border/50 px-2 py-1 text-[10px] uppercase tracking-wider text-muted-foreground">
                    <span>Column {c + 1}</span>
                    <div className="ml-auto flex items-center gap-0.5">
                      <AlignButton
                        active={state.aligns[c] === "left"}
                        onClick={() => setAlign(c, "left")}
                        label="Left"
                      >
                        <AlignLeft className="h-3 w-3" />
                      </AlignButton>
                      <AlignButton
                        active={state.aligns[c] === "center"}
                        onClick={() => setAlign(c, "center")}
                        label="Center"
                      >
                        <AlignCenter className="h-3 w-3" />
                      </AlignButton>
                      <AlignButton
                        active={state.aligns[c] === "right"}
                        onClick={() => setAlign(c, "right")}
                        label="Right"
                      >
                        <AlignRight className="h-3 w-3" />
                      </AlignButton>
                    </div>
                  </div>
                  <input
                    value={header}
                    onChange={(e) => updateHeader(c, e.target.value)}
                    className={cn(
                      "w-full bg-background px-3 py-2 text-sm font-semibold outline-none focus:bg-accent/50",
                      state.aligns[c] === "center" && "text-center",
                      state.aligns[c] === "right" && "text-right",
                    )}
                    aria-label={`Header for column ${c + 1}`}
                  />
                </th>
              ))}
            </tr>
          </thead>
          <tbody>
            {state.cells.map((row, r) => (
              <tr key={r} className="border-b last:border-b-0">
                {row.map((cell, c) => (
                  <td key={c} className="border-r p-0 last:border-r-0">
                    <input
                      value={cell}
                      onChange={(e) => updateCell(r, c, e.target.value)}
                      className={cn(
                        "w-full bg-background px-3 py-2 text-sm outline-none focus:bg-accent/50",
                        state.aligns[c] === "center" && "text-center",
                        state.aligns[c] === "right" && "text-right",
                      )}
                      aria-label={`Row ${r + 1} column ${c + 1}`}
                    />
                  </td>
                ))}
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      <div className="mt-6 grid gap-4 lg:grid-cols-2">
        <div className="overflow-hidden rounded-xl border bg-card">
          <div className="flex items-center justify-between border-b px-3 py-2 text-xs uppercase tracking-wider text-muted-foreground">
            <span>Markdown</span>
            <Button size="sm" variant="ghost" className="h-6 px-2 text-xs" onClick={copyMd}>
              <Copy className="h-3 w-3" /> Copy
            </Button>
          </div>
          <pre className="scrollbar-thin max-h-72 overflow-auto p-4 font-mono text-xs leading-relaxed">
            {markdown}
          </pre>
        </div>
        <div className="overflow-hidden rounded-xl border bg-card">
          <div className="border-b px-3 py-2 text-xs uppercase tracking-wider text-muted-foreground">
            Preview
          </div>
          <div className="scrollbar-thin max-h-72 overflow-auto p-4">
            <MarkdownPreview source={markdown} enableExtras={false} safeLinks={false} />
          </div>
        </div>
      </div>
    </section>
  );
}

function Stepper({
  label,
  value,
  min,
  max,
  onChange,
}: {
  label: string;
  value: number;
  min: number;
  max: number;
  onChange: (v: number) => void;
}) {
  return (
    <div className="inline-flex items-center gap-1 rounded-md border bg-card px-1 py-0.5">
      <span className="px-1 text-[11px] uppercase tracking-wider text-muted-foreground">
        {label}
      </span>
      <button
        type="button"
        onClick={() => onChange(Math.max(min, value - 1))}
        className="rounded p-0.5 text-muted-foreground hover:bg-accent"
        aria-label={`Decrease ${label}`}
      >
        <Minus className="h-3 w-3" />
      </button>
      <span className="min-w-[1.5rem] text-center text-xs tabular-nums">{value}</span>
      <button
        type="button"
        onClick={() => onChange(Math.min(max, value + 1))}
        className="rounded p-0.5 text-muted-foreground hover:bg-accent"
        aria-label={`Increase ${label}`}
      >
        <Plus className="h-3 w-3" />
      </button>
    </div>
  );
}

function AlignButton({
  active,
  onClick,
  label,
  children,
}: {
  active: boolean;
  onClick: () => void;
  label: string;
  children: React.ReactNode;
}) {
  return (
    <button
      type="button"
      onClick={onClick}
      aria-pressed={active}
      aria-label={`Align ${label}`}
      title={`Align ${label}`}
      className={cn(
        "rounded p-1 text-muted-foreground hover:bg-accent",
        active && "bg-accent text-foreground",
      )}
    >
      {children}
    </button>
  );
}
