import { useMemo, useState } from 'react';
import type { Campaign, Note } from '@/lib/schemas';
import { notesRepo } from '@/lib/db/repositories';
import { useDebouncedCallback } from '@/lib/useDebouncedCallback';
import { extractWikiLinks, splitWikiLinks } from '@/lib/wikilinks';
import { useNotes } from './hooks';
import { Page, PageHeader, EmptyState, RequireCampaign } from '@/components/ui/Page';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
import { cn } from '@/lib/cn';

export function NotesPage() {
  return <RequireCampaign>{(c) => <Notes campaign={c} />}</RequireCampaign>;
}

function Notes({ campaign }: { campaign: Campaign }) {
  const notes = useNotes(campaign.id);
  const [selectedId, setSelectedId] = useState<string | null>(null);
  const [query, setQuery] = useState('');

  const selected = notes.find((n) => n.id === selectedId) ?? null;
  const filtered = useMemo(() => {
    const q = query.trim().toLowerCase();
    const list = q
      ? notes.filter((n) => n.title.toLowerCase().includes(q) || n.body.toLowerCase().includes(q) || n.tags.some((t) => t.toLowerCase().includes(q)))
      : notes;
    return [...list].sort((a, b) => a.title.localeCompare(b.title));
  }, [notes, query]);

  const createNote = async (title = 'Untitled') => {
    const note = await notesRepo.create(campaign.id, title);
    setSelectedId(note.id);
  };

  const openByTitle = async (title: string) => {
    const existing = notes.find((n) => n.title.toLowerCase() === title.toLowerCase());
    if (existing) setSelectedId(existing.id);
    else await createNote(title);
  };

  return (
    <Page>
      <PageHeader
        title="Notes & Wiki"
        subtitle={`${campaign.name} · link entries with [[double brackets]]`}
        actions={<Button variant="primary" onClick={() => createNote()}>+ New note</Button>}
      />

      {notes.length === 0 ? (
        <EmptyState
          title="No notes yet"
          hint="Capture lore, session recaps, and locations. Use [[wiki links]] to connect them."
          action={<Button variant="primary" onClick={() => createNote()}>+ New note</Button>}
        />
      ) : (
        <div className="grid gap-4 lg:grid-cols-[280px_1fr]">
          <div>
            <Input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search notes…" aria-label="Search notes" />
            <ul className="mt-2 max-h-[65vh] space-y-1 overflow-auto">
              {filtered.map((n) => (
                <li key={n.id}>
                  <button
                    onClick={() => setSelectedId(n.id)}
                    className={cn(
                      'w-full truncate rounded-md border px-3 py-2 text-left text-sm',
                      selected?.id === n.id ? 'border-accent bg-elevated' : 'border-line bg-panel hover:border-accent/40',
                    )}
                  >
                    {n.title}
                  </button>
                </li>
              ))}
            </ul>
          </div>

          {selected ? (
            <NoteEditor key={selected.id} note={selected} allNotes={notes} onOpenTitle={openByTitle} onSelect={setSelectedId} />
          ) : (
            <div className="rounded-lg border border-line bg-panel p-5 text-sm text-muted">Select a note to edit.</div>
          )}
        </div>
      )}
    </Page>
  );
}

function NoteEditor({
  note,
  allNotes,
  onOpenTitle,
  onSelect,
}: {
  note: Note;
  allNotes: Note[];
  onOpenTitle: (title: string) => void;
  onSelect: (id: string | null) => void;
}) {
  const [title, setTitle] = useState(note.title);
  const [body, setBody] = useState(note.body);
  const [tags, setTags] = useState(note.tags.join(', '));

  // Save the full snapshot so editing title + body quickly doesn't drop an edit.
  const save = useDebouncedCallback((next: { title: string; body: string; tags: string }) => {
    void notesRepo.update(note.id, {
      title: next.title,
      body: next.body,
      tags: next.tags.split(',').map((t) => t.trim()).filter(Boolean),
    });
  }, 350);
  const persist = (over: Partial<{ title: string; body: string; tags: string }>) =>
    save({ title, body, tags, ...over });

  const backlinks = allNotes.filter(
    (n) => n.id !== note.id && extractWikiLinks(n.body).some((t) => t.toLowerCase() === note.title.toLowerCase()),
  );
  const titlesLower = new Set(allNotes.map((n) => n.title.toLowerCase()));

  return (
    <div className="rounded-lg border border-line bg-panel p-4">
      <div className="mb-3 flex items-center gap-2">
        <Input
          className="font-display text-lg font-semibold"
          value={title}
          aria-label="Note title"
          onChange={(e) => { setTitle(e.target.value); persist({ title: e.target.value }); }}
        />
        <Button
          variant="ghost"
          className="text-danger"
          onClick={async () => { await notesRepo.remove(note.id); onSelect(null); }}
        >
          Delete
        </Button>
      </div>

      <label className="mb-3 block text-xs text-muted">
        Tags (comma-separated)
        <Input
          value={tags}
          onChange={(e) => { setTags(e.target.value); persist({ tags: e.target.value }); }}
          placeholder="lore, barovia, npc"
        />
      </label>

      <textarea
        value={body}
        onChange={(e) => { setBody(e.target.value); persist({ body: e.target.value }); }}
        placeholder="Write here… link other notes with [[Note Title]]."
        className="min-h-48 w-full resize-y rounded-md border border-line bg-surface px-3 py-2 text-sm text-ink focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent/60"
      />

      {/* Rendered preview with clickable links */}
      <div className="mt-4">
        <h3 className="mb-1 text-xs font-semibold uppercase tracking-wide text-muted">Preview</h3>
        <p className="whitespace-pre-wrap rounded-md border border-line bg-surface p-3 text-sm text-ink">
          {splitWikiLinks(body).map((part, i) =>
            part.link ? (
              <button
                key={i}
                onClick={() => onOpenTitle(part.link!)}
                className={cn('underline', titlesLower.has(part.link.toLowerCase()) ? 'text-accent' : 'text-warning')}
                title={titlesLower.has(part.link.toLowerCase()) ? 'Open note' : 'Create this note'}
              >
                {part.text}
              </button>
            ) : (
              <span key={i}>{part.text}</span>
            ),
          )}
        </p>
      </div>

      {backlinks.length > 0 && (
        <div className="mt-4">
          <h3 className="mb-1 text-xs font-semibold uppercase tracking-wide text-muted">Linked from</h3>
          <div className="flex flex-wrap gap-1">
            {backlinks.map((n) => (
              <button key={n.id} onClick={() => onSelect(n.id)} className="rounded-md border border-line bg-surface px-2 py-1 text-xs text-ink hover:border-accent/40">
                {n.title}
              </button>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}
