/**
 * Post-it scratchpad for the Today page. Colours are --color-jot-1..4.
 *
 * The point is to get a stray thought out of your head in one keystroke and
 * go straight back to the task — so adding is Enter, nothing asks a question,
 * and filing a jot somewhere proper (a task, a waiting-on item) is a later,
 * one-click decision rather than something you do mid-flow.
 */
import { useNavigate } from "@tanstack/react-router";
import { format, isToday } from "date-fns";
import { CheckSquare, Hourglass, X } from "lucide-react";
import { useLayoutEffect, useRef, useState } from "react";
import { toast } from "sonner";
import { cn } from "@/lib/cn";
import { useWorkspace } from "@/lib/store";
import type { ScratchNote } from "@/lib/types";

const COLORS: ScratchNote["color"][] = [1, 2, 3, 4];
const COLOR_NAMES = { 1: "yellow", 2: "green", 3: "blue", 4: "pink" } as const;
const bg = (c: ScratchNote["color"]) => ({ background: `var(--color-jot-${c})` });

/** First non-empty line becomes a title; the rest becomes the body. */
function split(text: string): { title: string; rest: string } {
  const lines = text.split("\n");
  const i = lines.findIndex((l) => l.trim());
  if (i < 0) return { title: "", rest: "" };
  const first = lines[i].trim();
  const title = first.length > 120 ? `${first.slice(0, 117)}…` : first;
  const rest = [first.length > 120 ? first : "", ...lines.slice(i + 1)].join("\n").trim();
  return { title, rest };
}

export function Scratchpad({ className }: { className?: string }) {
  const scratch = useWorkspace((s) => s.scratch);
  const addScratch = useWorkspace((s) => s.addScratch);
  const clearScratch = useWorkspace((s) => s.clearScratch);
  const restoreScratch = useWorkspace((s) => s.restoreScratch);
  const [draft, setDraft] = useState("");
  const [color, setColor] = useState<ScratchNote["color"]>(1);

  const notes = [...scratch].sort((a, b) => b.createdAt.localeCompare(a.createdAt));

  const stick = () => {
    if (!draft.trim()) return;
    addScratch(draft.trim(), color);
    setDraft("");
  };

  return (
    <section
      className={cn(
        "border border-line bg-surface rounded-md overflow-hidden flex flex-col",
        className,
      )}
      aria-label="Scratchpad"
    >
      <div className="flex items-center gap-3 px-3.5 py-2.5 border-b border-line bg-sunken">
        <h2 className="text-[13px] font-semibold">Scratchpad</h2>
        <span className="text-[12px] text-ink-3 tabular-nums">{notes.length || ""}</span>
        {notes.length > 0 ? (
          <button
            type="button"
            className="ml-auto text-[12px] text-ink-3 hover:text-ink"
            onClick={() => {
              if (!window.confirm(`Clear all ${notes.length} notes from the scratchpad?`)) return;
              const removed = clearScratch();
              toast(`Cleared ${removed.length} notes`, {
                action: { label: "Undo", onClick: () => restoreScratch(removed) },
              });
            }}
          >
            Clear
          </button>
        ) : null}
      </div>

      <div className="p-3 border-b border-line-hair">
        <textarea
          value={draft}
          onChange={(e) => setDraft(e.target.value)}
          onKeyDown={(e) => {
            if (e.key === "Enter" && !e.shiftKey && !e.nativeEvent.isComposing) {
              e.preventDefault();
              stick();
            }
            if (e.key === "Escape") (e.target as HTMLTextAreaElement).blur();
          }}
          rows={2}
          placeholder="Jot it down, get back to work…"
          aria-label="New scratchpad note"
          className="w-full resize-none rounded-md border border-line px-2.5 py-2 text-[13px] leading-snug text-ink placeholder:text-ink-3 outline-none focus:border-accent focus:shadow-[0_0_0_3px_var(--color-focus)]"
          style={bg(color)}
        />
        <div className="mt-1.5 flex items-center gap-2 text-[11px] text-ink-3">
          <span className="flex items-center gap-1.5 pl-0.5">
            {COLORS.map((c) => (
              <button
                key={c}
                type="button"
                aria-label={`New notes ${COLOR_NAMES[c]}`}
                aria-pressed={color === c}
                onClick={() => setColor(c)}
                className={cn(
                  "size-4 rounded-full border border-line-strong",
                  color === c && "border-ink-2 shadow-[0_0_0_2px_var(--color-focus)]",
                )}
                style={bg(c)}
              />
            ))}
          </span>
          <span className="ml-auto hidden sm:inline">Enter to stick · Shift+Enter new line</span>
        </div>
      </div>

      <ul className="flex-1 min-h-0 overflow-y-auto p-3 flex flex-col gap-2 bg-sunken max-h-[50vh] xl:max-h-none">
        {notes.length === 0 ? (
          <li className="px-2 py-6 text-center text-[12px] text-ink-3 leading-relaxed">
            Nothing jotted.
            <br />
            Catch the stray thought here instead of chasing it.
          </li>
        ) : (
          notes.map((n) => <Jot key={n.id} note={n} />)
        )}
      </ul>
    </section>
  );
}

