/* Small focused popovers for inline graph editing. */
{
  const { useEffect, useMemo, useRef, useState } = React;

  const ID_RE = /^[A-Za-z_][\w]*$/;
  const ENUM_VAL_RE = /^[A-Z_][A-Z0-9_]*$/;

  const ENTITY_KINDS = ["class", "abstract", "interface", "enum"];
  const STEREOS = ["", "Stock", "Immutable", "OpenModule", "Embeddable", "Interface", "Key", "AggregateRoot"];
  const COMMON_TYPES = ["String", "Integer", "Long", "Double", "BigDecimal", "Boolean", "UUID", "LocalDate", "LocalDateTime", "Instant"];
  const REL_KINDS = [
    { value: "association", label: "→ link" },
    { value: "inheritance", label: "▷ extends" },
    { value: "composition", label: "◆ owns" },
    { value: "aggregation", label: "◇ has" },
    { value: "dependency",  label: "· · ·> uses" },
  ];

  function clampToViewport(x, y, w, h) {
    const M = 12;
    const vw = window.innerWidth, vh = window.innerHeight;
    const left = Math.max(M, Math.min(x, vw - w - M));
    const top  = Math.max(M, Math.min(y, vh - h - M));
    return { left, top };
  }

  function Popover({ anchor, width = 280, title, onClose, children }) {
    const ref = useRef(null);
    const [pos, setPos] = useState(() => clampToViewport(anchor.x + 6, anchor.y + 6, width, 220));

    useEffect(() => {
      // refine after mount so we can keep the actually-measured popover in the viewport
      const el = ref.current;
      const h = el ? el.offsetHeight : 220;
      setPos(clampToViewport(anchor.x + 6, anchor.y + 6, width, h));
    }, [anchor.x, anchor.y, width]);

    useEffect(() => {
      function onDown(e) {
        if (ref.current && !ref.current.contains(e.target)) onClose();
      }
      function onKey(e) {
        if (e.key === "Escape") onClose();
      }
      document.addEventListener("mousedown", onDown);
      document.addEventListener("keydown", onKey);
      return () => {
        document.removeEventListener("mousedown", onDown);
        document.removeEventListener("keydown", onKey);
      };
    }, [onClose]);

    return (
      <div
        ref={ref}
        className="popover"
        style={{ left: pos.left, top: pos.top, width }}
        onMouseDown={(e) => e.stopPropagation()}
      >
        {title && (
          <div className="popover-head">
            <span>{title}</span>
            <button className="popover-x" onClick={onClose} title="Close">×</button>
          </div>
        )}
        <div className="popover-body">{children}</div>
      </div>
    );
  }

  function Field({ label, children }) {
    return (
      <label className="pop-field">
        <span>{label}</span>
        {children}
      </label>
    );
  }

  function PillRow({ value, onChange, options }) {
    return (
      <div className="pop-pills">
        {options.map(o => {
          const v = typeof o === "string" ? o : o.value;
          const lbl = typeof o === "string" ? o : o.label;
          return (
            <button
              key={v}
              type="button"
              className={`pop-pill ${value === v ? "active" : ""}`}
              onClick={() => onChange(v)}
            >{lbl}</button>
          );
        })}
      </div>
    );
  }

  /* ---------------- Add entity ---------------- */
  function AddEntityPopover({ anchor, onClose, onSubmit, existingNames, parents, defaultExtendsFrom, defaultKind }) {
    const [name, setName] = useState("");
    const [kind, setKind] = useState(defaultKind || "class");
    const [stereotype, setStereotype] = useState("");
    const [extendsFrom, setExtendsFrom] = useState(defaultExtendsFrom || "");
    const [error, setError] = useState(null);

    function submit() {
      const n = name.trim();
      if (!n) { setError("Name required."); return; }
      if (!ID_RE.test(n)) { setError("Use letters, digits and underscores."); return; }
      if (existingNames.has(n)) { setError(`"${n}" already exists.`); return; }
      onSubmit({ name: n, kind, stereotype: stereotype || null, extendsFrom: extendsFrom || null });
      onClose();
    }

    const title = defaultExtendsFrom ? `Add subclass of ${defaultExtendsFrom}` : "Add entity";

    return (
      <Popover anchor={anchor} width={300} title={title} onClose={onClose}>
        <div className="pop-form">
          <Field label="Name">
            <input
              autoFocus
              type="text"
              value={name}
              onChange={(e) => setName(e.target.value)}
              onKeyDown={(e) => { if (e.key === "Enter") submit(); }}
              placeholder="MyEntity"
            />
          </Field>
          <Field label="Kind">
            <PillRow value={kind} onChange={setKind} options={ENTITY_KINDS} />
          </Field>
          {!defaultExtendsFrom && kind !== "enum" && parents && parents.length > 0 && (
            <Field label="Extends">
              <select value={extendsFrom} onChange={(e) => setExtendsFrom(e.target.value)}>
                <option value="">—</option>
                {parents.map(p => <option key={p} value={p}>{p}</option>)}
              </select>
            </Field>
          )}
          <Field label="Stereotype">
            <select value={stereotype} onChange={(e) => setStereotype(e.target.value)}>
              {STEREOS.map(s => <option key={s} value={s}>{s || "—"}</option>)}
            </select>
          </Field>
          {error && <div className="pop-error">{error}</div>}
          <div className="pop-actions">
            <button className="pop-btn" onClick={onClose}>Cancel</button>
            <button className="pop-btn primary" onClick={submit}>Add</button>
          </div>
        </div>
      </Popover>
    );
  }

  /* Unwrap a Java-ish type to its base + flags. List<X>, X[], Set<X> → list of X;
     Optional<X> → optional X. Everything else returns as-is. */
  function unwrapType(type) {
    let t = (type || "").trim();
    let isList = false, optional = false;
    let m;
    if ((m = t.match(/^(List|Set|Collection|Iterable|Array)\s*<\s*(.+?)\s*>$/))) {
      isList = true;
      t = m[2].trim();
    } else if (t.endsWith("[]")) {
      isList = true;
      t = t.slice(0, -2).trim();
    } else if ((m = t.match(/^Optional\s*<\s*(.+?)\s*>$/))) {
      optional = true;
      t = m[1].trim();
    }
    return { type: t, isList, optional };
  }

  /* ---------------- Add / edit field (or enum value) ---------------- */
  function AddFieldPopover({ anchor, onClose, onSubmit, onDelete, entity, isEnum, knownTypes, existing }) {
    const isEdit = !!existing;
    const init = useMemo(() => {
      if (!isEdit) return { name: "", type: "String", visibility: "+", isList: false, optional: false };
      if (isEnum) return { name: existing.value || "", type: "String", visibility: "+", isList: false, optional: false };
      const u = unwrapType(existing.type || "");
      return {
        name: existing.name || "",
        type: u.type || "String",
        visibility: existing.visibility || "+",
        isList: u.isList,
        optional: u.optional,
      };
    }, [isEdit, isEnum, existing]);

    const [name, setName] = useState(init.name);
    const [type, setType] = useState(init.type);
    const [visibility, setVisibility] = useState(init.visibility);
    const [isList, setIsList] = useState(init.isList);
    const [optional, setOptional] = useState(init.optional);
    const [error, setError] = useState(null);

    function wrappedType() {
      let t = type.trim();
      if (!t) return "";
      if (optional && !isList) t = `Optional<${t}>`;
      if (isList) t = `List<${t}>`;
      return t;
    }

    function submit() {
      const n = name.trim();
      if (!n) { setError("Name required."); return; }
      if (isEnum) {
        const v = n.toUpperCase();
        if (!ENUM_VAL_RE.test(v)) { setError("Enum values are UPPERCASE (e.g. ACTIVE)."); return; }
        if (isEdit) {
          onSubmit({ kind: "enumvalue-update", entity, oldValue: existing.value, value: v });
        } else {
          onSubmit({ kind: "enumvalue", entity, value: v });
        }
        onClose();
        return;
      }
      if (!ID_RE.test(n)) { setError("Use letters, digits and underscores."); return; }
      const t = wrappedType();
      if (!t) { setError("Type required."); return; }
      if (isEdit) {
        onSubmit({ kind: "attribute-update", entity, oldName: existing.name, name: n, type: t, visibility });
      } else {
        onSubmit({ kind: "attribute", entity, name: n, type: t, visibility });
      }
      onClose();
    }

    function remove() {
      if (!onDelete) return;
      onDelete();
      onClose();
    }

    const title = isEdit
      ? (isEnum ? `Edit ${entity}.${existing.value}` : `Edit ${entity}.${existing.name}`)
      : (isEnum ? `Add value to ${entity}` : `Add field to ${entity}`);

    return (
      <Popover anchor={anchor} width={300} title={title} onClose={onClose}>
        <div className="pop-form">
          <Field label={isEnum ? "Value" : "Name"}>
            <input
              autoFocus
              type="text"
              value={name}
              onChange={(e) => setName(isEnum ? e.target.value.toUpperCase() : e.target.value)}
              onKeyDown={(e) => { if (e.key === "Enter") submit(); }}
              placeholder={isEnum ? "ACTIVE" : "myField"}
            />
          </Field>
          {!isEnum && (
            <>
              <Field label="Type">
                <input
                  type="text"
                  value={type}
                  onChange={(e) => setType(e.target.value)}
                  onKeyDown={(e) => { if (e.key === "Enter") submit(); }}
                  list="dm-popover-types"
                  placeholder="String"
                />
                <datalist id="dm-popover-types">
                  {COMMON_TYPES.map(t => <option key={t} value={t} />)}
                  {(knownTypes || []).map(t => <option key={t} value={t} />)}
                </datalist>
              </Field>
              <div className="pop-checkrow">
                <label className="pop-check">
                  <input type="checkbox" checked={isList} onChange={(e) => setIsList(e.target.checked)} />
                  <span>list</span>
                </label>
                <label className="pop-check">
                  <input type="checkbox" checked={optional} disabled={isList} onChange={(e) => setOptional(e.target.checked)} />
                  <span>optional</span>
                </label>
                <div className="pop-vis">
                  {["+", "-", "#", "~"].map(v => (
                    <button key={v} type="button"
                      className={`pop-pill mini ${visibility === v ? "active" : ""}`}
                      onClick={() => setVisibility(v)}
                      title={v === "+" ? "public" : v === "-" ? "private" : v === "#" ? "protected" : "package"}
                    >{v}</button>
                  ))}
                </div>
              </div>
              <div className="pop-hint">As: <code>{wrappedType() || "—"}</code></div>
            </>
          )}
          {error && <div className="pop-error">{error}</div>}
          <div className="pop-actions">
            {isEdit && onDelete && (
              <button className="pop-btn danger" onClick={remove} title="Delete">Delete</button>
            )}
            <div style={{ marginLeft: "auto", display: "inline-flex", gap: 6 }}>
              <button className="pop-btn" onClick={onClose}>Cancel</button>
              <button className="pop-btn primary" onClick={submit}>{isEdit ? "Save" : "Add"}</button>
            </div>
          </div>
        </div>
      </Popover>
    );
  }

  /* ---------------- Edit / delete relation ---------------- */
  function EditRelationPopover({ anchor, onClose, onUpdate, onDelete, relation }) {
    const [label, setLabel] = useState(relation.label || "");
    const [fromCard, setFromCard] = useState(relation.fromCard || "");
    const [toCard, setToCard] = useState(relation.toCard || "");
    const [kind, setKind] = useState(relation.kind);

    function save() {
      onUpdate({
        from: relation.from,
        to: relation.to,
        kind,
        label: label.trim() || null,
        fromCard: fromCard.trim() || null,
        toCard: toCard.trim() || null,
      });
      onClose();
    }

    function remove() {
      onDelete();
      onClose();
    }

    return (
      <Popover anchor={anchor} width={320} title={`${relation.from} → ${relation.to}`} onClose={onClose}>
        <div className="pop-form">
          <Field label="Kind">
            <PillRow value={kind} onChange={setKind} options={REL_KINDS} />
          </Field>
          {kind !== "inheritance" && (
            <>
              <div className="pop-pair">
                <Field label={`${relation.from}`}>
                  <input type="text" value={fromCard} onChange={(e) => setFromCard(e.target.value)} placeholder="1" />
                </Field>
                <Field label={`${relation.to}`}>
                  <input type="text" value={toCard} onChange={(e) => setToCard(e.target.value)} placeholder="*" />
                </Field>
              </div>
              <Field label="Label">
                <input type="text" value={label} onChange={(e) => setLabel(e.target.value)}
                  onKeyDown={(e) => { if (e.key === "Enter") save(); }}
                  placeholder="optional" />
              </Field>
            </>
          )}
          <div className="pop-actions">
            <button className="pop-btn danger" onClick={remove} title="Delete this relation">Delete</button>
            <div style={{ marginLeft: "auto", display: "inline-flex", gap: 6 }}>
              <button className="pop-btn" onClick={onClose}>Cancel</button>
              <button className="pop-btn primary" onClick={save}>Save</button>
            </div>
          </div>
        </div>
      </Popover>
    );
  }

  window.Popovers = {
    AddEntityPopover,
    AddFieldPopover,
    EditRelationPopover,
  };
}
