import { useState, useRef, useEffect } from "react";
import {
  ChevronUp,
  ChevronDown,
  Pencil,
  Trash2,
  Plus,
  ExternalLink,
} from "lucide-react";
import { AuthorInlineForm } from "./AuthorInlineForm";
import type { FrontmatterStore, Author, Affiliation } from "./frontmatter-store";

interface AuthorsManagerProps {
  open: boolean;
  store: FrontmatterStore;
  authors: Author[];
  affiliations: Affiliation[];
  onClose: () => void;
}

/**
 * One-stop modal to manage the article byline: add/edit/remove authors,
 * add/edit/remove affiliations, and reorder both lists with explicit
 * up/down controls (the discoverable replacement for the invisible inline
 * drag). All mutations go through the FrontmatterStore so they stay
 * collaborative + undoable; reordering or deleting an affiliation remaps
 * every author's 1-based references inside the store.
 */
export function AuthorsManager({
  open,
  store,
  authors,
  affiliations,
  onClose,
}: AuthorsManagerProps) {
  const dialogRef = useRef<HTMLDialogElement>(null);
  // `null` = closed, `"new"` = add form, number = edit author at that index.
  const [authorForm, setAuthorForm] = useState<number | "new" | null>(null);
  const [newAffName, setNewAffName] = useState("");

  useEffect(() => {
    const dialog = dialogRef.current;
    if (!dialog) return;
    if (open && !dialog.open) {
      setAuthorForm(null);
      setNewAffName("");
      dialog.showModal();
    } else if (!open && dialog.open) {
      dialog.close();
    }
  }, [open]);

  useEffect(() => {
    const dialog = dialogRef.current;
    if (!dialog) return;
    const onCloseEvent = () => onClose();
    dialog.addEventListener("close", onCloseEvent);
    return () => dialog.removeEventListener("close", onCloseEvent);
  }, [onClose]);

  const multipleAffiliations = affiliations.length > 1;

  const submitAuthorForm = (author: Author, newAff?: Affiliation) => {
    const finalAuthor = { ...author };
    if (newAff) {
      const idx = store.addAffiliation(newAff);
      finalAuthor.affiliations = [...finalAuthor.affiliations, idx];
    }
    if (authorForm === "new") {
      store.addAuthor(finalAuthor);
    } else if (typeof authorForm === "number") {
      store.updateAuthor(authorForm, finalAuthor);
    }
    setAuthorForm(null);
  };

  const addAffiliation = () => {
    const name = newAffName.trim();
    if (!name) return;
    store.addAffiliation({ name });
    setNewAffName("");
  };

  return (
    <dialog ref={dialogRef} className="ed-dialog ed-dialog--manager">
      <h3 className="ed-dialog__title">Authors &amp; affiliations</h3>

      <div className="ed-dialog__body authors-manager">
        {/* ---- Authors ---- */}
        <section className="am-section">
          <div className="am-section__head">
            <span className="am-section__title">Authors</span>
            <button
              className="btn btn--primary am-add-btn"
              onClick={() => setAuthorForm("new")}
            >
              <Plus size={14} />
              <span>Add author</span>
            </button>
          </div>

          {authors.length === 0 ? (
            <p className="am-empty">No authors yet.</p>
          ) : (
            <ul className="am-list">
              {authors.map((author, i) => (
                <li className="am-row" key={`am-author-${i}`}>
                  <div className="am-row__reorder">
                    <button
                      className="icon-btn icon-btn--sm"
                      aria-label="Move up"
                      disabled={i === 0}
                      onClick={() => store.moveAuthor(i, i - 1)}
                    >
                      <ChevronUp size={14} />
                    </button>
                    <button
                      className="icon-btn icon-btn--sm"
                      aria-label="Move down"
                      disabled={i === authors.length - 1}
                      onClick={() => store.moveAuthor(i, i + 1)}
                    >
                      <ChevronDown size={14} />
                    </button>
                  </div>

                  <div className="am-row__main">
                    <span className="am-row__name">
                      {author.name || <em className="am-muted">Unnamed</em>}
                      {multipleAffiliations && author.affiliations?.length > 0 && (
                        <sup className="am-row__affs">
                          {[...author.affiliations].sort((a, b) => a - b).join(",")}
                        </sup>
                      )}
                    </span>
                    {author.url && (
                      <a
                        className="am-row__url"
                        href={author.url}
                        target="_blank"
                        rel="noopener noreferrer"
                      >
                        <ExternalLink size={11} />
                        <span>{prettyUrl(author.url)}</span>
                      </a>
                    )}
                  </div>

                  <div className="am-row__actions">
                    <button
                      className="icon-btn icon-btn--sm"
                      aria-label="Edit author"
                      onClick={() => setAuthorForm(i)}
                    >
                      <Pencil size={14} />
                    </button>
                    <button
                      className="icon-btn icon-btn--sm am-row__danger"
                      aria-label="Remove author"
                      onClick={() => store.removeAuthor(i)}
                    >
                      <Trash2 size={14} />
                    </button>
                  </div>
                </li>
              ))}
            </ul>
          )}
        </section>

        {/* ---- Affiliations ---- */}
        <section className="am-section">
          <div className="am-section__head">
            <span className="am-section__title">Affiliations</span>
          </div>

          {affiliations.length === 0 ? (
            <p className="am-empty">
              No affiliations yet. Add one below, then attach it to authors.
            </p>
          ) : (
            <ol className="am-list am-list--aff">
              {affiliations.map((aff, i) => (
                <AffiliationRow
                  key={`am-aff-${i}`}
                  index={i}
                  total={affiliations.length}
                  affiliation={aff}
                  store={store}
                />
              ))}
            </ol>
          )}

          <div className="am-add-row">
            <input
              className="form-input"
              placeholder="New affiliation, e.g. Hugging Face"
              value={newAffName}
              onChange={(e) => setNewAffName(e.target.value)}
              onKeyDown={(e) => e.key === "Enter" && addAffiliation()}
            />
            <button
              className="btn"
              onClick={addAffiliation}
              disabled={!newAffName.trim()}
            >
              <Plus size={14} />
              <span>Add</span>
            </button>
          </div>
        </section>
      </div>

      <div className="ed-dialog__actions">
        <button className="btn btn--primary" onClick={() => dialogRef.current?.close()}>
          Done
        </button>
      </div>

      {/* Author add/edit form, stacked on top of this dialog. */}
      <AuthorInlineForm
        open={authorForm !== null}
        initial={typeof authorForm === "number" ? authors[authorForm] : undefined}
        affiliations={affiliations}
        onSubmit={submitAuthorForm}
        onCancel={() => setAuthorForm(null)}
      />
    </dialog>
  );
}

