// PromoteToolbar — converts a taxonomy term into a formal SysML element
// without leaving the document. Lives inside TermDetail.
//
// The four buttons map onto the existing ModelOp alphabet so undo/redo and
// SSE sync work for free; each op carries `linkedTermId = term.id` so the
// new formalism is anchored back to the concept that named it.
//
// All forms are inline + dismissive: an open form replaces the toolbar, and
// the user can cancel back to the toolbar without a destructive action.

"use client";

import { useState } from "react";
import { useModelStore } from "../../lib/sync/ModelStore";
import type { ClientTerm } from "../../lib/workspace/analysisStore";
import { useOpenPanes } from "../../lib/workspace/openPanesStore";
import { useEditorPaneContext } from "./sections/paneContext";
import {
  addBlock,
  addAssociation,
  addConstraint,
  addRequirement,
  tempId,
} from "../../lib/sync/ops";

interface Props {
  term: ClientTerm;
  /** Called after a successful promote, so the parent can flash + scroll. */
  onPromoted?: (kind: "block" | "association" | "constraint" | "requirement") => void;
}

type FormKind = null | "association" | "constraint" | "requirement";

export function PromoteToolbar({ term, onPromoted }: Props) {
  const { model, apply } = useModelStore();
  const [open, setOpen] = useState<FormKind>(null);
  const { openSection } = useOpenPanes();
  const { setFocusBlockId } = useEditorPaneContext();

  // Persist the term-to-block link server-side after a successful promote so
  // the next analyze pass sees the link.
  const persistTermLink = async (blockId: string) => {
    try {
      const projectId = window.location.pathname.split("/").pop() ?? "";
      if (!projectId) return;
      await fetch(`/api/projects/${encodeURIComponent(projectId)}/term-link`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ termId: term.id, blockId }),
      });
    } catch (err) {
      console.error("[PromoteToolbar] term-link persistence failed:", err);
    }
  };

  const promoteBlock = () => {
    const id = tempId("blk");
    apply([
      addBlock(
        {
          id,
          label: term.label,
          kind: "block",
          stereotypes: ["block"],
          properties: [],
          linkedTermId: term.id,
        },
        id
      ),
    ]);
    void persistTermLink(id);
    openSection("model");
    setFocusBlockId(id);
    onPromoted?.("block");
  };

  if (open === "association") {
    return (
      <AssociationForm
        term={term}
        blocks={model.blocks}
        onCancel={() => setOpen(null)}
        onSubmit={(fromId, toId, label) => {
          const id = tempId("a");
          apply([
            addAssociation(
              { id, fromBlockId: fromId, toBlockId: toId, label, kind: "association", linkedTermId: term.id },
              id
            ),
          ]);
          setOpen(null);
          openSection("model");
          onPromoted?.("association");
        }}
      />
    );
  }

  if (open === "constraint") {
    return (
      <ConstraintForm
        term={term}
        blocks={model.blocks}
        onCancel={() => setOpen(null)}
        onSubmit={(label, expression, appliesTo) => {
          const id = tempId("c");
          apply([
            addConstraint(
              { id, label, expression, appliesTo, linkedTermId: term.id },
              id
            ),
          ]);
          setOpen(null);
          openSection("model");
          onPromoted?.("constraint");
        }}
      />
    );
  }

  if (open === "requirement") {
    return (
      <RequirementForm
        term={term}
        blocks={model.blocks}
        onCancel={() => setOpen(null)}
        onSubmit={(tag, text, satisfiedBy) => {
          const id = tempId("r");
          apply([
            addRequirement(
              {
                id,
                tag,
                text,
                relations: satisfiedBy.map(blockId => ({ kind: "satisfy" as const, blockId })),
                linkedTermId: term.id,
              },
              id
            ),
          ]);
          setOpen(null);
          openSection("requirements");
          onPromoted?.("requirement");
        }}
      />
    );
  }

  // No block linked yet → recommend "Make Block" as the primary action.
  const hasBlock = !!term.linkedBlockId;
  return (
    <div className="promote-toolbar">
      <button
        type="button"
        className={`promote-btn ${!hasBlock ? "promote-btn-primary" : ""}`}
        onClick={promoteBlock}
        title={hasBlock ? "Already a block" : "Create a SysML block from this concept"}
        disabled={hasBlock}
      >
        + Block
      </button>
      <button type="button" className="promote-btn" onClick={() => setOpen("association")}>
        + Association
      </button>
      <button type="button" className="promote-btn" onClick={() => setOpen("constraint")}>
        + Constraint
      </button>
      <button type="button" className="promote-btn" onClick={() => setOpen("requirement")}>
        + Requirement
      </button>
    </div>
  );
}

// ─── Inline forms ───────────────────────────────────────────────────────

interface AssocFormProps {
  term: ClientTerm;
  blocks: { id: string; label: string }[];
  onCancel: () => void;
  onSubmit: (fromId: string, toId: string, label: string) => void;
}

function AssociationForm({ term, blocks, onCancel, onSubmit }: AssocFormProps) {
  const [from, setFrom] = useState("");
  const [to, setTo] = useState("");
  const [label, setLabel] = useState(term.label);
  const canSubmit = from && to && from !== to;
  return (
    <form
      className="promote-form"
      onSubmit={e => {
        e.preventDefault();
        if (!canSubmit) return;
        onSubmit(from, to, label.trim() || term.label);
      }}
    >
      <FormHead title="New Association" subtitle={`anchored to "${term.label}"`} onCancel={onCancel} />
      <BlockSelect label="From" value={from} onChange={setFrom} blocks={blocks} />
      <BlockSelect label="To" value={to} onChange={setTo} blocks={blocks} excludeId={from} />
      <FieldRow label="Label">
        <input
          className="promote-input"
          value={label}
          onChange={e => setLabel(e.target.value)}
          placeholder="verb phrase"
        />
      </FieldRow>
      <FormActions canSubmit={!!canSubmit} />
    </form>
  );
}

