// ===== ExpenseModal.jsx — add / edit a charge =====

function Dropdown({ trigger, children, width, align }) {
  const [open, setOpen] = useState(false);
  const [pos, setPos] = useState(null);
  const ref = useRef(null);
  useEffect(() => {
    const h = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", h);
    return () => document.removeEventListener("mousedown", h);
  }, []);
  // Position the menu with fixed coords clamped to the viewport, so it never
  // gets cut off regardless of where the trigger sits (left/right, any width).
  useEffect(() => {
    if (!open) return;
    const place = () => {
      if (!ref.current) return;
      const r = ref.current.getBoundingClientRect();
      const vw = document.documentElement.clientWidth;
      const w = Math.min(typeof width === "number" ? width : r.width, vw - 16);
      let left = align === "right" ? r.right - w : r.left;
      left = Math.max(8, Math.min(left, vw - w - 8));
      setPos({ top: r.bottom + 6, left, width: w });
    };
    place();
    window.addEventListener("resize", place);
    window.addEventListener("scroll", place, true);
    return () => { window.removeEventListener("resize", place); window.removeEventListener("scroll", place, true); };
  }, [open, width, align]);
  return (
    <div ref={ref} style={{ position: "relative" }}>
      {trigger(open, () => setOpen((o) => !o))}
      {open && pos && (
        <div className="card" style={{ position: "fixed", top: pos.top, left: pos.left, width: pos.width, zIndex: 60, padding: 6, maxHeight: "min(60vh, 360px)", overflowY: "auto" }}>
          {children(() => setOpen(false))}
        </div>
      )}
    </div>
  );
}