/**
 * Single affiliation row with inline name + URL editing. Keeps a local draft
 * so typing doesn't round-trip through Yjs on every keystroke; commits on
 * blur / Enter only when the value actually changed.
 */
function AffiliationRow({
  index,
  total,
  affiliation,
  store,
}: {
  index: number;
  total: number;
  affiliation: Affiliation;
  store: FrontmatterStore;
}) {
  const [name, setName] = useState(affiliation.name);
  const [url, setUrl] = useState(affiliation.url || "");

  useEffect(() => setName(affiliation.name), [affiliation.name]);
  useEffect(() => setUrl(affiliation.url || ""), [affiliation.url]);

  const commit = () => {
    const nextName = name.trim();
    const nextUrl = url.trim();
    if (nextName === affiliation.name && nextUrl === (affiliation.url || "")) return;
    if (!nextName) {
      // Don't allow blanking the name: revert to the stored value.
      setName(affiliation.name);
      return;
    }
    store.updateAffiliation(index, {
      name: nextName,
      url: nextUrl || undefined,
    });
  };

  return (
    <li className="am-row am-row--aff">
      <span className="am-row__index">{index + 1}.</span>

      <div className="am-row__reorder">
        <button
          className="icon-btn icon-btn--sm"
          aria-label="Move up"
          disabled={index === 0}
          onClick={() => store.moveAffiliation(index, index - 1)}
        >
          <ChevronUp size={14} />
        </button>
        <button
          className="icon-btn icon-btn--sm"
          aria-label="Move down"
          disabled={index === total - 1}
          onClick={() => store.moveAffiliation(index, index + 1)}
        >
          <ChevronDown size={14} />
        </button>
      </div>

      <div className="am-row__fields">
        <input
          className="form-input"
          placeholder="Affiliation name"
          value={name}
          onChange={(e) => setName(e.target.value)}
          onBlur={commit}
          onKeyDown={(e) => e.key === "Enter" && (e.target as HTMLInputElement).blur()}
        />
        <input
          className="form-input"
          placeholder="URL (optional)"
          value={url}
          onChange={(e) => setUrl(e.target.value)}
          onBlur={commit}
          onKeyDown={(e) => e.key === "Enter" && (e.target as HTMLInputElement).blur()}
        />
      </div>

      <button
        className="icon-btn icon-btn--sm am-row__danger"
        aria-label="Remove affiliation"
        onClick={() => store.removeAffiliation(index)}
      >
        <Trash2 size={14} />
      </button>
    </li>
  );
}

/** Strip protocol + trailing slash for a compact URL label. */
function prettyUrl(url: string): string {
  return url.replace(/^https?:\/\//, "").replace(/\/$/, "");
}
