"use client";

import Link from "next/link";
import { useSearchParams } from "next/navigation";
import { Suspense, useCallback, useEffect, useMemo, useState } from "react";
import { AppShell } from "@/components/AppShell";
import { searchNotesRanked, type SearchRankedHit } from "@/lib/notes-client";
import { listSavedViews, createSavedView, deleteSavedView, type SavedView } from "@/lib/saved-views-client";
import { useDebounce } from "@/lib/use-debounce";

export default function SearchPage() {
  return (
    <Suspense fallback={<AppShell title="Search" description="Search notes"><p>Loading...</p></AppShell>}>
      <SearchPageInner />
    </Suspense>
  );
}

function SearchPageInner() {
  const searchParams = useSearchParams();
  const [hits, setHits] = useState<SearchRankedHit[]>([]);
  const [query, setQuery] = useState(() => searchParams?.get("q") ?? "");
  const debouncedQuery = useDebounce(query, 250);
  const [mode, setMode] = useState<"lexical" | "hybrid">("hybrid");
  const [savedViewsList, setSavedViewsList] = useState<SavedView[]>([]);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    setQuery(searchParams?.get("q") ?? "");
  }, [searchParams]);

  useEffect(() => {
    void (async () => {
      try {
        const res = await searchNotesRanked(debouncedQuery, mode);
        setHits(res.items);
        setError(null);
      } catch (err) {
        setError(err instanceof Error ? err.message : "Unable to load notes");
      }
    })();
  }, [debouncedQuery, mode]);

  useEffect(() => {
    void (async () => {
      try {
        setSavedViewsList(await listSavedViews("search"));
      } catch {
        // Saved views are best-effort
      }
    })();
  }, []);

  const handleSaveCurrentSearch = useCallback(async () => {
    if (!query.trim()) return;
    try {
      const view = await createSavedView({
        id: crypto.randomUUID(),
        name: query.trim().slice(0, 60),
        scope: "search",
        query: query.trim(),
      });
      setSavedViewsList((current) => [...current, view]);
    } catch {
      // Best-effort
    }
  }, [query]);

  const handleDeleteSavedView = useCallback(async (id: string) => {
    try {
      await deleteSavedView(id);
      setSavedViewsList((current) => current.filter((v) => v.id !== id));
    } catch {
      // Best-effort
    }
  }, []);

  const savedViews = useMemo(
    () =>
      savedViewsList.map((view) => ({
        id: view.id,
        name: view.name,
        query: view.query,
        resultCount: 0,
      })),
    [savedViewsList],
  );

  return (
    <AppShell
      title="Search"
      description="Lexical and hybrid ranked search with match hints (title, body, tag). Toggle modes to compare behavior."
      actions={<div className="badge">POST /notes/search</div>}
    >
      <section style={{ display: "grid", gridTemplateColumns: "minmax(260px, 320px) minmax(0, 1fr)", gap: "var(--nl-space-4)" }}>
        <aside className="surface-card" style={{ padding: "var(--nl-space-5)", display: "grid", gap: "var(--nl-space-4)" }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
            <div style={{ fontWeight: 700 }}>Saved searches</div>
            {query.trim() ? (
              <button
                type="button"
                className="badge"
                onClick={() => void handleSaveCurrentSearch()}
                style={{ cursor: "pointer" }}
              >
                + Save current
              </button>
            ) : null}
          </div>
          <div style={{ display: "grid", gap: "var(--nl-space-3)" }}>
            {savedViews.map((view) => (
              <div
                key={view.id}
                className="surface-muted"
                style={{ padding: "var(--nl-space-4)", display: "grid", gap: "var(--nl-space-2)" }}
              >
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "start" }}>
                  <Link href={`/search?q=${encodeURIComponent(view.query)}`} style={{ display: "grid", gap: "var(--nl-space-2)" }}>
                    <strong>{view.name}</strong>
                    <span style={{ color: "var(--nl-text-secondary)" }}>{view.query}</span>
                  </Link>
                  <button
                    type="button"
                    onClick={() => {
                      if (window.confirm("Remove this saved view?")) void handleDeleteSavedView(view.id);
                    }}
                    style={{
                      color: "var(--nl-text-secondary)",
                      background: "none",
                      border: "none",
                      cursor: "pointer",
                      fontSize: "0.75rem",
                    }}
                  >
                    Remove
                  </button>
                </div>
              </div>
            ))}
            {savedViews.length === 0 ? (
              <span style={{ color: "var(--nl-text-secondary)", fontSize: "0.875rem" }}>No saved searches yet.</span>
            ) : null}
          </div>

          <div style={{ display: "grid", gap: "var(--nl-space-2)" }}>
            <strong>Search mode</strong>
            <label style={{ display: "flex", alignItems: "center", gap: 8 }}>
              <input type="radio" name="smode" checked={mode === "hybrid"} onChange={() => setMode("hybrid")} />
              Hybrid ranked (default)
            </label>
            <label style={{ display: "flex", alignItems: "center", gap: 8 }}>
              <input type="radio" name="smode" checked={mode === "lexical"} onChange={() => setMode("lexical")} />
              Lexical only
            </label>
          </div>
        </aside>

        <section className="surface-card" style={{ padding: "var(--nl-space-6)", display: "grid", gap: "var(--nl-space-4)" }}>
          <input
            aria-label="Search notes"
            className="input-shell"
            placeholder="Search notes, tags, and body text"
            value={query}
            onChange={(event) => setQuery(event.target.value)}
          />
          <div style={{ display: "flex", gap: "var(--nl-space-2)", flexWrap: "wrap" }}>
            <span className="badge">mode:{mode}</span>
            <span className="badge">{hits.length} hits</span>
          </div>
          {error ? <div style={{ color: "var(--nl-text-secondary)" }}>{error}</div> : null}
          <div style={{ display: "grid", gap: "var(--nl-space-3)" }}>
            {hits.map((hit) => (
              <div key={hit.noteId} className="surface-muted" style={{ padding: "var(--nl-space-4)", display: "grid", gap: "var(--nl-space-2)" }}>
                <div style={{ display: "flex", justifyContent: "space-between", gap: "var(--nl-space-3)", flexWrap: "wrap" }}>
                  <Link href={`/notes/${hit.noteId}`} style={{ fontWeight: 700 }}>
                    {hit.title}
                  </Link>
                  <span className="badge">
                    {hit.matchKind} · score {hit.score}
                  </span>
                </div>
                <div style={{ color: "var(--nl-text-secondary)", fontSize: "var(--nl-fs-sm)" }}>{hit.snippet}</div>
                <Link href={`/search?q=${encodeURIComponent(hit.workspaceId)}`} style={{ color: "var(--nl-text-secondary)", fontSize: "var(--nl-fs-sm)" }}>
                  workspace: {hit.workspaceId}
                </Link>
              </div>
            ))}
          </div>
        </section>
      </section>
    </AppShell>
  );
}