interface ConstraintFormProps {
  term: ClientTerm;
  blocks: { id: string; label: string }[];
  onCancel: () => void;
  onSubmit: (label: string, expression: string, appliesTo: string[]) => void;
}

function ConstraintForm({ term, blocks, onCancel, onSubmit }: ConstraintFormProps) {
  const [label, setLabel] = useState(term.label);
  const [expression, setExpression] = useState("");
  const [appliesTo, setAppliesTo] = useState<string[]>([]);
  const canSubmit = !!label.trim();
  return (
    <form
      className="promote-form"
      onSubmit={e => {
        e.preventDefault();
        if (!canSubmit) return;
        onSubmit(label.trim(), expression.trim(), appliesTo);
      }}
    >
      <FormHead title="New Constraint" subtitle={`anchored to "${term.label}"`} onCancel={onCancel} />
      <FieldRow label="Label">
        <input className="promote-input" value={label} onChange={e => setLabel(e.target.value)} />
      </FieldRow>
      <FieldRow label="Expression">
        <input
          className="promote-input"
          value={expression}
          onChange={e => setExpression(e.target.value)}
          placeholder="e.g. sessions_per_day <= 3"
        />
      </FieldRow>
      <BlockMultiSelect label="Applies to" value={appliesTo} onChange={setAppliesTo} blocks={blocks} />
      <FormActions canSubmit={canSubmit} />
    </form>
  );
}

interface RequirementFormProps {
  term: ClientTerm;
  blocks: { id: string; label: string }[];
  onCancel: () => void;
  onSubmit: (tag: string, text: string, satisfiedBy: string[]) => void;
}

function RequirementForm({ term, blocks, onCancel, onSubmit }: RequirementFormProps) {
  const [tag, setTag] = useState("REQ-001");
  const [text, setText] = useState("");
  const [satisfiedBy, setSatisfiedBy] = useState<string[]>(
    term.linkedBlockId ? [term.linkedBlockId] : []
  );
  const canSubmit = !!tag.trim() && !!text.trim();
  return (
    <form
      className="promote-form"
      onSubmit={e => {
        e.preventDefault();
        if (!canSubmit) return;
        onSubmit(tag.trim(), text.trim(), satisfiedBy);
      }}
    >
      <FormHead title="New Requirement" subtitle={`anchored to "${term.label}"`} onCancel={onCancel} />
      <FieldRow label="Tag">
        <input className="promote-input" value={tag} onChange={e => setTag(e.target.value)} />
      </FieldRow>
      <FieldRow label="Text">
        <textarea
          className="promote-textarea"
          value={text}
          onChange={e => setText(e.target.value)}
          placeholder="The system must …"
          rows={2}
        />
      </FieldRow>
      <BlockMultiSelect label="Satisfied by" value={satisfiedBy} onChange={setSatisfiedBy} blocks={blocks} />
      <FormActions canSubmit={canSubmit} />
    </form>
  );
}

// ─── Form atoms ─────────────────────────────────────────────────────────

function FormHead({ title, subtitle, onCancel }: { title: string; subtitle: string; onCancel: () => void }) {
  return (
    <div className="promote-form-head">
      <div>
        <div className="promote-form-title">{title}</div>
        <div className="promote-form-subtitle">{subtitle}</div>
      </div>
      <button type="button" className="promote-form-cancel" onClick={onCancel} aria-label="Cancel">
        ✕
      </button>
    </div>
  );
}

function FieldRow({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <label className="promote-field">
      <span className="promote-field-label">{label}</span>
      {children}
    </label>
  );
}

function FormActions({ canSubmit }: { canSubmit: boolean }) {
  return (
    <div className="promote-form-actions">
      <button type="submit" className="promote-btn promote-btn-primary" disabled={!canSubmit}>
        Create
      </button>
    </div>
  );
}

interface BlockSelectProps {
  label: string;
  value: string;
  onChange: (v: string) => void;
  blocks: { id: string; label: string }[];
  excludeId?: string;
}

function BlockSelect({ label, value, onChange, blocks, excludeId }: BlockSelectProps) {
  const options = blocks.filter(b => b.id !== excludeId);
  return (
    <FieldRow label={label}>
      <select className="promote-input" value={value} onChange={e => onChange(e.target.value)}>
        <option value="">— pick block —</option>
        {options.map(b => (
          <option key={b.id} value={b.id}>
            {b.label}
          </option>
        ))}
      </select>
    </FieldRow>
  );
}

interface BlockMultiSelectProps {
  label: string;
  value: string[];
  onChange: (v: string[]) => void;
  blocks: { id: string; label: string }[];
}

function BlockMultiSelect({ label, value, onChange, blocks }: BlockMultiSelectProps) {
  if (blocks.length === 0) {
    return (
      <FieldRow label={label}>
        <span className="promote-empty">No blocks yet — promote one first.</span>
      </FieldRow>
    );
  }
  return (
    <FieldRow label={label}>
      <div className="promote-checkbox-list">
        {blocks.map(b => {
          const checked = value.includes(b.id);
          return (
            <label key={b.id} className="promote-checkbox">
              <input
                type="checkbox"
                checked={checked}
                onChange={() =>
                  onChange(checked ? value.filter(x => x !== b.id) : [...value, b.id])
                }
              />
              <span>{b.label}</span>
            </label>
          );
        })}
      </div>
    </FieldRow>
  );
}

