/* FLOWLINE — shared components */
const { useState, useEffect, useRef, useContext, createContext } = React;

const SEV_TEXT = {
  green: "In flow",
  yellow: "Flagged",
  orange: "Escalated",
  red: "Critical",
};

/* context that lets any exception card trigger a live resolution action */
const ActionContext = createContext({ act: async () => {}, pendingId: null });

/* ---------- neutral silhouette avatar ---------- */
function Silhouette() {
  return (
    <svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
      <circle cx="12" cy="8" r="4" />
      <path d="M4 21c0-4.4 3.6-7 8-7s8 2.6 8 7v1H4z" />
    </svg>
  );
}
function ShopGlyph() {
  return (
    <svg
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="1.7"
      aria-hidden="true"
    >
      <path d="M4 10l1.5-5h13L20 10" />
      <path d="M4 10v9h16v-9" />
      <path d="M9 19v-5h6v5" />
      <path d="M4 10h16" />
    </svg>
  );
}
function DeptGlyph() {
  return (
    <svg
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="1.7"
      aria-hidden="true"
    >
      <rect x="4" y="4" width="16" height="16" rx="2" />
      <path d="M4 9h16M9 9v11" />
    </svg>
  );
}
function VehicleGlyph() {
  return (
    <svg
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="1.6"
      aria-hidden="true"
    >
      <path d="M3 14V8h10l3 3h5v3" />
      <path d="M3 14v3h2.2M21 14v3h-2.2" />
      <path d="M7.5 17h8.5" />
      <circle cx="6.2" cy="17.5" r="1.7" />
      <circle cx="17.2" cy="17.5" r="1.7" />
    </svg>
  );
}

function Avatar({
  kind,
  size = 38,
  sev,
  dotStyle = "filled",
  pulse = true,
  square,
}) {
  const s = { width: size, height: size };
  let glyph = <Silhouette />;
  if (kind === "shop" || kind === "senior") glyph = <ShopGlyph />;
  else if (kind === "dept" || kind === "department" || kind === "ownership")
    glyph = <DeptGlyph />;
  else if (kind === "vehicle") glyph = <VehicleGlyph />;
  return (
    <span className={"avatar" + (square ? " sq" : "")} style={s}>
      {glyph}
      {sev && (
        <span className="av-dot">
          <Dot
            sev={sev}
            style={dotStyle}
            pulse={pulse}
            size={size > 44 ? "lg" : ""}
          />
        </span>
      )}
    </span>
  );
}

/* ---------- status dot ---------- */
function Dot({ sev = "green", style = "filled", pulse = false, size = "" }) {
  return (
    <span className={`dot ${sev} s-${style} ${size} ${pulse ? "pulse" : ""}`} />
  );
}

/* ---------- severity tag ---------- */
function SevTag({ sev, children }) {
  return (
    <span className={`tag ${sev}`}>
      <Dot sev={sev} style="filled" size="sm" />
      {children || SEV_TEXT[sev]}
    </span>
  );
}
function Tag({ tone = "neutral", children, mono }) {
  return (
    <span
      className={`tag ${tone}`}
      style={mono ? { fontFamily: "var(--mono)" } : null}
    >
      {children}
    </span>
  );
}

/* ---------- generic single-select filter dropdown ----------
   Used for the topbar filters (severity, group-by, branch) so every
   filter reads as an explicit menu instead of a loose toggle button.
   options: [{ value, label, hint, sev, count }] — hint shows as a
   hover tooltip on that option so new users can see what it does
   before picking it. */
