// priority-modal.jsx — cross-coordinator priority conflict picker
//
// Globally-mounted host (<PriorityConflictHost/>) plus a window-level
// helper `window.requestPriorityChange(task, newPriority, opts)` that
// returns a Promise<boolean>. Any code path that wants to change a
// task's priority should:
//
//   const ok = await window.requestPriorityChange(task, "high");
//   if (ok) actualPatchToHigh();
//
// The host's behaviour:
//
//   * newPriority NOT in {high, critical} or NOT an upgrade
//     → resolves true immediately (no prompt).
//   * No assignee or self-assigned only → resolves true (no conflict
//     possible by definition).
//   * Otherwise fetches /api/priority/load for the assignee, computes
//     would-be-total = current count + 1, and:
//        - under the workspace cap        → friendly "Set anyway"
//                                            picker with the current
//                                            high list visible.
//        - at/over the workspace cap      → red banner + downgrade
//                                            choices + admin-override
//                                            button. The user still
//                                            decides — caps are soft.
//
// The picker NEVER blocks irreversibly — coordinators retain final
// say. Its job is to surface the conflict so the choice is informed.

(function () {
  if (typeof window === "undefined") return;
  let _resolvers = [];

  // Public helper. Returns Promise<boolean>: true → caller proceeds
  // with the patch; false → caller cancels (user picked Cancel or
  // closed the modal). Falls back to `true` when the host isn't
  // mounted yet (no UX regression for code that ran before app
  // finished hydrating).
  window.requestPriorityChange = function requestPriorityChange(task, nextPriority, opts) {
    opts = opts || {};
    // Fast paths — anything not an upgrade to high/critical bypasses
    // the picker entirely.
    if (!task) return Promise.resolve(true);
    if (nextPriority !== "high" && nextPriority !== "critical") {
      return Promise.resolve(true);
    }
    const current = task.prio || task.priority;
    // Same value → no-op.
    if (current === nextPriority) return Promise.resolve(true);
    // Already at critical, downshifting to high — not a conflict.
    const RANK = { critical: 0, high: 1, medium: 2, low: 3, none: 4 };
    if (RANK[current] != null && RANK[current] < RANK[nextPriority]) {
      return Promise.resolve(true);
    }
    // No assignees → can't conflict with anyone.
    if (!Array.isArray(task.owners) || task.owners.length === 0) {
      return Promise.resolve(true);
    }
    // Only the current user assigned → self-conflict, not coordinator
    // pressure. Skip the picker.
    const me = opts.currentUserId || window.__currentUserId || null;
    if (me && task.owners.length === 1 && task.owners[0] === me) {
      return Promise.resolve(true);
    }
    return new Promise(resolve => {
      const event = new CustomEvent("priority:request", {
        detail: {
          task,
          nextPriority,
          currentUserId: me,
          resolve,
        },
      });
      _resolvers.push(resolve);
      window.dispatchEvent(event);
      // Safety net — if the host doesn't pick it up within 50ms,
      // resolve true so we never deadlock a write path. The host
      // sets a flag in the event detail when it consumes the event.
      setTimeout(() => {
        if (event.detail._consumed) return;
        try { resolve(true); } catch {}
      }, 50);
    });
  };

  // ── Host component ───────────────────────────────────────────
  function PriorityConflictHost() {
    const [pending, setPending] = React.useState(null);
    React.useEffect(() => {
      function onRequest(e) {
        if (!e || !e.detail) return;
        e.detail._consumed = true;
        setPending(e.detail);
      }
      window.addEventListener("priority:request", onRequest);
      return () => window.removeEventListener("priority:request", onRequest);
    }, []);
    if (!pending) return null;
    return (
      <PriorityConflictPicker
        task={pending.task}
        nextPriority={pending.nextPriority}
        currentUserId={pending.currentUserId}
        onResolve={(ok) => {
          try { pending.resolve(!!ok); } catch {}
          setPending(null);
        }}/>
    );
  }

  function PriorityConflictPicker({ task, nextPriority, currentUserId, onResolve }) {
    const targetUserId = (task.owners && task.owners[0]) || null;
    const [loading, setLoading] = React.useState(true);
    const [data, setData]       = React.useState(null);
    const [err, setErr]         = React.useState("");
    React.useEffect(() => {
      let cancelled = false;
      (async () => {
        try {
          const r = await window.api.priority.load({
            userId: targetUserId,
            excludeTaskId: task && task.id,
          });
          if (!cancelled) setData(r);
        } catch (e) {
          if (!cancelled) setErr((e && (e.body && e.body.message)) || (e && e.message) || "Could not load priority context");
        } finally {
          if (!cancelled) setLoading(false);
        }
      })();
      return () => { cancelled = true; };
    }, [targetUserId, task && task.id]);

    // Auto-resolve when we can't fetch the context — coordinators
    // shouldn't be blocked by a degraded backend.
    React.useEffect(() => {
      if (!loading && err) {
        const t = setTimeout(() => onResolve(true), 1500);
        return () => clearTimeout(t);
      }
    }, [loading, err, onResolve]);

    const ownerPerson = ((window.PEOPLE || []).find(p => p.id === targetUserId)) || null;
    const ownerName = (ownerPerson && ownerPerson.name) || targetUserId;

    if (loading) {
      return ReactDOM.createPortal(
        <div className="modal-backdrop" onClick={() => onResolve(false)}>
          <div className="priority-modal" onClick={(e) => e.stopPropagation()}>
            <div style={{ padding: 24, textAlign: "center", color: "var(--ink-muted)" }}>
              Checking {ownerName}'s priority load…
            </div>
          </div>
        </div>,
        document.body
      );
    }
    if (err) {
      return ReactDOM.createPortal(
        <div className="modal-backdrop" onClick={() => onResolve(false)}>
          <div className="priority-modal" onClick={(e) => e.stopPropagation()}>
            <div style={{ padding: 24 }}>
              <div style={{ color: "var(--prio-critical, #c93636)", marginBottom: 12 }}>
                Couldn't load priority context: {err}
              </div>
              <div style={{ fontSize: 12, color: "var(--ink-muted)" }}>Proceeding with the change…</div>
            </div>
          </div>
        </div>,
        document.body
      );
    }

    const caps = (data && data.caps) || { cap_high: 2, cap_critical: 1 };
    const counts = (data && data.counts) || { critical: 0, high: 0 };
    const byMe = (data && data.by_me_counts) || { critical: 0, high: 0 };
    const items = (data && data.items) || [];

    const isCritical = nextPriority === "critical";
    const sameLevelCap = isCritical ? caps.cap_critical : caps.cap_high;
    const sameLevelCount = isCritical ? counts.critical : counts.high;
    const totalAfter = sameLevelCount + 1;
    const overCap = totalAfter > sameLevelCap;
    const myCountAtLevel = isCritical ? byMe.critical : byMe.high;
    const youAreAlreadyOver = myCountAtLevel >= sameLevelCap;

    const titleLabel = isCritical ? "critical" : "high";

    return ReactDOM.createPortal(
      <div className="modal-backdrop" onClick={() => onResolve(false)}>
        <div className="priority-modal" onClick={(e) => e.stopPropagation()}>
          <div className="pm-head">
            <div className={"pm-head-icon" + (overCap ? " is-danger" : " is-warn")}>
              {overCap ? "!" : "▲"}
            </div>
            <div>
              <h3>Set this task to {titleLabel}?</h3>
              <p style={{ margin: "4px 0 0", color: "var(--ink-muted)", fontSize: 13 }}>
                <b>{ownerName}</b> already has <b>{counts.critical} critical</b>
                {" · "}<b>{counts.high} high</b> open
                {sameLevelCap > 0 && (
                  <> · cap for {titleLabel}: <b>{sameLevelCap}</b></>
                )}
              </p>
            </div>
          </div>

          {overCap && (
            <div className="pm-banner is-danger">
              Setting this {titleLabel} would put {ownerName} at <b>{totalAfter} {titleLabel} tasks</b> — over the
              workspace cap of <b>{sameLevelCap}</b>.
              {youAreAlreadyOver && (
                <> You already have <b>{myCountAtLevel}</b> {titleLabel} task{myCountAtLevel === 1 ? "" : "s"} on
                  their plate from previous assignments.</>
              )}
            </div>
          )}

          {items.length > 0 ? (
            <div className="pm-body">
              <div className="pm-section-label">Currently {sameLevelCount > 0 ? "on their plate" : "open from you"}</div>
              <ul className="pm-list">
                {items.map(it => {
                  const isMine = it.creator_id === currentUserId;
                  return (
                    <li key={it.id} className={"pm-item is-" + it.priority}>
                      <span className={"pm-prio pm-prio-" + it.priority}>{it.priority}</span>
                      <div className="pm-item-body">
                        <div className="pm-item-name" title={it.name}>{it.name}</div>
                        <div className="pm-item-sub">
                          <span className="pm-proj-dot" style={{ background: it.project_color || "#a3a8b6" }}/>
                          {it.project_name}
                          {it.due_date && <> · due <b>{it.due_date}</b></>}
                          {it.creator_name && (
                            <> · {isMine ? <b>by you</b> : <>by {it.creator_name}</>}</>
                          )}
                        </div>
                      </div>
                    </li>
                  );
                })}
              </ul>
            </div>
          ) : (
            <div className="pm-body" style={{ color: "var(--ink-muted)", fontSize: 13, padding: "8px 18px 14px" }}>
              No other {titleLabel} or critical work on their plate.
            </div>
          )}

          <div className="pm-footer">
            <button className="btn" onClick={() => onResolve(false)}>Cancel</button>
            <button className="btn"
                    onClick={() => onResolve("downgrade-medium")}
                    title="Skip the high stamp and set as medium instead">
              Set as medium instead
            </button>
            <button className={"btn btn-primary" + (overCap ? " btn-danger" : "")}
                    onClick={() => onResolve(true)}
                    title={overCap
                      ? "Override the cap — leadership will see this in the Conflicts dashboard"
                      : "Set the priority and notify the assignee"}>
              {overCap ? "Set anyway (over cap)" : "Set " + titleLabel}
            </button>
          </div>
        </div>
        <style>{PRIORITY_MODAL_CSS}</style>
      </div>,
      document.body
    );
  }

  const PRIORITY_MODAL_CSS = `
  .priority-modal {
    background: white;
    border-radius: 12px;
    box-shadow: 0 24px 60px rgba(15,23,41,.32);
    width: min(560px, 92vw);
    max-height: 86vh;
    display: flex; flex-direction: column;
    overflow: hidden;
  }
  .pm-head {
    display: flex; gap: 14px; align-items: flex-start;
    padding: 18px 20px 14px;
    border-bottom: 1px solid var(--border);
  }
  .pm-head h3 {
    margin: 0; font-size: 16px; color: var(--ink-strong);
  }
  .pm-head-icon {
    width: 36px; height: 36px; border-radius: 999px;
    display: inline-flex; align-items: center; justify-content: center;
    font-weight: 800; font-size: 16px; flex: none;
  }
  .pm-head-icon.is-warn   { background: #fff4e0; color: #a16207; }
  .pm-head-icon.is-danger { background: rgba(226,68,92,.14); color: #8a1024; }
  .pm-banner {
    margin: 10px 20px 0;
    padding: 10px 12px;
    border-radius: 8px;
    font-size: 13px;
  }
  .pm-banner.is-danger { background: rgba(226,68,92,.10); color: #8a1024; }
  .pm-body { padding: 12px 20px 0; overflow-y: auto; flex: 1 1 auto; }
  .pm-section-label {
    font-size: 11px; font-weight: 700; letter-spacing: .04em;
    text-transform: uppercase; color: var(--ink-muted);
    margin-bottom: 8px;
  }
  .pm-list { list-style: none; padding: 0; margin: 0 0 12px; }
  .pm-item {
    display: flex; gap: 10px; align-items: center;
    padding: 8px 10px; border-radius: 8px;
    border: 1px solid var(--border, #e7e8ec);
    margin-bottom: 6px; background: #fafbfd;
  }
  .pm-item.is-critical { border-color: rgba(226,68,92,.5); }
  .pm-prio {
    text-transform: uppercase; font-size: 10px; font-weight: 800;
    padding: 2px 8px; border-radius: 999px;
    color: white; letter-spacing: .04em; flex: none;
  }
  .pm-prio-critical { background: #c93636; }
  .pm-prio-high     { background: #f59e0b; color: #5a3500; }
  .pm-item-body { flex: 1; min-width: 0; }
  .pm-item-name {
    font-weight: 600; color: var(--ink-strong);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: 13px;
  }
  .pm-item-sub {
    font-size: 11px; color: var(--ink-muted);
    display: flex; align-items: center; gap: 6px; flex-wrap: wrap;
    margin-top: 3px;
  }
  .pm-proj-dot { width: 8px; height: 8px; border-radius: 999px; flex: none; }
  .pm-footer {
    display: flex; justify-content: flex-end; gap: 8px;
    padding: 12px 20px;
    border-top: 1px solid var(--border);
    background: #fafbfd;
  }
  .btn.btn-danger { background: #c93636; border-color: #8a1024; color: white; font-weight: 700; }
  `;

  // Mount the host onto a globally-known node once the app's React
  // root is ready. Mounting through a portal target keeps it out of
  // any local component's lifecycle.
  function mount() {
    if (document.getElementById("priority-conflict-host")) return;
    const node = document.createElement("div");
    node.id = "priority-conflict-host";
    document.body.appendChild(node);
    try {
      const root = (ReactDOM.createRoot ? ReactDOM.createRoot(node) : null);
      if (root) root.render(<PriorityConflictHost/>);
      else ReactDOM.render(<PriorityConflictHost/>, node);
    } catch (e) {
      console.warn("[priority-modal] mount failed:", e && e.message);
    }
  }
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", mount);
  } else {
    mount();
  }
})();
