"use client";

import { useCallback, useEffect, useMemo, useState } from "react";
import { useRouter, useSearchParams } from "next/navigation";
import Link from "next/link";
import {
  BookOpen,
  FileText,
  Folder,
  Hash,
  LayoutGrid,
  List as ListIcon,
  Pin,
  Plus,
  Search,
  SortAsc,
  Sparkles,
  X,
} from "lucide-react";
import { NoteCard } from "@/components/notes/note-card";
import { NoteListRow } from "@/components/notes/note-list-row";
import { FolderTree } from "@/components/notes/folder-tree";
import { NoteTree, type NoteTreeNode } from "@/components/notes/note-tree";
import { NoteTemplateGallery } from "@/components/notes/note-template-gallery";
import { SavedViewsBar } from "@/components/tasks/saved-views-bar";
import { useNotes, type NoteWithRelations } from "@/hooks/use-notes";
import { useSavedViews } from "@/hooks/use-saved-views";
import { useTeamPermissions } from "@/hooks/use-team-permissions";
import { useNoteTemplates } from "@/hooks/use-note-templates";
import { cn } from "@/lib/utils";

// Extract plain text from Tiptap ProseMirror JSON for full-text search
function extractText(node: unknown): string {
  if (!node || typeof node !== "object") return "";
  const n = node as Record<string, unknown>;
  if (n.type === "text" && typeof n.text === "string") return n.text;
  if (Array.isArray(n.content)) return (n.content as unknown[]).map(extractText).join(" ");
  return "";
}

type NoteFilterValues = {
  search: string;
  folderId: string;
  pinState: string;
};

const EMPTY_FILTERS: NoteFilterValues = {
  search: "",
  folderId: "",
  pinState: "",
};

const BUILT_IN_VIEWS = [
  { id: "all", label: "All notes", filters: {} },
  { id: "pinned", label: "Pinned", filters: { pinState: "pinned" } },
  { id: "unfiled", label: "No folder", filters: { folderId: "__none__" } },
] satisfies Array<{ id: string; label: string; filters: Partial<NoteFilterValues> }>;

