import { useState, useCallback, useEffect } from "react";
import type { Editor } from "@tiptap/core";
import type * as Y from "yjs";

interface CitationPanelProps {
  editor: Editor;
  citationsMap: Y.Map<any>;
  onClose: () => void;
}

function isBibTeX(input: string): boolean {
  const trimmed = input.trim();
  return trimmed.startsWith("@") && /\{[\s\S]*\}/.test(trimmed);
}

/**
 * Single smart-field citation panel.
 * Auto-detects DOI / URL / BibTeX from the input.
 * Library is always visible below.
 */
export function CitationPanel({
  editor,
  citationsMap,
  onClose,
}: CitationPanelProps) {
  const [input, setInput] = useState("");
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState("");
  const [libraryEntries, setLibraryEntries] = useState<
    { key: string; entry: any }[]
  >([]);

  useEffect(() => {
    const refresh = () => setLibraryEntries(getLibraryEntries(citationsMap));
    refresh();
    citationsMap.observe(refresh);
    return () => citationsMap.unobserve(refresh);
  }, [citationsMap]);

  const ensureBibliography = useCallback(() => {
    let hasBibliography = false;
    editor.state.doc.descendants((node) => {
      if (node.type.name === "bibliography") hasBibliography = true;
    });
    if (!hasBibliography) {
      const endPos = editor.state.doc.content.size;
      editor
        .chain()
        .insertContentAt(endPos, [
          { type: "paragraph" },
          { type: "bibliography" },
        ])
        .run();
    }
  }, [editor]);

  const insertCitation = useCallback(
    (entry: any) => {
      const key =
        entry["citation-key"] || entry.id || generateKey(entry);
      citationsMap.set(key, entry);
      editor.chain().focus().insertCitation(key).run();
      ensureBibliography();
      onClose();
    },
    [editor, citationsMap, onClose, ensureBibliography],
  );

  const insertExisting = useCallback(
    (key: string) => {
      editor.chain().focus().insertCitation(key).run();
      ensureBibliography();
      onClose();
    },
    [editor, onClose, ensureBibliography],
  );

  const resolveInput = useCallback(async () => {
    if (!input.trim()) return;
    setLoading(true);
    setError("");
    try {
      const bibtex = isBibTeX(input);
      const endpoint = bibtex
        ? "/api/citations/import-bib"
        : "/api/citations/resolve";
      const body = bibtex ? { bibtex: input } : { input };

      const res = await fetch(endpoint, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(body),
      });
      const data = await res.json();

      if (!res.ok) {
        setError(data.error || "Resolution failed");
        return;
      }

      if (data.entries?.length >= 1) {
        data.entries.forEach((entry: any) => {
          const key =
            entry["citation-key"] || entry.id || generateKey(entry);
          citationsMap.set(key, entry);
        });
        insertCitation(data.entries[0]);
      }
    } catch (err: any) {
      setError(err.message || "Network error");
    } finally {
      setLoading(false);
    }
  }, [input, insertCitation, citationsMap]);

  return (
    <div className="citation-panel-overlay" onClick={onClose}>
      <div className="citation-panel" onClick={(e) => e.stopPropagation()}>
        <div className="citation-panel-header">
          <h3>Add reference</h3>
          <button className="citation-panel-close" onClick={onClose}>
            &times;
          </button>
        </div>

        <div className="citation-panel-body">
          <textarea
            className="citation-input citation-smart-input"
            placeholder={"Paste a DOI, URL, or BibTeX entry...\ne.g. 10.1038/s41586-020-2649-2"}
            value={input}
            onChange={(e) => setInput(e.target.value)}
            onKeyDown={(e) => {
              if (e.key === "Enter" && !e.shiftKey && !isBibTeX(input)) {
                e.preventDefault();
                resolveInput();
              }
            }}
            rows={3}
            autoFocus
          />

          {error && <p className="citation-error">{error}</p>}

          <button
            className="citation-resolve-btn"
            onClick={resolveInput}
            disabled={loading || !input.trim()}
          >
            {loading ? "Resolving..." : "Resolve & Add"}
          </button>

          {libraryEntries.length > 0 && (
            <>
              <div className="citation-library-divider">
                <span>Your references ({libraryEntries.length})</span>
              </div>
              <div className="citation-library-list">
                {libraryEntries.map(({ key, entry }) => (
                  <div key={key} className="citation-library-item">
                    <div className="citation-library-info">
                      <span className="citation-library-meta">
                        {formatAuthorsShort(entry)}{" "}
                        {entry.issued?.["date-parts"]?.[0]?.[0] || ""}
                      </span>
                      <span className="citation-library-title">
                        {entry.title || key}
                      </span>
                    </div>
                    <button
                      className="citation-library-insert"
                      onClick={() => insertExisting(key)}
                      title="Insert citation"
                    >
                      +
                    </button>
                  </div>
                ))}
              </div>
            </>
          )}
        </div>
      </div>
    </div>
  );
}

function generateKey(entry: any): string {
  const firstAuthor = entry.author?.[0]?.family || "unknown";
  const year = entry.issued?.["date-parts"]?.[0]?.[0] || "nd";
  return `${firstAuthor.toLowerCase()}${year}`.replace(/[^a-z0-9]/gi, "");
}

function formatAuthorsShort(entry: any): string {
  const authors = entry.author;
  if (!authors?.length) return "";
  const first = authors[0].family || "";
  if (authors.length === 1) return first;
  if (authors.length === 2) return `${first} & ${authors[1].family || ""}`;
  return `${first} et al.`;
}

function getLibraryEntries(map: Y.Map<any>): { key: string; entry: any }[] {
  const result: { key: string; entry: any }[] = [];
  map.forEach((entry, key) => {
    result.push({ key, entry });
  });
  result.sort((a, b) => {
    const aName = a.entry.author?.[0]?.family || a.key;
    const bName = b.entry.author?.[0]?.family || b.key;
    return aName.localeCompare(bName);
  });
  return result;
}