function Jot({ note }: { note: ScratchNote }) {
  const navigate = useNavigate();
  const updateScratch = useWorkspace((s) => s.updateScratch);
  const removeScratch = useWorkspace((s) => s.removeScratch);
  const restoreScratch = useWorkspace((s) => s.restoreScratch);
  const addTask = useWorkspace((s) => s.addTask);
  const addWaiting = useWorkspace((s) => s.addWaiting);
  const ref = useRef<HTMLTextAreaElement>(null);

  // Grow to fit the text; a post-it that scrolls internally hides what you wrote.
  useLayoutEffect(() => {
    const el = ref.current;
    if (!el) return;
    el.style.height = "0px";
    el.style.height = `${el.scrollHeight}px`;
  }, [note.text]);

  const remove = (label: string) => {
    const removed = removeScratch(note.id);
    if (removed) {
      toast(label, { action: { label: "Undo", onClick: () => restoreScratch([removed]) } });
    }
  };

  const fileAs = (kind: "task" | "waiting") => {
    const { title, rest } = split(note.text);
    if (!title) return;
    if (kind === "task") {
      const id = addTask({ title, body: rest });
      removeScratch(note.id);
      toast("Moved to Tasks", {
        action: { label: "Open", onClick: () => void navigate({ to: "/tasks", search: { focus: id } }) },
      });
    } else {
      addWaiting({ title, notes: rest });
      removeScratch(note.id);
      toast("Moved to Waiting on", {
        action: { label: "Open", onClick: () => void navigate({ to: "/waiting" }) },
      });
    }
  };

  const when = new Date(note.createdAt);
  const stampText = isToday(when) ? format(when, "HH:mm") : format(when, "d MMM HH:mm");

  return (
    <li
      className="group rounded-sm border border-line-hair shadow-[0_1px_2px_rgb(0_0_0/0.06)] px-2.5 pt-2 pb-1.5"
      style={bg(note.color)}
    >
      <textarea
        ref={ref}
        value={note.text}
        onChange={(e) => updateScratch(note.id, { text: e.target.value })}
        onBlur={(e) => {
          // An emptied note has nothing worth undoing; just let it go.
          if (!e.target.value.trim()) removeScratch(note.id);
        }}
        onKeyDown={(e) => {
          if (e.key === "Escape") (e.target as HTMLTextAreaElement).blur();
        }}
        rows={1}
        aria-label="Scratchpad note"
        className="block w-full resize-none overflow-hidden bg-transparent text-[13px] leading-snug text-ink outline-none"
      />
      <div className="mt-1 flex items-center gap-1 text-[11px] text-ink-3">
        <time dateTime={note.createdAt} className="tabular-nums">
          {stampText}
        </time>
        {/* Controls stay quiet until you reach for a note, so the pad reads as notes, not buttons. */}
        <span className="ml-auto flex items-center gap-0.5 opacity-100 xl:opacity-0 xl:group-hover:opacity-100 xl:group-focus-within:opacity-100 transition-opacity">
          {COLORS.filter((c) => c !== note.color).map((c) => (
            <button
              key={c}
              type="button"
              aria-label={`Make ${COLOR_NAMES[c]}`}
              title={COLOR_NAMES[c]}
              onClick={() => updateScratch(note.id, { color: c })}
              className="size-3 rounded-full border border-line-strong mx-0.5"
              style={bg(c)}
            />
          ))}
          <button
            type="button"
            onClick={() => fileAs("task")}
            aria-label="Move to Tasks"
            title="Move to Tasks"
            className="size-6 inline-flex items-center justify-center rounded-xs hover:bg-surface/70 hover:text-ink"
          >
            <CheckSquare className="size-3.5" />
          </button>
          <button
            type="button"
            onClick={() => fileAs("waiting")}
            aria-label="Move to Waiting on"
            title="Move to Waiting on"
            className="size-6 inline-flex items-center justify-center rounded-xs hover:bg-surface/70 hover:text-ink"
          >
            <Hourglass className="size-3.5" />
          </button>
          <button
            type="button"
            onClick={() => remove("Note removed")}
            aria-label="Delete note"
            title="Delete"
            className="size-6 inline-flex items-center justify-center rounded-xs hover:bg-surface/70 hover:text-error"
          >
            <X className="size-3.5" />
          </button>
        </span>
      </div>
    </li>
  );
}