function PersonSelect({ value, people, onChange }) {
  const sel = people.find((p) => p.id === value);
  const selIdx = people.findIndex((p) => p.id === value);
  return (
    <Dropdown
      trigger={(open, toggle) => (
        <button type="button" onClick={toggle} className="inp" style={{ display: "flex", alignItems: "center", gap: 10, cursor: "pointer", textAlign: "left" }}>
          {sel ? <Avatar person={sel} idx={selIdx} size={24} /> : null}
          <span style={{ flex: 1, minWidth: 0, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap", color: sel ? "var(--text)" : "var(--faint)" }}>{sel ? sel.name : "Select…"}</span>
          <span style={{ color: "var(--faint)", display: "inline-flex", flex: "none" }}><Icon name="chevron" size={16} /></span>
        </button>
      )}
    >
      {(close) => people.map((p, i) => (
        <button key={p.id} type="button" onClick={() => { onChange(p.id); close(); }}
          className="menu-item" style={{ background: p.id === value ? "var(--surface-2)" : "transparent" }}>
          <Avatar person={p} idx={i} size={24} />
          <span style={{ flex: 1, textAlign: "left" }}>{p.name}</span>
          {p.id === value && <span style={{ color: "var(--accent)" }}><Icon name="check" size={16} /></span>}
        </button>
      ))}
    </Dropdown>
  );
}

function CategorySelect({ value, onChange }) {
  const sel = catOf(value);
  return (
    <Dropdown
      trigger={(open, toggle) => (
        <button type="button" onClick={toggle} className="inp" style={{ display: "flex", alignItems: "center", gap: 10, cursor: "pointer", textAlign: "left" }}>
          <CatIcon id={sel.id} size={18} />
          <span style={{ flex: 1, color: "var(--text)" }}>{sel.label}</span>
          <span style={{ color: "var(--faint)", display: "inline-flex" }}><Icon name="chevron" size={16} /></span>
        </button>
      )}
    >
      {(close) => CATEGORIES.map((c) => (
        <button key={c.id} type="button" onClick={() => { onChange(c.id); close(); }}
          className="menu-item" style={{ background: c.id === value ? "var(--surface-2)" : "transparent" }}>
          <CatIcon id={c.id} size={18} />
          <span style={{ flex: 1, textAlign: "left" }}>{c.label}</span>
          {c.id === value && <span style={{ color: "var(--accent)" }}><Icon name="check" size={16} /></span>}
        </button>
      ))}
    </Dropdown>
  );
}

function ExpenseModal({ people, initial, onSave, onClose }) {
  const idxOf = (id) => people.findIndex((p) => p.id === id);

  const [desc, setDesc] = useState(initial?.description || "");
  const [amount, setAmount] = useState(initial?.amount != null ? String(initial.amount) : "");
  const [category, setCategory] = useState(initial?.category || "food");
  const [date, setDate] = useState(initial?.date || todayISO());
  const [note, setNote] = useState(initial?.note || "");
  const [multiPayer, setMultiPayer] = useState((initial?.payers?.length || 0) > 1);
  const [payers, setPayers] = useState(
    initial?.payers?.length ? initial.payers.map((p) => ({ ...p, amount: String(p.amount) }))
      : [{ personId: people[0]?.id, amount: "" }]
  );
  const [participants, setParticipants] = useState(
    initial?.participants?.length ? initial.participants : people.map((p) => p.id)
  );
  const [splitMode, setSplitMode] = useState(initial?.splitMode || "equal");
  const [splits, setSplits] = useState(() => {
    const s = {};
    people.forEach((p) => (s[p.id] = initial?.splits?.[p.id] != null ? String(initial.splits[p.id]) : ""));
    return s;
  });

  const amtNum = Number(amount) || 0;

  useEffect(() => {
    if (!multiPayer) setPayers((ps) => [{ personId: ps[0]?.personId || people[0]?.id, amount: amount }]);
  }, [amount, multiPayer]);

  const txnDraft = {
    amount: amtNum, participants, splitMode,
    splits: Object.fromEntries(Object.entries(splits).map(([k, v]) => [k, Number(v) || 0])),
    payers: payers.map((p) => ({ personId: p.personId, amount: Number(p.amount) || 0 })),
  };

  const sStatus = splitStatus(txnDraft);
  const pStatus = payerStatus(txnDraft);
  const sharePreview = computeShares(txnDraft, people);

  const togglePart = (id) => setParticipants((cur) => (cur.includes(id) ? cur.filter((x) => x !== id) : [...cur, id]));
  const setSplit = (id, v) => setSplits((s) => ({ ...s, [id]: v }));

  const switchMode = (m) => {
    setSplitMode(m);
    if (m === "shares") {
      setSplits((s) => {
        const next = { ...s };
        participants.forEach((id) => { if (!(Number(next[id]) > 0)) next[id] = "1"; });
        return next;
      });
    }
  };
  const bumpShare = (id, d) => setSplits((s) => ({ ...s, [id]: String(Math.max(0, (Number(s[id]) || 0) + d)) }));

  const fillEqualExact = () => {
    const total = toCents(amtNum), n = participants.length;
    if (!n) return;
    const base = Math.floor(total / n);
    let rem = total - base * n;
    const next = { ...splits };
    participants.forEach((id, i) => (next[id] = fromCents(base + (i < rem ? 1 : 0)).toFixed(2)));
    setSplits(next);
  };
  const fillEqualPercent = () => {
    const n = participants.length;
    if (!n) return;
    const each = Math.floor(10000 / n) / 100;
    const next = { ...splits };
    let acc = 0;
    participants.forEach((id, i) => {
      if (i === n - 1) next[id] = String(Math.round((100 - acc) * 100) / 100);
      else { next[id] = String(each); acc += each; }
    });
    setSplits(next);
  };

  const addPayer = () => {
    const used = new Set(payers.map((p) => p.personId));
    const next = people.find((p) => !used.has(p.id));
    setPayers((ps) => [...ps, { personId: next?.id || people[0]?.id, amount: "" }]);
  };
  const removePayer = (i) => setPayers((ps) => ps.filter((_, k) => k !== i));
  const setPayer = (i, patch) => setPayers((ps) => ps.map((p, k) => (k === i ? { ...p, ...patch } : p)));

  const canSave = desc.trim() && amtNum > 0 && participants.length > 0 && pStatus.ok && sStatus.ok;

  const submit = () => {
    if (!canSave) return;
    onSave({
      id: initial?.id || uid(),
      description: desc.trim(), amount: amtNum, category, date, note: note.trim(),
      payers: txnDraft.payers, participants, splitMode, splits: txnDraft.splits,
      createdAt: initial?.createdAt || Date.now(),
    });
  };

  useEffect(() => {
    const h = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", h);
    return () => window.removeEventListener("keydown", h);
  }, []);

  const totalShares = participants.reduce((s, id) => s + (Number(splits[id]) || 0), 0);
  const fieldLabel = (t) => <div className="label" style={{ marginBottom: 9 }}>{t}</div>;

  return (
    <div className="modal-backdrop" onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal">
        <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "20px 24px" }}>
          <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
            <span style={{ color: "var(--accent)", display: "inline-flex" }}><Icon name="receipt" size={22} /></span>
            <h2 className="display" style={{ fontSize: 19, fontWeight: 600 }}>{initial ? "Edit charge" : "Add a charge"}</h2>
          </div>
          <button className="btn btn-icon btn-quiet" onClick={onClose} aria-label="Close"><Icon name="close" size={18} /></button>
        </div>
        <hr className="divider" />

        <div style={{ padding: 24, display: "flex", flexDirection: "column", gap: 20 }}>
          <div className="modal-grid2" style={{ display: "grid", gridTemplateColumns: "1fr 168px", gap: 14 }}>
            <div>
              {fieldLabel("What was it for")}
              <input type="text" value={desc} autoFocus onChange={(e) => setDesc(e.target.value)} placeholder="Dinner at the beach shack" />
            </div>
            <div>
              {fieldLabel("Amount")}
              <div style={{ position: "relative" }}>
                <span style={{ position: "absolute", left: 14, top: "50%", transform: "translateY(-50%)", color: "var(--faint)", fontWeight: 600 }}>$</span>
                <input type="number" className="mono" value={amount} onChange={(e) => setAmount(e.target.value)} placeholder="0.00" style={{ paddingLeft: 28, textAlign: "right" }} min="0" step="0.01" />
              </div>
            </div>
          </div>

          <div className="modal-grid2" style={{ display: "grid", gridTemplateColumns: "1fr 168px", gap: 14 }}>
            <div>
              {fieldLabel("Category")}
              <CategorySelect value={category} onChange={setCategory} />
            </div>
            <div>
              {fieldLabel("Date")}
              <input type="date" className="mono inp" value={date} onChange={(e) => setDate(e.target.value)} style={{ colorScheme: "dark" }} />
            </div>
          </div>

          {/* paid by */}
          <div>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 9 }}>
              <div className="label">Paid by</div>
              <button className="btn btn-sm btn-quiet" style={{ height: 28 }} onClick={() => {
                if (multiPayer) { setMultiPayer(false); setPayers([{ personId: payers[0]?.personId || people[0]?.id, amount }]); }
                else { setMultiPayer(true); setPayers([{ personId: payers[0]?.personId || people[0]?.id, amount: amount || "" }]); }
              }}>
                <Icon name="split" size={15} /> {multiPayer ? "Single payer" : "Split the bill"}
              </button>
            </div>
            {!multiPayer ? (
              <PersonSelect value={payers[0]?.personId} people={people} onChange={(id) => setPayer(0, { personId: id })} />
            ) : (
              <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
                {payers.map((p, i) => (
                  <div key={i} className="payer-row" style={{ display: "grid", gridTemplateColumns: "minmax(0, 1fr) 150px 34px", gap: 8 }}>
                    <PersonSelect value={p.personId} people={people} onChange={(id) => setPayer(i, { personId: id })} />
                    <div style={{ position: "relative" }}>
                      <span style={{ position: "absolute", left: 12, top: "50%", transform: "translateY(-50%)", color: "var(--faint)", fontWeight: 600 }}>$</span>
                      <input type="number" className="mono" value={p.amount} onChange={(e) => setPayer(i, { amount: e.target.value })} placeholder="0.00" style={{ paddingLeft: 26, textAlign: "right" }} min="0" step="0.01" />
                    </div>
                    <button className="btn btn-icon btn-quiet" onClick={() => removePayer(i)} disabled={payers.length <= 1} aria-label="Remove payer"><Icon name="trash" size={16} /></button>
                  </div>
                ))}
                <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginTop: 2 }}>
                  <button className="btn btn-sm btn-ghost" onClick={addPayer} disabled={payers.length >= people.length}><Icon name="plus" size={15} /> Add payer</button>
                  <span className="mono" style={{ fontSize: 13, fontWeight: 600, color: pStatus.ok ? "var(--pos)" : "var(--neg)" }}>
                    {pStatus.ok ? "Balanced" : `${money(pStatus.remaining)} ${pStatus.remaining > 0 ? "left" : "over"}`}
                  </span>
                </div>
              </div>
            )}
          </div>

          {/* split between */}
          <div>
            <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 9, flexWrap: "wrap", gap: 8 }}>
              <div className="label">Split between</div>
              <div style={{ display: "flex", gap: 8 }}>
                <button className="btn btn-sm btn-quiet" style={{ height: 28 }} onClick={() => setParticipants(people.map((p) => p.id))}>All</button>
                <button className="btn btn-sm btn-quiet" style={{ height: 28 }} onClick={() => setParticipants([])}>None</button>
              </div>
            </div>
            <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
              {people.map((p, i) => {
                const on = participants.includes(p.id);
                return (
                  <button key={p.id} className={"pill" + (on ? " on" : "")} onClick={() => togglePart(p.id)}>
                    <Avatar person={p} idx={i} size={24} />
                    <span>{p.name}</span>
                    {on && <span style={{ color: "var(--accent)", display: "inline-flex", marginLeft: -2 }}><Icon name="check" size={15} /></span>}
                  </button>
                );
              })}
            </div>
          </div>

          {/* split method */}
          {participants.length > 0 && (
            <div>
              <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 11, flexWrap: "wrap", gap: 10 }}>
                <div className="seg">
                  <button className={splitMode === "equal" ? "on" : ""} onClick={() => switchMode("equal")}>Equally</button>
                  <button className={splitMode === "exact" ? "on" : ""} onClick={() => switchMode("exact")}>Exact $</button>
                  <button className={splitMode === "percent" ? "on" : ""} onClick={() => switchMode("percent")}>Percent</button>
                  <button className={splitMode === "shares" ? "on" : ""} onClick={() => switchMode("shares")}>Shares</button>
                </div>
                {splitMode === "exact" && <button className="btn btn-sm btn-quiet" onClick={fillEqualExact}>Distribute evenly</button>}
                {splitMode === "percent" && <button className="btn btn-sm btn-quiet" onClick={fillEqualPercent}>Distribute evenly</button>}
                {splitMode === "shares" && <button className="btn btn-sm btn-quiet" onClick={() => { const n = {}; participants.forEach((id) => (n[id] = "1")); setSplits((s) => ({ ...s, ...n })); }}>Reset to 1 each</button>}
              </div>

              <div className="card" style={{ background: "var(--bg-2)", padding: 6 }}>
                {participants.map((id) => {
                  const p = people.find((x) => x.id === id);
                  const i = idxOf(id);
                  const shareC = sharePreview[id] || 0;
                  return (
                    <div key={id} style={{ display: "flex", alignItems: "center", gap: 11, padding: "8px 10px" }}>
                      <Avatar person={p} idx={i} size={26} />
                      <span style={{ flex: 1, fontWeight: 500 }}>{p?.name}</span>
                      {splitMode === "equal" && <span className="mono" style={{ color: "var(--muted)", fontWeight: 600 }}>{money(fromCents(shareC))}</span>}
                      {splitMode === "exact" && (
                        <div style={{ position: "relative", width: 130 }}>
                          <span style={{ position: "absolute", left: 11, top: "50%", transform: "translateY(-50%)", color: "var(--faint)", fontWeight: 600, fontSize: 14 }}>$</span>
                          <input type="number" className="mono inp" value={splits[id] || ""} onChange={(e) => setSplit(id, e.target.value)} placeholder="0.00" style={{ height: 38, paddingLeft: 24, paddingRight: 10, textAlign: "right" }} min="0" step="0.01" />
                        </div>
                      )}
                      {splitMode === "percent" && (
                        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
                          <span className="mono" style={{ color: "var(--faint)", fontSize: 13, minWidth: 58, textAlign: "right" }}>{money(fromCents(shareC))}</span>
                          <div style={{ position: "relative", width: 96 }}>
                            <span style={{ position: "absolute", right: 11, top: "50%", transform: "translateY(-50%)", color: "var(--faint)", fontWeight: 600, fontSize: 14 }}>%</span>
                            <input type="number" className="mono inp" value={splits[id] || ""} onChange={(e) => setSplit(id, e.target.value)} placeholder="0" style={{ height: 38, paddingRight: 24, paddingLeft: 10, textAlign: "right" }} min="0" step="0.1" />
                          </div>
                        </div>
                      )}
                      {splitMode === "shares" && (
                        <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
                          <span className="mono" style={{ color: "var(--faint)", fontSize: 13, minWidth: 58, textAlign: "right" }}>{money(fromCents(shareC))}</span>
                          <div className="stepper">
                            <button onClick={() => bumpShare(id, -1)} aria-label="Less"><Icon name="minus" size={15} /></button>
                            <span className="mono" style={{ minWidth: 22, textAlign: "center", fontWeight: 700 }}>{Number(splits[id]) || 0}</span>
                            <button onClick={() => bumpShare(id, 1)} aria-label="More"><Icon name="plus" size={15} /></button>
                          </div>
                        </div>
                      )}
                    </div>
                  );
                })}
                {splitMode !== "equal" && (
                  <>
                    <hr className="divider" style={{ margin: "4px 4px" }} />
                    <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "8px 10px" }}>
                      <span style={{ fontSize: 13, color: "var(--muted)", fontWeight: 600 }}>
                        {splitMode === "shares" ? `Split into ${totalShares} share${totalShares === 1 ? "" : "s"}`
                          : sStatus.ok ? "Adds up perfectly"
                          : "Needs to total " + (splitMode === "percent" ? "100%" : money(sStatus.target))}
                      </span>
                      <span className="mono" style={{ fontSize: 13.5, fontWeight: 700, color: sStatus.ok ? "var(--pos)" : "var(--neg)" }}>
                        {splitMode === "shares" ? (sStatus.ok ? "even by share" : "add a share")
                          : sStatus.ok ? (splitMode === "percent" ? "100%" : money(sStatus.target))
                          : (splitMode === "percent" ? `${sStatus.remaining}% left` : `${money(sStatus.remaining)} left`)}
                      </span>
                    </div>
                  </>
                )}
              </div>
            </div>
          )}

          <div>
            {fieldLabel("Note (optional)")}
            <textarea value={note} onChange={(e) => setNote(e.target.value)} rows={2} className="inp"
              placeholder="Add context — e.g. why the split isn't even, or what's included…"
              style={{ height: "auto", minHeight: 62, padding: "10px 14px", resize: "vertical", lineHeight: 1.45 }} />
          </div>
        </div>

        <hr className="divider" />
        <div className="modal-foot" style={{ display: "flex", alignItems: "center", justifyContent: "space-between", padding: "16px 24px", gap: 12 }}>
          <span style={{ fontSize: 13, color: "var(--faint)" }}>
            {participants.length} {participants.length === 1 ? "person" : "people"} · {money(amtNum)}
          </span>
          <div className="foot-actions" style={{ display: "flex", gap: 10 }}>
            <button className="btn btn-ghost" onClick={onClose}>Cancel</button>
            <button className="btn btn-accent" onClick={submit} disabled={!canSave}>
              <Icon name="check" size={17} /> {initial ? "Save changes" : "Add charge"}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { ExpenseModal, PersonSelect, CategorySelect, Dropdown });