function FilterDropdown({
  label,
  value,
  options,
  onChange,
  title,
  className,
  renderTrigger,
}) {
  const [open, setOpen] = useState(false);
  const rootRef = useRef(null);

  useEffect(() => {
    if (!open) return undefined;
    const onDown = (e) => {
      if (rootRef.current && !rootRef.current.contains(e.target))
        setOpen(false);
    };
    const onKey = (e) => {
      if (e.key === "Escape") setOpen(false);
    };
    document.addEventListener("mousedown", onDown);
    document.addEventListener("keydown", onKey);
    return () => {
      document.removeEventListener("mousedown", onDown);
      document.removeEventListener("keydown", onKey);
    };
  }, [open]);

  const current = options.find((o) => o.value === value) || options[0];
  const pick = (v) => {
    onChange(v);
    setOpen(false);
  };

  return (
    <div
      className={"filterdd" + (className ? " " + className : "")}
      ref={rootRef}
    >
      <button
        type="button"
        className={"btn ghost sm filterdd-trigger" + (open ? " open" : "")}
        onClick={() => setOpen((o) => !o)}
        aria-haspopup="true"
        aria-expanded={open}
        title={title}
      >
        {renderTrigger ? (
          renderTrigger(current)
        ) : (
          <>
            <span className="filterdd-label">{label}</span>
            <span className="filterdd-cur">{current ? current.label : ""}</span>
          </>
        )}
        <span className="filterdd-caret">▾</span>
      </button>

      {open && (
        <div className="filterdd-panel" role="menu" aria-label={label}>
          {options.map((o) => (
            <button
              key={String(o.value)}
              type="button"
              role="menuitemradio"
              aria-checked={o.value === value}
              className={"filterdd-row" + (o.value === value ? " cur" : "")}
              onClick={() => pick(o.value)}
              title={o.hint}
            >
              {o.sev && <Dot sev={o.sev} style="filled" size="sm" />}
              <span className="filterdd-rowlabel">{o.label}</span>
              {typeof o.count === "number" && (
                <span className="filterdd-count">{o.count}</span>
              )}
              {o.value === value && <span className="filterdd-check">✓</span>}
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

/* ---------- elapsed time formatting ---------- */
function fmtElapsed(min) {
  if (min < 60) return min + "m";
  const h = Math.floor(min / 60),
    m = min % 60;
  if (h < 24) return h + "h" + (m ? " " + m + "m" : "");
  const d = Math.floor(h / 24);
  return d + "d" + (h % 24 ? " " + (h % 24) + "h" : "");
}

/* ---------- escalation clock + meter ---------- */
function EscalationClock({ exc }) {
  const sev = exc.current;
  let nextLabel = "Moves up a level if it's not cleared in time.";
  let pct = 1;
  const T = window.FL.THRESH;
  if (sev === "yellow") {
    pct = Math.min(1, exc.elapsedMin / T.yellowToOrange);
    nextLabel = `Becomes "Escalated" at ${T.yellowToOrange}m if not cleared.`;
  } else if (sev === "orange") {
    pct = Math.min(1, exc.elapsedMin / (T.yellowToOrange + T.orangeToRed));
    nextLabel = `Becomes "Critical" if not cleared.`;
  } else {
    pct = 1;
    nextLabel = "At the top level — with the current holder.";
  }
  const barColor = `var(--${sev})`;
  return (
    <div className="clock">
      <div>
        <div className="clock-big" style={{ color: barColor }}>
          {fmtElapsed(exc.elapsedMin)}
        </div>
        <div className="clock-meta">open</div>
      </div>
      <div style={{ flex: 1 }}>
        <div className="clock-meta">{nextLabel}</div>
        <div className="meter">
          <i
            style={{
              width: (pct * 100).toFixed(0) + "%",
              background: barColor,
            }}
          />
        </div>
      </div>
    </div>
  );
}

/* ---------- escalation route timeline ---------- */
function RouteTimeline({ route }) {
  return (
    <div className="route">
      {route.map((step, i) => (
        <div
          key={i}
          className={
            "route-step" + (step.status === "current" ? " current" : "")
          }
        >
          <div className="route-rail">
            <span
              className="route-node"
              style={{
                background:
                  step.status === "current"
                    ? "var(--accent)"
                    : "var(--border-strong)",
              }}
            />
          </div>
          <div className="route-body">
            <div className="route-role">{step.role}</div>
            <div className="route-name">
              {step.name}
              <span className="route-when">{step.at}</span>
              {step.status === "passed" && (
                <span className="tag neutral" style={{ fontSize: 9.5 }}>
                  passed
                </span>
              )}
              {step.status === "current" && (
                <span className="tag red" style={{ fontSize: 9.5 }}>
                  sitting here
                </span>
              )}
              {step.status === "pending" && (
                <span className="tag neutral" style={{ fontSize: 9.5 }}>
                  next up
                </span>
              )}
            </div>
            <div className="route-note">{step.note}</div>
          </div>
        </div>
      ))}
    </div>
  );
}

/* ---------- small reason row ---------- */
function ReasonRow({ r, onOpen }) {
  return (
    <div
      className={"reason" + (r.excId ? " click" : "")}
      onClick={r.excId && onOpen ? () => onOpen(r.excId) : undefined}
    >
      <Dot sev={r.sev} style="filled" />
      <div style={{ flex: 1 }}>{r.text}</div>
      {r.excId && (
        <span style={{ color: "var(--ink-3)", fontSize: 15, lineHeight: 1 }}>
          ›
        </span>
      )}
    </div>
  );
}

/* ---------- tweaks: persisted settings + compact popover ---------- */
function useTweaks(defaults) {
  const [t, setT] = useState(() => {
    try {
      const saved = JSON.parse(localStorage.getItem("fl.tweaks") || "{}");
      return Object.assign({}, defaults, saved);
    } catch (_e) {
      return Object.assign({}, defaults);
    }
  });
  const setTweak = (k, v) =>
    setT((prev) => {
      const next = Object.assign({}, prev, { [k]: v });
      try {
        localStorage.setItem("fl.tweaks", JSON.stringify(next));
      } catch (_e) {}
      return next;
    });
  return [t, setTweak];
}

function Toggle({ value, onChange }) {
  return (
    <button
      className={"toggle" + (value ? " on" : "")}
      onClick={() => onChange(!value)}
      aria-pressed={value}
    />
  );
}

function SettingsPanel({ t, setTweak }) {
  const [open, setOpen] = useState(false);
  return (
    <>
      {open && (
        <div className="settings-panel">
          <div className="s-head">Canvas</div>
          <div className="s-row">
            <span>Dark command center</span>
            <Toggle value={t.dark} onChange={(v) => setTweak("dark", v)} />
          </div>
          <div className="s-head">Status dots</div>
          <div className="s-row">
            <span>Dot style</span>
            <span className="seg">
              {["filled", "ring", "glow"].map((o) => (
                <button
                  key={o}
                  className={t.dotStyle === o ? "on" : ""}
                  onClick={() => setTweak("dotStyle", o)}
                >
                  {o}
                </button>
              ))}
            </span>
          </div>
          <div className="s-row">
            <span>Pulse critical</span>
            <Toggle value={t.pulse} onChange={(v) => setTweak("pulse", v)} />
          </div>
          <div className="s-row">
            <span>Quiet the greens</span>
            <Toggle
              value={t.quietGreens}
              onChange={(v) => setTweak("quietGreens", v)}
            />
          </div>
        </div>
      )}
      <button
        className="settings-fab"
        title="Settings"
        onClick={() => setOpen((o) => !o)}
      >
        {open ? "✕" : "⚙"}
      </button>
    </>
  );
}

Object.assign(window, {
  Dot,
  Avatar,
  SevTag,
  Tag,
  SevText: SEV_TEXT,
  EscalationClock,
  RouteTimeline,
  ReasonRow,
  fmtElapsed,
  Silhouette,
  useTweaks,
  SettingsPanel,
  ActionContext,
});