export default function NotesPage() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const {
    notes,
    folders,
    loading,
    createNote,
    deleteNote,
    togglePin,
    createFolder,
    renameFolder,
    deleteFolder,
  } = useNotes();
  const { views, createView, updateView, deleteView } = useSavedViews("notes");
  const { getTemplate } = useNoteTemplates();
  const { can } = useTeamPermissions();
  const canEditNotes = can("notes", "edit");

  const [filters, setFilters] = useState<NoteFilterValues>(EMPTY_FILTERS);
  const [showFolderSidebar, setShowFolderSidebar] = useState(true);
  const [sortBy, setSortBy] = useState<"updated" | "created" | "name">("updated");
  const [viewMode, setViewMode] = useState<"grid" | "list">("list");
  const [expandedNoteIds, setExpandedNoteIds] = useState<Set<string>>(new Set());

  const selectedFolderId =
    filters.folderId && filters.folderId !== "__none__" ? filters.folderId : null;

  const handleCreate = useCallback(async (templateId?: string) => {
    const folderId = filters.folderId && filters.folderId !== "__none__" ? filters.folderId : null;
    const template = getTemplate(templateId);
    const note = await createNote({
      folder_id: folderId,
      title: template?.name,
      content: template?.content,
      cover_id: template?.coverId,
      source_template_id: template?.id,
      source_template_price_cents: template?.price,
    });
    router.push(`/notes/${note.id}`);
  }, [createNote, filters.folderId, getTemplate, router]);

  const handleCreateSubPage = useCallback(async (parent: NoteWithRelations) => {
    const note = await createNote({
      parent_note_id: parent.id,
      folder_id: parent.folder_id,
      project_id: parent.project_id,
    });
    router.push(`/notes/${note.id}`);
  }, [createNote, router]);

  useEffect(() => {
    const savedViewId = searchParams.get("savedView");
    if (!savedViewId || views.length === 0) return;

    const matchedView = views.find((view) => view.id === savedViewId);
    if (!matchedView) return;

    const timer = window.setTimeout(() => {
      setFilters({
        ...EMPTY_FILTERS,
        ...Object.fromEntries(
          Object.entries(matchedView.filters).filter(([, value]) => typeof value === "string")
        ),
      });
    }, 0);

    return () => window.clearTimeout(timer);
  }, [searchParams, views]);

  useEffect(() => {
    const shouldCreate = searchParams.get("create");
    if (shouldCreate !== "1") return;

    const nextParams = new URLSearchParams(searchParams.toString());
    nextParams.delete("create");
    const nextQuery = nextParams.toString();
    router.replace(nextQuery ? `/notes?${nextQuery}` : "/notes", { scroll: false });

    if (canEditNotes) {
      void handleCreate();
    }
  }, [canEditNotes, handleCreate, router, searchParams]);

  /* ── Filter + sort — single source of truth, no duplicate sections ──────── */
  const filtered = useMemo(() => {
    let result = [...notes];

    // Folder filter
    if (filters.folderId === "__none__") {
      result = result.filter((n) => n.folder_id === null);
    } else if (filters.folderId) {
      result = result.filter((n) => n.folder_id === filters.folderId);
    }

    // Pin filter
    if (filters.pinState === "pinned") {
      result = result.filter((n) => n.is_pinned);
    }

    // Full-text search — title + note content
    if (filters.search.trim()) {
      const q = filters.search.toLowerCase();
      result = result.filter((n) => {
        if (n.title.toLowerCase().includes(q)) return true;
        const bodyText = extractText(n.content).toLowerCase();
        return bodyText.includes(q);
      });
    }

    // Sort
    if (sortBy === "updated") {
      result.sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime());
    } else if (sortBy === "created") {
      result.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime());
    } else {
      result.sort((a, b) => a.title.localeCompare(b.title));
    }

    return result;
  }, [filters, notes, sortBy]);

  const pinnedNotes = useMemo(() => notes.filter((n) => n.is_pinned), [notes]);

  const folderById = useMemo(() => new Map(folders.map((f) => [f.id, f])), [folders]);

  // List view shows sub-pages nested under their parent, Notion-style —
  // collapsed by default, toggled per note via expandedNoteIds.
  const listRows = useMemo(() => {
    const filteredIds = new Set(filtered.map((n) => n.id));
    const byParent = new Map<string, NoteWithRelations[]>();

    filtered.forEach((n) => {
      if (n.parent_note_id && filteredIds.has(n.parent_note_id)) {
        const siblings = byParent.get(n.parent_note_id) || [];
        siblings.push(n);
        byParent.set(n.parent_note_id, siblings);
      }
    });

    const rows: { note: NoteWithRelations; depth: number; hasChildren: boolean }[] = [];

    function walk(note: NoteWithRelations, depth: number) {
      const children = byParent.get(note.id);
      rows.push({ note, depth, hasChildren: !!children });
      if (children && expandedNoteIds.has(note.id)) {
        children.forEach((child) => walk(child, depth + 1));
      }
    }

    filtered
      .filter((n) => !(n.parent_note_id && filteredIds.has(n.parent_note_id)))
      .forEach((n) => walk(n, 0));

    return rows;
  }, [filtered, expandedNoteIds]);

  const toggleNoteExpanded = useCallback((noteId: string) => {
    setExpandedNoteIds((prev) => {
      const next = new Set(prev);
      if (next.has(noteId)) {
        next.delete(noteId);
      } else {
        next.add(noteId);
      }
      return next;
    });
  }, []);

  const noteCountByFolder = useMemo(() => {
    const counts: Record<string, number> = {};
    notes.forEach((n) => {
      if (n.folder_id) {
        counts[n.folder_id] = (counts[n.folder_id] || 0) + 1;
      }
    });
    return counts;
  }, [notes]);

  // Sub-pages (created via the "Sub-page" block) form a note hierarchy,
  // shown as a Notion-style expandable tree — only notes that actually
  // participate in one, so it doesn't duplicate the flat notes grid below.
  const noteTreeRoots = useMemo(() => {
    const byParent = new Map<string, typeof notes>();
    const inHierarchy = new Set<string>();

    notes.forEach((n) => {
      if (n.parent_note_id) {
        inHierarchy.add(n.id);
        inHierarchy.add(n.parent_note_id);
        const siblings = byParent.get(n.parent_note_id) || [];
        siblings.push(n);
        byParent.set(n.parent_note_id, siblings);
      }
    });

    if (inHierarchy.size === 0) return [];

    function buildNode(note: (typeof notes)[number]): NoteTreeNode {
      return {
        id: note.id,
        title: note.title,
        children: (byParent.get(note.id) || []).map(buildNode),
      };
    }

    return notes
      .filter((n) => inHierarchy.has(n.id) && !n.parent_note_id)
      .map(buildNode);
  }, [notes]);

  const activeFolder = filters.folderId && filters.folderId !== "__none__"
    ? folders.find(f => f.id === filters.folderId)
    : null;

  if (loading) {
    return (
      <div className="space-y-6">
        <div className="h-40 rounded-[28px] border border-white/[0.07] bg-white/[0.03] animate-pulse" />
        <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-3">
          {Array.from({ length: 6 }).map((_, i) => (
            <div key={i} className="h-28 rounded-[20px] bg-white/[0.03] border border-white/[0.06] animate-pulse" />
          ))}
        </div>
      </div>
    );
  }

  return (
    <div className="space-y-6">

      {/* ── Hero header ─────────────────────────────────────────────────────── */}
      <div
        className="relative overflow-hidden rounded-[28px] border border-white/[0.07] bg-[#0e0c15] p-8"
        style={{
          backgroundImage:
            "radial-gradient(ellipse at 20% -30%, rgba(20,184,166,0.15) 0%, transparent 55%), radial-gradient(ellipse at 85% 110%, rgba(99,102,241,0.08) 0%, transparent 50%)",
        }}
      >
        <div className="flex flex-wrap items-start justify-between gap-4">
          <div>
            <div className="mb-3 inline-flex items-center gap-2 rounded-full border border-teal-500/20 bg-teal-500/[0.08] px-3 py-1">
              <BookOpen className="h-3.5 w-3.5 text-teal-400" />
              <span className="text-[10px] font-bold uppercase tracking-[0.18em] text-teal-300">Notes</span>
            </div>
            <h1 className="text-[28px] font-bold tracking-tight text-white">
              {notes.length} {notes.length === 1 ? "Note" : "Notes"}
            </h1>
            <p className="mt-1 text-[14px] text-white/40">
              Your thinking space — capture, organize, and connect your knowledge.
            </p>
          </div>

          <div className="flex flex-wrap items-center gap-2">
            <Link
              href="/notes/marketplace"
              className="inline-flex items-center gap-1.5 rounded-xl border border-pink-500/20 bg-pink-500/[0.06] px-3 py-2 text-[12px] font-semibold text-pink-300 transition-all hover:border-pink-500/35 hover:bg-pink-500/[0.12]"
            >
              <Sparkles className="h-3.5 w-3.5" />
              Designs
            </Link>
            <button
              onClick={() => setShowFolderSidebar((v) => !v)}
              className={cn(
                "inline-flex items-center gap-1.5 rounded-xl border px-3 py-2 text-[12px] font-semibold transition-all",
                showFolderSidebar
                  ? "border-teal-500/25 bg-teal-500/[0.10] text-teal-300"
                  : "border-white/[0.07] bg-white/[0.03] text-white/40 hover:text-white/65",
              )}
            >
              <Folder className="h-3.5 w-3.5" />
              Folders
            </button>
            <button
              onClick={() => void handleCreate()}
              disabled={!canEditNotes}
              className="inline-flex items-center gap-2 rounded-xl border border-teal-500/30 bg-teal-500/[0.15] px-4 py-2 text-[13px] font-bold text-teal-200 transition-all hover:border-teal-500/50 hover:bg-teal-500/[0.22] disabled:opacity-40"
            >
              <Plus className="h-3.5 w-3.5" />
              New note
            </button>
          </div>
        </div>

        {/* ── Stats ─────────────────────────────────────────────────────── */}
        <div className="mt-6 flex flex-wrap gap-3">
          <div className="flex items-center gap-2 rounded-xl border border-white/[0.05] bg-white/[0.025] px-3 py-2">
            <Pin className="h-3 w-3 text-teal-400/60" />
            <span className="text-[12px] font-semibold text-white/50">{pinnedNotes.length} pinned</span>
          </div>
          <div className="flex items-center gap-2 rounded-xl border border-white/[0.05] bg-white/[0.025] px-3 py-2">
            <Folder className="h-3 w-3 text-white/25" />
            <span className="text-[12px] font-semibold text-white/50">{folders.length} {folders.length === 1 ? "folder" : "folders"}</span>
          </div>
          <div className="flex items-center gap-2 rounded-xl border border-white/[0.05] bg-white/[0.025] px-3 py-2">
            <Hash className="h-3 w-3 text-white/25" />
            <span className="text-[12px] font-semibold text-white/50">
              {notes.filter(n => !n.folder_id).length} unfiled
            </span>
          </div>
        </div>
      </div>

      {/* ── Saved views ─────────────────────────────────────────────────────── */}
      <SavedViewsBar
        filters={filters}
        emptyFilters={EMPTY_FILTERS}
        views={views}
        builtInViews={BUILT_IN_VIEWS}
        title="Saved note views"
        description="Keep your favorite note lenses ready, from pinned thinking spaces to unfiled capture."
        onApply={setFilters}
        onCreate={async (name, nextFilters) => {
          await createView({ name, filters: { ...nextFilters } });
        }}
        onDelete={async (id) => {
          await deleteView(id);
        }}
        onToggleFavorite={async (id, isFavorite) => {
          await updateView(id, { is_favorite: isFavorite });
        }}
      />

      {/* ── Template starters ───────────────────────────────────────────────── */}
      {!filters.search && !filters.folderId && !filters.pinState && notes.length > 0 && (
        <NoteTemplateGallery onSelect={(id) => void handleCreate(id)} disabled={!canEditNotes} collapsible />
      )}

      {/* ── Main layout ─────────────────────────────────────────────────────── */}
      <div className="flex gap-6">

        {/* ── Folder sidebar ──────────────────────────────────────────────── */}
        {showFolderSidebar && (
          <aside className="hidden md:block w-52 shrink-0 space-y-3">
            <div className="rounded-[22px] border border-white/[0.06] bg-[#0e0c15] p-4">
              <FolderTree
                folders={folders}
                selectedFolderId={selectedFolderId}
                onSelect={(folderId) =>
                  setFilters((current) => ({
                    ...current,
                    folderId: folderId || "",
                  }))
                }
                noteCountByFolder={noteCountByFolder}
                totalNoteCount={notes.length}
                onCreate={async (name) => { await createFolder(name); }}
                onRename={renameFolder}
                onDelete={deleteFolder}
                canManage={canEditNotes}
              />
            </div>

            {noteTreeRoots.length > 0 && (
              <div className="rounded-[22px] border border-white/[0.06] bg-[#0e0c15] p-4">
                <p className="mb-2 px-1 text-[10px] font-bold uppercase tracking-[0.16em] text-white/25">
                  Pages
                </p>
                <NoteTree roots={noteTreeRoots} />
              </div>
            )}
          </aside>
        )}

        {/* ── Content area ────────────────────────────────────────────────── */}
        <div className="flex-1 min-w-0 space-y-4">

          {/* ── Filter + Sort bar ───────────────────────────────────────── */}
          <div className="flex flex-wrap items-center gap-2">

            {/* Search */}
            <div className="relative flex-1 min-w-[160px]">
              <Search className="absolute left-3 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-white/25" />
              <input
                value={filters.search}
                onChange={(e) => setFilters((c) => ({ ...c, search: e.target.value }))}
                placeholder="Notizen durchsuchen…"
                className="h-9 w-full rounded-xl border border-white/[0.07] bg-white/[0.04] pl-9 pr-3 text-[13px] text-white/80 placeholder:text-white/25 outline-none focus:border-white/[0.14] focus:bg-white/[0.06] transition-colors"
              />
            </div>

            {/* View tabs */}
            <div className="flex items-center rounded-xl border border-white/[0.07] bg-white/[0.03] p-0.5 gap-0.5">
              {[
                { id: "", label: "Alle", icon: null },
                { id: "pinned", label: "Angeheftet", icon: <Pin className="h-3 w-3" /> },
              ].map((tab) => (
                <button
                  key={tab.id}
                  onClick={() => setFilters((c) => ({ ...c, pinState: tab.id }))}
                  className={cn(
                    "inline-flex items-center gap-1.5 rounded-lg px-3 py-1.5 text-[12px] font-semibold transition-all",
                    filters.pinState === tab.id
                      ? "bg-white/[0.08] text-white/90 shadow-sm"
                      : "text-white/35 hover:text-white/60"
                  )}
                >
                  {tab.icon}
                  {tab.label}
                </button>
              ))}
            </div>

            {/* Mobile folder select */}
            <div className="md:hidden">
              <select
                value={filters.folderId}
                onChange={(e) => setFilters((c) => ({ ...c, folderId: e.target.value }))}
                className="h-9 rounded-xl border border-white/[0.07] bg-white/[0.04] px-3 text-[12px] text-white/70 outline-none"
              >
                <option value="">Alle ({notes.length})</option>
                <option value="__none__">Kein Ordner</option>
                {folders.map((f) => (
                  <option key={f.id} value={f.id}>
                    {f.name} ({noteCountByFolder[f.id] || 0})
                  </option>
                ))}
              </select>
            </div>

            {/* Sort */}
            <div className="flex items-center gap-1.5 rounded-xl border border-white/[0.07] bg-white/[0.03] px-3 py-1.5">
              <SortAsc className="h-3.5 w-3.5 text-white/25 shrink-0" />
              <select
                value={sortBy}
                onChange={(e) => setSortBy(e.target.value as typeof sortBy)}
                className="bg-transparent text-[12px] text-white/55 outline-none cursor-pointer"
              >
                <option value="updated">Zuletzt bearbeitet</option>
                <option value="created">Erstellt</option>
                <option value="name">Name A–Z</option>
              </select>
            </div>

            {/* Grid / List toggle */}
            <div className="flex items-center rounded-xl border border-white/[0.07] bg-white/[0.03] p-0.5 gap-0.5">
              <button
                onClick={() => setViewMode("grid")}
                title="Grid"
                className={cn(
                  "flex items-center justify-center rounded-lg p-1.5 transition-all",
                  viewMode === "grid" ? "bg-white/[0.08] text-white/90 shadow-sm" : "text-white/35 hover:text-white/60",
                )}
              >
                <LayoutGrid className="h-3.5 w-3.5" />
              </button>
              <button
                onClick={() => setViewMode("list")}
                title="List"
                className={cn(
                  "flex items-center justify-center rounded-lg p-1.5 transition-all",
                  viewMode === "list" ? "bg-white/[0.08] text-white/90 shadow-sm" : "text-white/35 hover:text-white/60",
                )}
              >
                <ListIcon className="h-3.5 w-3.5" />
              </button>
            </div>

            {/* Clear all filters */}
            {(filters.search || filters.folderId || filters.pinState) && (
              <button
                onClick={() => setFilters(EMPTY_FILTERS)}
                className="inline-flex items-center gap-1.5 rounded-xl border border-white/[0.06] px-3 py-1.5 text-[12px] text-white/30 transition-all hover:text-white/55"
              >
                <X className="h-3 w-3" />
                Zurücksetzen
              </button>
            )}
          </div>

          {/* ── Active folder indicator ──────────────────────────────────── */}
          {activeFolder && (
            <div className="flex items-center gap-2.5 rounded-[16px] border border-teal-500/15 bg-teal-500/[0.05] px-4 py-2.5">
              <Folder className="h-4 w-4 text-teal-400/60" />
              <span className="text-[13px] font-semibold text-teal-300/70">{activeFolder.name}</span>
              <span className="text-[12px] text-white/30">
                · {noteCountByFolder[activeFolder.id] || 0} Notes
              </span>
              <button
                onClick={() => setFilters((c) => ({ ...c, folderId: "" }))}
                className="ml-auto text-white/25 hover:text-white/50 transition-colors"
              >
                <X className="h-3.5 w-3.5" />
              </button>
            </div>
          )}

          {/* ── Results label ────────────────────────────────────────────── */}
          {notes.length > 0 && (
            <div className="flex items-center gap-2">
              {filters.pinState === "pinned"
                ? <Pin className="h-3.5 w-3.5 text-teal-400/50" />
                : <FileText className="h-3.5 w-3.5 text-white/20" />
              }
              <span className="text-[11px] font-bold uppercase tracking-[0.16em] text-white/25">
                {filtered.length} {filtered.length === 1 ? "Note" : "Notes"}
                {filters.pinState === "pinned" ? " · Angeheftet" : ""}
                {activeFolder ? ` · ${activeFolder.name}` : ""}
                {filters.search ? ` · "${filters.search}"` : ""}
              </span>
            </div>
          )}

          {/* ── Single unified grid ──────────────────────────────────────── */}
          {filtered.length === 0 ? (
            <div className="rounded-[24px] border border-dashed border-white/[0.07] bg-white/[0.01] p-12 text-center">
              <div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-3xl border border-white/[0.08] bg-white/[0.04]">
                <FileText className="h-7 w-7 text-white/25" />
              </div>
              <p className="text-[16px] font-bold text-white/40">
                {notes.length === 0 ? "Noch keine Notizen" : "Keine passenden Notizen"}
              </p>
              <p className="mt-2 text-[13px] text-white/25">
                {notes.length === 0
                  ? "Erstelle deine erste Notiz."
                  : "Andere Filter oder Suche ausprobieren."}
              </p>
              {notes.length === 0 && (
                <div className="mt-5 space-y-4">
                  <button
                    onClick={() => void handleCreate()}
                    disabled={!canEditNotes}
                    className="inline-flex items-center gap-2 rounded-xl border border-teal-500/30 bg-teal-500/[0.15] px-4 py-2 text-[13px] font-bold text-teal-200 transition-all hover:border-teal-500/50 hover:bg-teal-500/[0.22] disabled:opacity-40"
                  >
                    <Plus className="h-3.5 w-3.5" />
                    Notiz erstellen
                  </button>
                  <div className="mx-auto max-w-3xl">
                    <NoteTemplateGallery
                      onSelect={(id) => void handleCreate(id)}
                      disabled={!canEditNotes}
                      compact
                    />
                  </div>
                </div>
              )}
            </div>
          ) : viewMode === "list" ? (
            <div className="overflow-hidden rounded-[20px] border border-white/[0.06] bg-white/[0.015]">
              {listRows.map(({ note, depth, hasChildren }) => (
                <NoteListRow
                  key={note.id}
                  note={note}
                  folder={note.folder_id ? folderById.get(note.folder_id) : null}
                  onTogglePin={() => togglePin(note.id, note.is_pinned)}
                  onDelete={() => deleteNote(note.id)}
                  canManage={canEditNotes}
                  depth={depth}
                  hasChildren={hasChildren}
                  expanded={expandedNoteIds.has(note.id)}
                  onToggleExpand={() => toggleNoteExpanded(note.id)}
                  onCreateSubPage={
                    canEditNotes
                      ? () => {
                          setExpandedNoteIds((prev) => new Set(prev).add(note.id));
                          void handleCreateSubPage(note);
                        }
                      : undefined
                  }
                />
              ))}
            </div>
          ) : (
            <div className="grid gap-3 sm:grid-cols-2 lg:grid-cols-3">
              {filtered.map((note) => (
                <NoteCard
                  key={note.id}
                  note={note}
                  onTogglePin={() => togglePin(note.id, note.is_pinned)}
                  onDelete={() => deleteNote(note.id)}
                  canManage={canEditNotes}
                  onCreateSubPage={canEditNotes ? () => void handleCreateSubPage(note) : undefined}
                />
              ))}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}
