/* ============================================================
   Screens: MyBookings, Profile + Booking / Edit / Cancel modals
   ============================================================ */

/* -------------------- CLAIM SPOT MODAL -------------------- */
function ClaimModal({ slot, dayLabel, member, onConfirm, onClose }) {
  const open = 4 - slot.players.length;
  const [transport, setTransport] = useState("walk");
  return (
    <Modal onClose={onClose}>
      <ModalHead title="Claim this spot" sub={`${dayLabel} · Championship 18`} onClose={onClose} />
      <div className="card-pad" style={{ padding: 24 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 14, padding: "14px 16px", background: "var(--brand-soft)", borderRadius: "var(--radius-sm)", marginBottom: 20 }}>
          <Icon name="clock" size={22} style={{ color: "var(--brand)" }} />
          <div>
            <div className="serif" style={{ fontSize: 26, fontWeight: 700, lineHeight: 1 }}>{slot.time}</div>
            <div className="muted" style={{ fontSize: 12.5, marginTop: 3 }}>{open} of 4 spots open</div>
          </div>
        </div>

        {slot.players.length > 0 && (
          <div style={{ marginBottom: 18 }}>
            <div className="eyebrow" style={{ marginBottom: 10 }}>Players in this group</div>
            <div className="stack" style={{ gap: 8 }}>
              {slot.players.map((p, i) => (
                <div key={i} style={{ display: "flex", alignItems: "center", gap: 11 }}>
                  <Avatar initials={p.initials} size={30} />
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 13.5, fontWeight: 600, whiteSpace: "nowrap" }}>{p.name}</div>
                    <div className="faint" style={{ fontSize: 11.5, fontFamily: "ui-monospace, monospace" }}>HI {p.hi} · GHIN {p.ghin}</div>
                  </div>
                </div>
              ))}
            </div>
          </div>
        )}

        <div className="eyebrow" style={{ marginBottom: 10 }}>You'll join as</div>
        <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "12px 14px", borderRadius: "var(--radius-sm)", background: "color-mix(in srgb,var(--accent) 12%,var(--surface))", border: "1px solid var(--accent)" }}>
          <Avatar initials={member.initials} size={36} tone="accent" />
          <div style={{ flex: 1 }}>
            <div style={{ fontSize: 14.5, fontWeight: 700 }}>{member.name}</div>
            <div className="faint" style={{ fontSize: 12, fontFamily: "ui-monospace, monospace" }}>HI {member.handicapIndex ?? "—"} · GHIN {member.ghin || "—"} · CH {member.handicapIndex == null ? "—" : window.YCC.courseHandicapForTee(member.handicapIndex, member.tee || "Blue")} ({member.tee || "Blue"})</div>
          </div>
          <span style={{ color: "var(--accent-deep)" }}><Icon name="shield" size={18} /></span>
        </div>
        <p className="faint" style={{ fontSize: 12, marginTop: 10, lineHeight: 1.5 }}>Your USGA handicap travels with you into this group's weekend game.</p>

        <div className="eyebrow" style={{ margin: "20px 0 10px" }}>Walking or riding?</div>
        <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 10 }}>
          {[["walk", "walk", "Walk", "Carry or push"], ["ride", "cart", "Ride", "Take a cart"]].map(([val, icon, label, sub]) => {
            const on = transport === val;
            return (
              <button key={val} type="button" onClick={() => setTransport(val)} style={{
                display: "flex", alignItems: "center", gap: 11, padding: "13px 14px", borderRadius: "var(--radius-sm)", textAlign: "left",
                border: "1.5px solid " + (on ? "var(--brand)" : "var(--line-strong)"),
                background: on ? "var(--brand-soft)" : "var(--surface)", transition: "all .14s",
              }}>
                <span style={{ width: 36, height: 36, borderRadius: "50%", flex: "0 0 auto", display: "grid", placeItems: "center",
                  background: on ? "var(--brand)" : "var(--surface-2)", color: on ? "var(--on-brand)" : "var(--ink-soft)" }}>
                  <Icon name={icon} size={18} />
                </span>
                <span>
                  <span style={{ display: "block", fontSize: 14.5, fontWeight: 700 }}>{label}</span>
                  <span className="faint" style={{ fontSize: 11.5 }}>{sub}</span>
                </span>
              </button>
            );
          })}
        </div>
        <p className="faint" style={{ fontSize: 11.5, marginTop: 8 }}>Defaults to walking — you can change this anytime before play.</p>

        <div style={{ display: "flex", justifyContent: "flex-end", gap: 10, marginTop: 22, paddingTop: 18, borderTop: "1px solid var(--line)" }}>
          <button className="btn btn-ghost" onClick={onClose}>Cancel</button>
          <button className="btn btn-primary" onClick={() => onConfirm(transport)}><Icon name="check" size={16} /> Confirm my spot</button>
        </div>
      </div>
    </Modal>
  );
}

/* -------------------- MOVE SPOT MODAL -------------------- */
function MoveSpotModal({ booking, fromTime, dateLabel, openSlots, onPick, onClose }) {
  const [sel, setSel] = useState(null);
  const sorted = window.YCC.sortByTime(openSlots);
  return (
    <Modal onClose={onClose}>
      <ModalHead title="Move my spot" sub={`${dateLabel} · currently ${fromTime}`} onClose={onClose} />
      <div style={{ padding: "8px 0 0" }}>
        <div style={{ maxHeight: 320, overflowY: "auto", padding: "8px 24px" }}>
          {sorted.length === 0 && <p className="muted" style={{ fontSize: 14, padding: "20px 0", textAlign: "center" }}>No other groups with an open spot that day.</p>}
          <div className="grid" style={{ gridTemplateColumns: "repeat(3,1fr)", gap: 8 }}>
            {sorted.map(s => (
              <button key={s.id} onClick={() => setSel(s.id)} style={{
                padding: "11px 8px", borderRadius: 9, fontSize: 14, fontWeight: 700, fontFamily: "var(--font-display)",
                border: "1px solid " + (sel === s.id ? "var(--brand)" : "var(--line-strong)"),
                background: sel === s.id ? "var(--brand)" : "var(--surface)", color: sel === s.id ? "var(--on-brand)" : "var(--ink)",
                transition: "all .12s",
              }}>{s.time}<div style={{ fontSize: 10, fontWeight: 500, opacity: .7, fontFamily: "var(--font-body)" }}>{4 - s.players.length} open</div></button>
            ))}
          </div>
        </div>
        <div style={{ display: "flex", justifyContent: "flex-end", gap: 10, padding: "16px 24px", borderTop: "1px solid var(--line)", marginTop: 8 }}>
          <button className="btn btn-ghost" onClick={onClose}>Keep current</button>
          <button className="btn btn-primary" disabled={!sel} onClick={() => onPick(sorted.find(s => s.id === sel))}>Move my spot</button>
        </div>
      </div>
    </Modal>
  );
}

/* -------------------- MANAGER: MOVE ANY PLAYER -------------------- */
function ManagerMoveModal({ player, fromTime, dateLabel, openSlots, onPick, onClose }) {
  const [sel, setSel] = useState(null);
  const sorted = window.YCC.sortByTime(openSlots);
  return (
    <Modal onClose={onClose}>
      <ModalHead title={`Move ${player.name.split(" ")[0]}`} sub={`${dateLabel} · currently ${fromTime}`} onClose={onClose} />
      <div style={{ padding: "16px 24px 0" }}>
        <div style={{ display: "flex", alignItems: "center", gap: 11, padding: "10px 12px", borderRadius: "var(--radius-sm)", background: "var(--surface-2)", marginBottom: 14 }}>
          <Avatar initials={player.initials} size={32} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 13.5, fontWeight: 700 }}>{player.name}{player.guest && <span className="pill" style={{ marginLeft: 7, background: "var(--surface)", color: "var(--ink-soft)", fontSize: 9.5 }}>Added by manager</span>}</div>
            <div className="faint" style={{ fontSize: 11.5, fontFamily: "ui-monospace, monospace" }}>HI {player.hi} · GHIN {player.ghin}</div>
          </div>
        </div>
      </div>
      <div style={{ padding: "0 0 0" }}>
        <div style={{ maxHeight: 300, overflowY: "auto", padding: "0 24px 8px" }}>
          <div className="eyebrow" style={{ marginBottom: 10 }}>Move to another group</div>
          {sorted.length === 0 && <p className="muted" style={{ fontSize: 14, padding: "16px 0", textAlign: "center" }}>No other groups with an open spot that day.</p>}
          <div className="grid" style={{ gridTemplateColumns: "repeat(3,1fr)", gap: 8 }}>
            {sorted.map(s => (
              <button key={s.id} onClick={() => setSel(s.id)} style={{
                padding: "11px 8px", borderRadius: 9, fontSize: 14, fontWeight: 700, fontFamily: "var(--font-display)",
                border: "1px solid " + (sel === s.id ? "var(--brand)" : "var(--line-strong)"),
                background: sel === s.id ? "var(--brand)" : "var(--surface)", color: sel === s.id ? "var(--on-brand)" : "var(--ink)",
                transition: "all .12s",
              }}>{s.time}<div style={{ fontSize: 10, fontWeight: 500, opacity: .7, fontFamily: "var(--font-body)" }}>{4 - s.players.length} open</div></button>
            ))}
          </div>
        </div>
        <div style={{ display: "flex", justifyContent: "flex-end", gap: 10, padding: "16px 24px", borderTop: "1px solid var(--line)", marginTop: 8 }}>
          <button className="btn btn-ghost" onClick={onClose}>Cancel</button>
          <button className="btn btn-primary" disabled={!sel} onClick={() => onPick(sorted.find(s => s.id === sel))}><Icon name="swap" size={15} /> Move player</button>
        </div>
      </div>
    </Modal>
  );
}

/* -------------------- MANAGER: ADD OFF-APP MEMBER -------------------- */
function AddPlayerModal({ slot, dayLabel, members, weekSlots, onAdd, onClose }) {
  const Y = window.YCC;
  const list = members || [];
  const fullName = (m) => `${m.first_name || ""} ${m.last_name || ""}`.trim() || m.email;
  const confirmed = (m) => !!m.handicap_confirmed_at;
  const signedNames = new Set();
  Object.values(weekSlots || {}).forEach(slots => (slots || []).forEach(s => s.players.forEach(p => signedNames.add(p.name))));
  const inThisSlot = new Set(slot.players.map(p => p.name.toLowerCase()));
  const signedUpConfirmed = list.filter(m => signedNames.has(fullName(m)) && confirmed(m));
  const signedIds = new Set(signedUpConfirmed.map(m => m.id));
  const others = list.filter(m => !signedIds.has(m.id));

  const [pick, setPick] = useState(list.length ? "" : "__guest__");
  const [form, setForm] = useState({ name: "", hi: "", ghin: "", tee: "White", transport: "walk" });
  const open = 4 - slot.players.length;
  const dot = { Blue: "#2f5db0", White: "#c7c8b3", Green: "#3a7a4f", Gold: "#b08d4f", Red: "#9e3b2f" };

  function selectPick(v) {
    setPick(v);
    if (v === "__guest__" || v === "") { setForm({ name: "", hi: "", ghin: "", tee: "White", transport: "walk" }); return; }
    const m = list.find(x => x.id === v);
    if (m) setForm({ name: fullName(m), hi: m.handicap_index == null ? "" : String(m.handicap_index), ghin: m.ghin || "", tee: m.tee || "White", transport: "walk" });
  }
  const isGuest = pick === "__guest__";
  const isMember = !!pick && pick !== "__guest__";
  const selMember = isMember ? list.find(m => m.id === pick) : null;
  const dupe = (isMember || isGuest) && inThisSlot.has((form.name || "").trim().toLowerCase());
  const canAdd = open > 0 && !!form.name.trim() && (isGuest || isMember) && !dupe;
  function submit() {
    onAdd({ name: form.name.trim(), hi: form.hi, ghin: form.ghin, tee: form.tee, transport: form.transport, guest: isGuest, memberId: isMember ? pick : undefined });
  }

  return (
    <Modal onClose={onClose}>
      <ModalHead title="Add a member" sub={`${slot.time} · ${dayLabel}`} onClose={onClose} />
      <div style={{ padding: 24 }}>
        <div className="field">
          <label>Who are you adding?</label>
          <select className="input" autoFocus value={pick} onChange={e => selectPick(e.target.value)} style={{ appearance: "auto" }}>
            <option value="">Select a member…</option>
            {signedUpConfirmed.length > 0 && (
              <optgroup label="Signed up this week · confirmed">
                {signedUpConfirmed.map(m => <option key={m.id} value={m.id}>{fullName(m)} · HI {m.handicap_index ?? "—"}</option>)}
              </optgroup>
            )}
            {others.length > 0 && (
              <optgroup label="All DIV Tour members">
                {others.map(m => <option key={m.id} value={m.id}>{fullName(m)}{confirmed(m) ? " ✓" : ""} · HI {m.handicap_index ?? "—"}</option>)}
              </optgroup>
            )}
            <option value="__guest__">Other — add a guest…</option>
          </select>
          {dupe && <div className="err-msg">Already in this group.</div>}
        </div>

        {isGuest && (
          <>
            <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "10px 14px", borderRadius: "var(--radius-sm)", background: "var(--brand-soft)", color: "var(--brand)", margin: "0 0 16px", fontSize: 12.5, lineHeight: 1.4 }}>
              <Icon name="info" size={16} style={{ flex: "0 0 auto" }} />
              <span>A guest who isn't on the DIV Tour app. You're adding them on their behalf — their handicap drives the weekend game.</span>
            </div>
            <div className="field"><label>Full name</label><input className="input" value={form.name} onChange={e => setForm({ ...form, name: e.target.value })} placeholder="e.g. Tom Bradley" /></div>
          </>
        )}

        {isMember && selMember && (
          <div style={{ display: "flex", alignItems: "center", gap: 11, padding: "11px 13px", borderRadius: "var(--radius-sm)", background: "var(--surface-2)", marginBottom: 16 }}>
            <Avatar initials={(form.name || "?").split(/\s+/).map(s => s[0]).join("").slice(0, 2).toUpperCase()} size={34} />
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ fontSize: 14, fontWeight: 700, display: "flex", alignItems: "center", gap: 7 }}>{form.name}
                {confirmed(selMember)
                  ? <span className="pill" style={{ background: "var(--brand-soft)", color: "var(--brand)", fontSize: 9.5 }}><Icon name="check" size={10} /> Confirmed</span>
                  : <span className="pill" style={{ background: "color-mix(in srgb,var(--danger) 12%,transparent)", color: "var(--danger)", fontSize: 9.5 }}>Not confirmed</span>}
              </div>
              <div className="faint" style={{ fontSize: 11.5, fontFamily: "ui-monospace, monospace" }}>GHIN {form.ghin || "—"}</div>
            </div>
          </div>
        )}
        {(isGuest || isMember) && (
          <>
            <div className="grid" style={{ gridTemplateColumns: isGuest ? "1fr 1fr" : "1fr" }}>
              <div className="field"><label>Handicap Index</label><input className="input" inputMode="decimal" value={form.hi} onChange={e => setForm({ ...form, hi: e.target.value.replace(/[^0-9.]/g, "").slice(0, 4) })} placeholder="e.g. 14.2" /></div>
              {isGuest && <div className="field"><label>GHIN <span className="faint" style={{ fontWeight: 400 }}>(optional)</span></label><input className="input" value={form.ghin} onChange={e => setForm({ ...form, ghin: e.target.value.replace(/[^0-9]/g, "").slice(0, 8) })} style={{ fontFamily: "ui-monospace, monospace" }} placeholder="8-digit" /></div>}
            </div>
            <div className="field">
              <label>Tees</label>
          <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(82px, 1fr))", gap: 8 }}>
            {Y.TEES.map(t => {
              const on = form.tee === t.name;
              return (
                <button key={t.name} type="button" onClick={() => setForm({ ...form, tee: t.name })} style={{
                  display: "flex", alignItems: "center", gap: 7, padding: "9px 11px", borderRadius: 9,
                  border: "1.5px solid " + (on ? "var(--brand)" : "var(--line-strong)"),
                  background: on ? "var(--brand-soft)" : "var(--surface)", transition: "all .12s",
                }}>
                  <span style={{ width: 11, height: 11, borderRadius: "50%", background: dot[t.name], border: "1px solid rgba(0,0,0,.15)" }}></span>
                  <span style={{ fontSize: 12.5, fontWeight: 700 }}>{t.name}</span>
                </button>
              );
            })}
          </div>
        </div>
        <div className="field" style={{ marginBottom: 0 }}>
          <label>Walking or riding?</label>
          <div style={{ display: "flex", gap: 8 }}>
            {[["walk", "walk", "Walk"], ["ride", "cart", "Ride"]].map(([val, icon, label]) => {
              const on = form.transport === val;
              return (
                <button key={val} type="button" onClick={() => setForm({ ...form, transport: val })} style={{
                  flex: 1, display: "flex", alignItems: "center", justifyContent: "center", gap: 8, padding: "11px", borderRadius: 9,
                  border: "1.5px solid " + (on ? "var(--brand)" : "var(--line-strong)"),
                  background: on ? "var(--brand-soft)" : "var(--surface)", color: on ? "var(--brand)" : "var(--ink-soft)", fontWeight: 700, fontSize: 13.5, transition: "all .12s",
                }}><Icon name={icon} size={16} /> {label}</button>
              );
            })}
          </div>
        </div>
          </>
        )}
        <div style={{ display: "flex", justifyContent: "flex-end", gap: 10, marginTop: 22, paddingTop: 18, borderTop: "1px solid var(--line)" }}>
          <button className="btn btn-ghost" onClick={onClose}>Cancel</button>
          <button className="btn btn-primary" disabled={!canAdd} onClick={submit}><Icon name="plus" size={16} /> Add to group</button>
        </div>
      </div>
    </Modal>
  );
}

/* -------------------- REQUEST A CHANGE (email the primary manager) -------------------- */
// Once member self-service closes (Wed 11:59 PM ET) the tee sheet is managed by
// the tour manager. Members compose a change request that opens in their email app,
// pre-addressed to the primary manager with their current spots filled in.
function RequestChangeModal({ member, primary, primaryEmail, bookings, slotOf, tour, phase, toast, onClose }) {
  const Y = window.YCC;
  const rows = (bookings || [])
    .map(b => ({ b, slot: slotOf(b) }))
    .filter(x => x.slot)
    .sort((a, b) => a.b.dateISO.localeCompare(b.b.dateISO) || Y.parseTime(a.slot.time) - Y.parseTime(b.slot.time));
  const KINDS = [
    ["move", "Move to a different tee time"],
    ["release", "Release / cancel a spot"],
    ["add", "Add me to a group"],
    ["group", "Change who's in my group"],
    ["other", "Something else"],
  ];
  const [kind, setKind] = useState("move");
  const [note, setNote] = useState("");
  const contacts = (Y.CLUB_CONTACTS || []);
  const [cc, setCc] = useState([]);
  const toggleCc = (email) => setCc((prev) => prev.includes(email) ? prev.filter((e) => e !== email) : [...prev, email]);
  const primaryName = (primary && primary.name) || "the DIV Tour Manager";
  const lockedCopy = phase === "locked"
    ? "The Friday 9:00 AM ET lock has passed, so groups are final."
    : "Member sign-ups are closed for this week.";

  function buildBody() {
    const kindLabel = (KINDS.find(k => k[0] === kind) || [])[1] || "Change request";
    const lines = [];
    lines.push(`Hi ${primaryName.split(" ")[0]},`);
    lines.push("");
    lines.push(`I'd like to request a change to my DIV Tour entry for the weekend of ${tour.weekendLabel}.`);
    lines.push("");
    lines.push(`Request type: ${kindLabel}`);
    if (rows.length) {
      lines.push("");
      lines.push("My current spot(s):");
      rows.forEach(({ b, slot }) => {
        lines.push(`  • ${Y.fmtDate(new Date(b.dateISO + "T00:00:00"))} — ${slot.time}`);
      });
    } else {
      lines.push("");
      lines.push("I don't currently have a spot this weekend.");
    }
    lines.push("");
    lines.push("Details:");
    lines.push(note.trim() || "(add any specifics here)");
    lines.push("");
    lines.push("Thanks,");
    lines.push(member.name || "");
    lines.push(`HI ${member.handicapIndex ?? "—"} · GHIN ${member.ghin || "—"}${member.phone ? " · " + member.phone : ""}`);
    return lines.join("\n");
  }

  function send() {
    const subject = `DIV Tour change request — ${member.name} (${tour.weekendLabel})`;
    // Always copy the requester at the email they signed up with, plus any chosen club inboxes.
    const selfEmail = (member.email || "").trim();
    const ccList = [...cc];
    if (selfEmail && selfEmail.toLowerCase() !== (primaryEmail || "").toLowerCase() && !ccList.some((e) => e.toLowerCase() === selfEmail.toLowerCase())) ccList.push(selfEmail);
    const ccPart = ccList.length ? `&cc=${encodeURIComponent(ccList.join(","))}` : "";
    const url = `mailto:${encodeURIComponent(primaryEmail)}?subject=${encodeURIComponent(subject)}${ccPart}&body=${encodeURIComponent(buildBody())}`;
    try { window.location.href = url; } catch (e) {}
    if (toast) toast("Opening your email app…");
    onClose();
  }

  return (
    <Modal onClose={onClose}>
      <ModalHead title="Request a change" sub="Sign-ups are closed — your manager makes changes" onClose={onClose} />
      <div className="card-pad" style={{ padding: 24 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "12px 14px", borderRadius: "var(--radius-sm)", background: "color-mix(in srgb,var(--accent) 12%,var(--surface))", border: "1px solid var(--accent)", marginBottom: 18 }}>
          <Icon name="clock" size={18} style={{ color: "var(--accent-deep)", flex: "0 0 auto" }} />
          <div style={{ fontSize: 12.5, lineHeight: 1.5 }}>{lockedCopy} Send your request to the primary manager and they'll take care of it.</div>
        </div>

        <div className="eyebrow" style={{ marginBottom: 10 }}>Goes to</div>
        <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "12px 14px", borderRadius: "var(--radius-sm)", background: "var(--surface-2)", marginBottom: 18 }}>
          <Avatar initials={(primary && primary.initials) || "M"} size={36} tone="brand" />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 14, fontWeight: 700 }}>{primaryName}</div>
            <div className="faint" style={{ fontSize: 12, display: "flex", alignItems: "center", gap: 6, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}><Icon name="mail" size={12} /> {primaryEmail}</div>
          </div>
          <span className="pill pill-green" style={{ whiteSpace: "nowrap" }}>Primary</span>
        </div>

        {contacts.length > 0 && (
          <div style={{ marginBottom: 18 }}>
            <div className="eyebrow" style={{ marginBottom: 10 }}>Also notify <span className="faint" style={{ textTransform: "none", letterSpacing: 0, fontWeight: 500 }}>(optional CC)</span></div>
            <div style={{ display: "flex", gap: 8, flexWrap: "wrap" }}>
              {contacts.map((c) => {
                const on = cc.includes(c.email);
                return (
                  <button key={c.id} type="button" onClick={() => toggleCc(c.email)} title={c.email} style={{
                    display: "inline-flex", alignItems: "center", gap: 8, padding: "8px 13px", borderRadius: 999,
                    border: "1.5px solid " + (on ? "var(--brand)" : "var(--line-strong)"),
                    background: on ? "var(--brand-soft)" : "var(--surface)", color: on ? "var(--brand)" : "var(--ink)", transition: "all .12s",
                  }}>
                    <Icon name={on ? "check" : "mail"} size={14} />
                    <span style={{ fontSize: 12.5, fontWeight: 700 }}>{c.name}</span>
                  </button>
                );
              })}
            </div>
          </div>
        )}

        {rows.length > 0 && (
          <div style={{ marginBottom: 18 }}>
            <div className="eyebrow" style={{ marginBottom: 10 }}>Your current spot{rows.length > 1 ? "s" : ""}</div>
            <div className="stack" style={{ gap: 8 }}>
              {rows.map(({ b, slot }) => (
                <div key={b.id} style={{ display: "flex", alignItems: "center", gap: 10, padding: "9px 13px", borderRadius: "var(--radius-sm)", background: "var(--surface-2)" }}>
                  <Icon name="clock" size={15} style={{ color: "var(--accent-deep)" }} />
                  <span className="serif" style={{ fontSize: 18, fontWeight: 700 }}>{slot.time}</span>
                  <span className="faint" style={{ fontSize: 12.5 }}>{Y.fmtDate(new Date(b.dateISO + "T00:00:00"))}</span>
                </div>
              ))}
            </div>
          </div>
        )}

        <div className="field">
          <label>What do you need?</label>
          <select className="input" value={kind} onChange={e => setKind(e.target.value)} style={{ appearance: "auto" }}>
            {KINDS.map(([v, l]) => <option key={v} value={v}>{l}</option>)}
          </select>
        </div>
        <div className="field" style={{ marginBottom: 4 }}>
          <label>Details for the manager</label>
          <textarea className="input" value={note} onChange={e => setNote(e.target.value)} rows={4}
            placeholder="e.g. Please move me from the 8:00 group to the 8:30 group on Saturday — I have a conflict in the morning."
            style={{ resize: "vertical", minHeight: 90, lineHeight: 1.5 }} />
          <div className="hint">This opens your email app with the message ready to send — review it before sending. A copy goes to you at <strong>{member.email}</strong>.</div>
        </div>

        <div style={{ display: "flex", justifyContent: "flex-end", gap: 10, marginTop: 18, paddingTop: 18, borderTop: "1px solid var(--line)" }}>
          <button className="btn btn-ghost" onClick={onClose}>Cancel</button>
          <button className="btn btn-primary" disabled={!primaryEmail} onClick={send}><Icon name="mail" size={16} /> Compose email</button>
        </div>
      </div>
    </Modal>
  );
}

/* -------------------- CANCEL CONFIRM -------------------- */
function ConfirmModal({ title, body, confirmLabel, danger, onConfirm, onClose }) {
  return (
    <Modal onClose={onClose}>
      <div style={{ padding: 26 }}>
        <h3 className="serif" style={{ fontSize: 23, fontWeight: 600 }}>{title}</h3>
        <p className="muted" style={{ fontSize: 14.5, margin: "10px 0 22px", lineHeight: 1.55 }}>{body}</p>
        <div style={{ display: "flex", justifyContent: "flex-end", gap: 10 }}>
          <button className="btn btn-ghost" onClick={onClose}>Keep it</button>
          <button className={"btn " + (danger ? "btn-danger" : "btn-primary")} onClick={onConfirm}>{confirmLabel}</button>
        </div>
      </div>
    </Modal>
  );
}

/* -------------------- MY TEE TIMES -------------------- */
function MyBookings({ ctx }) {
  const Y = window.YCC;
  const { bookings, member, slotOf, go, requestEdit, requestCancel, daysUntil, setTransport, phase, entry, confirmedNames, requestManagerEmail, primaryManager } = ctx;
  const memberOpen = phase === "open";
  const approved = !!(member && confirmedNames && confirmedNames.has(member.name));
  const rows = bookings
    .map(b => ({ b, slot: slotOf(b) }))
    .filter(x => x.slot)
    .sort((a, b) => a.b.dateISO.localeCompare(b.b.dateISO) || Y.parseTime(a.slot.time) - Y.parseTime(b.slot.time));

  return (
    <div className="page fade-in">
      <div className="page-head" style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", flexWrap: "wrap", gap: 16 }}>
        <div>
          <div className="eyebrow">DIV Tour · My spots</div>
          <h1 style={{ marginTop: 6 }}>My tee times</h1>
          <p>{memberOpen ? "The spots you've claimed in this weekend's entry. Move or release your own spot until Wednesday 11:59 PM ET — after that, changes go through your manager." : "Member changes are closed for this weekend. Contact your manager to add, move, or release a spot."}</p>
        </div>
        <button className="btn btn-accent" onClick={() => memberOpen ? go("book") : requestManagerEmail()}>
          {memberOpen ? <><Icon name="plus" size={16} /> Claim another spot</> : <><Icon name="mail" size={16} /> Request a change</>}
        </button>
      </div>

      {!memberOpen && (
        <div style={{ display: "flex", alignItems: "center", gap: 12, padding: "13px 16px", borderRadius: "var(--radius)", background: "color-mix(in srgb,var(--accent) 12%,var(--surface))", border: "1px solid var(--accent)", marginBottom: 20, flexWrap: "wrap" }}>
          <Icon name="clock" size={18} style={{ color: "var(--accent-deep)", flex: "0 0 auto" }} />
          <div style={{ flex: 1, minWidth: 220, fontSize: 13, lineHeight: 1.45 }}>
            <strong>{phase === "locked" ? "Groups are final for this weekend." : "Member sign-ups are closed."}</strong> Need to move, release, or change a spot? Email {(primaryManager && primaryManager.name) || "your manager"} to request it.
          </div>
          <button className="btn btn-primary btn-sm" onClick={requestManagerEmail}><Icon name="mail" size={14} /> Request a change</button>
        </div>
      )}

      {rows.length === 0 ? (
        <div className="card card-pad" style={{ textAlign: "center", padding: 48 }}>
          <Icon name="calendar" size={30} style={{ color: "var(--ink-faint)" }} />
          <h3 className="serif" style={{ fontSize: 22, marginTop: 12 }}>No spots claimed</h3>
          <p className="muted" style={{ fontSize: 14, margin: "6px 0 18px" }}>Head to the tee times to claim an open spot for the weekend.</p>
          <button className="btn btn-primary" onClick={() => go("book")}>View tee times</button>
        </div>
      ) : (
        <div className="stack">
          {rows.map(({ b, slot }) => {
            const dateLabel = Y.fmtDate(new Date(b.dateISO + "T00:00:00"));
            return (
              <div key={b.id} className="card" style={{ overflow: "hidden", display: "flex", alignItems: "stretch", flexWrap: "wrap" }}>
                <div style={{ background: "var(--brand)", color: "var(--on-brand)", padding: "20px 24px", display: "flex", flexDirection: "column", justifyContent: "center", minWidth: 168 }}>
                  <div className="serif" style={{ fontSize: 30, fontWeight: 700, lineHeight: 1, whiteSpace: "nowrap" }}>{slot.time}</div>
                  <div style={{ fontSize: 13, marginTop: 7, color: "rgba(244,241,230,.8)", whiteSpace: "nowrap" }}>{dateLabel}</div>
                  <span className="pill" style={{ background: "var(--accent)", color: "#1b1404", marginTop: 12, alignSelf: "flex-start" }}>{daysUntil(b.dateISO)}</span>
                </div>
                <div className="card-pad" style={{ flex: 1, minWidth: 240, display: "flex", flexDirection: "column", justifyContent: "center" }}>
                  <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 12 }}>
                    <Icon name="pin" size={15} style={{ color: "var(--accent-deep)" }} />
                    <span style={{ fontWeight: 600, fontSize: 14 }}>Championship 18 · DIV Tour</span>
                    <span className="pill pill-green" style={{ marginLeft: 4 }}>{slot.players.length} of 4</span>
                  </div>
                  <div style={{ display: "flex", flexWrap: "wrap", gap: 8 }}>
                    {slot.players.map((p, i) => (
                      <span key={i} title={`HI ${p.hi} · GHIN ${p.ghin}`} style={{ display: "flex", alignItems: "center", gap: 7, padding: "4px 11px 4px 4px", background: p.name === member.name ? "color-mix(in srgb,var(--accent) 18%,var(--surface))" : "var(--surface-2)", borderRadius: 999, fontSize: 12.5, fontWeight: 600 }}>
                        <Avatar initials={p.initials} size={20} tone={p.name === member.name ? "accent" : "brand"} />
                        {p.name === member.name ? "You" : p.name} · {p.hi}
                        <Icon name={p.transport === "ride" ? "cart" : "walk"} size={13} style={{ color: "var(--ink-faint)" }} title={p.transport === "ride" ? "Riding" : "Walking"} />
                      </span>
                    ))}
                  </div>
                </div>
                <div style={{ display: "flex", flexDirection: "column", justifyContent: "center", gap: 8, padding: "var(--card-pad)", borderLeft: "1px solid var(--line)" }} className="booking-actions">
                  <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 8, marginBottom: 2 }}>
                    <span className="faint" style={{ fontSize: 11, fontWeight: 700, letterSpacing: ".05em", textTransform: "uppercase" }}>Transport</span>
                    <Transport mode={slot.players.find(p => p.name === member.name)?.transport || "walk"} size="md"
                      onToggle={() => setTransport(b.dateISO, slot.id, member.name, (slot.players.find(p => p.name === member.name)?.transport || "walk") === "walk" ? "ride" : "walk")} />
                  </div>
                  {memberOpen ? (
                    <>
                      <button className="btn btn-quiet btn-sm" onClick={() => requestEdit(b)}><Icon name="swap" size={14} /> Move spot</button>
                      <button className="btn btn-danger btn-sm" onClick={() => requestCancel(b)}><Icon name="trash" size={14} /> Release</button>
                    </>
                  ) : (
                    <button className="btn btn-quiet btn-sm" onClick={requestManagerEmail} title={`Email ${(primaryManager && primaryManager.name) || "your manager"} to request a change`}><Icon name="mail" size={14} /> Request change</button>
                  )}
                  <span className="pill" style={{ marginTop: 2, justifyContent: "center", background: approved ? "var(--brand-soft)" : "color-mix(in srgb,var(--accent) 16%,transparent)", color: approved ? "var(--brand)" : "var(--accent-deep)" }} title={approved ? "Handicap confirmed for this week" : "Your manager must confirm your handicap before Friday 9 AM ET"}>
                    <Icon name={approved ? "check" : "clock"} size={11} /> {approved ? "Approved" : "Pending HCP"}
                  </span>
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

/* -------------------- PROFILE -------------------- */
function Profile({ ctx }) {
  const { member, setMember, toast } = ctx;
  const Y = window.YCC;
  const [form, setForm] = useState({ first: member.first, last: member.last, phone: member.phone, ghin: member.ghin, tee: member.tee || "White", handicapIndex: member.handicapIndex ?? "" });
  const dirty = form.first !== member.first || form.last !== member.last || form.phone !== member.phone || form.ghin !== member.ghin || form.tee !== (member.tee || "White") || String(form.handicapIndex) !== String(member.handicapIndex ?? "");

  function save() {
    const hi = form.handicapIndex === "" || form.handicapIndex == null ? null : Number(form.handicapIndex);
    const name = `${form.first} ${form.last}`.trim();
    // Saving a handicap counts as the weekly handicap confirmation (unblocks booking).
    if (hi != null) { try { localStorage.setItem("ycc_ghin_sync_" + ((member.email) || "").toLowerCase(), String(Date.now())); } catch (e) {} }
    setSaveState({ busy: true, msg: "", ok: null });
    const next = { ...member, first: form.first, last: form.last, name, initials: (name || "?").split(/\s+/).map(s => s[0]).join("").slice(0, 2).toUpperCase(), phone: form.phone, ghin: form.ghin, tee: form.tee, handicapIndex: hi };
    Promise.resolve(setMember(next)).then((res) => {
      if (res && res.ok === false) setSaveState({ busy: false, ok: false, msg: res.error || "Save failed." });
      else setSaveState({ busy: false, ok: true, msg: res && res.local ? "Saved on this device." : "Saved to your account." });
    });
  }
  const [saveState, setSaveState] = useState({ busy: false, ok: null, msg: "" });
  const incomplete = !(member.first && member.last && member.ghin);
  const [ghinBusy, setGhinBusy] = useState(false);
  const [ghinMsg, setGhinMsg] = useState("");
  const [ghinOpen, setGhinOpen] = useState(false);
  const [gLogin, setGLogin] = useState({ id: member.ghin || "", pw: "" });

  function openGhin() { setGhinMsg(""); setGLogin(g => ({ ...g, id: g.id || member.ghin || "" })); setGhinOpen(true); }

  function connectGhin() {
    const db = window.YCCdb;
    setGhinMsg(""); setGhinBusy(true);
    const finish = (msg) => { setGhinBusy(false); setGhinMsg(msg); };
    if (!db || !db.loginGhin) { finish("GHIN connect isn't available yet."); return; }
    const timer = setTimeout(() => finish("GHIN is taking too long — try again or enter your index manually."), 12000);
    db.loginGhin(gLogin.id.trim(), gLogin.pw).then((res) => {
      clearTimeout(timer); setGhinBusy(false);
      if (res && res.handicapIndex != null) {
        try { localStorage.setItem("ycc_ghin_sync_" + ((member.email) || "").toLowerCase(), String(Date.now())); } catch (e) {}
        setForm(f => ({
          ...f,
          handicapIndex: res.handicapIndex,
          ghin: res.ghin || f.ghin,
          first: f.first || res.first || "",
          last: f.last || res.last || "",
        }));
        setGhinMsg(`Connected — index ${res.handicapIndex}${res.ghin ? " · GHIN " + res.ghin : ""}. Review and save below.`);
        setGLogin({ id: "", pw: "" });
        setGhinOpen(false);
      } else {
        setGhinMsg((res && res.error) || "Couldn't retrieve your handicap. You can enter it manually.");
      }
    }).catch(() => { clearTimeout(timer); finish("Couldn't reach GHIN. Enter your index manually."); });
  }

  return (
    <div className="page fade-in">
      <div className="page-head">
        <div className="eyebrow">Member account</div>
        <h1 style={{ marginTop: 6 }}>Profile</h1>
        <p>{incomplete ? "Welcome! Complete your profile below to start booking tee times." : "Your membership details and USGA handicap information."}</p>
      </div>

      {incomplete && (
        <div style={{ display: "flex", alignItems: "center", gap: 10, padding: "12px 16px", borderRadius: "var(--radius)", background: "color-mix(in srgb,var(--accent) 14%,var(--surface))", border: "1px solid var(--accent)", marginBottom: 20, fontSize: 13.5 }}>
          <Icon name="info" size={16} style={{ color: "var(--accent-deep)" }} />
          <span style={{ fontWeight: 600 }}>Add your name and GHIN number, then save to finish setting up your account.</span>
        </div>
      )}

      <div className="grid" style={{ gridTemplateColumns: "1fr 1.4fr", alignItems: "start" }}>
        {/* identity card */}
        <div className="card" style={{ overflow: "hidden" }}>
          <div style={{ background: "var(--brand)", padding: "28px 26px", color: "var(--on-brand)", display: "flex", alignItems: "center", gap: 16, backgroundImage: "radial-gradient(100% 100% at 100% 0%, rgba(180,144,78,.25), transparent 60%)" }}>
            <div style={{ width: 60, height: 60, borderRadius: "50%", background: "var(--accent)", color: "var(--brand-deep)", display: "grid", placeItems: "center", fontWeight: 700, fontSize: 22, fontFamily: "var(--font-display)" }}>{member.initials}</div>
            <div>
              <div className="serif" style={{ fontSize: 26, fontWeight: 600, lineHeight: 1.05 }}>{member.name}</div>
              <div style={{ fontSize: 12.5, color: "rgba(244,241,230,.75)", marginTop: 4 }}>{member.tier}{member.memberSince ? " · Since " + member.memberSince : ""}</div>
            </div>
          </div>
          <div className="card-pad">
            <div style={{ display: "flex", justifyContent: "space-between", padding: "10px 0", borderBottom: "1px solid var(--line)" }}>
              <span className="muted" style={{ fontSize: 13.5, whiteSpace: "nowrap" }}>Handicap Index</span>
              <span className="serif" style={{ fontSize: 22, fontWeight: 600, color: "var(--brand)" }}>{member.handicapIndex ?? "—"}</span>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", padding: "10px 0", borderBottom: "1px solid var(--line)" }}>
              <span className="muted" style={{ fontSize: 13.5, whiteSpace: "nowrap" }}>Course Handicap</span>
              <span style={{ fontWeight: 700, fontSize: 15 }}>{member.handicapIndex == null ? "—" : Y.courseHandicapForTee(member.handicapIndex, member.tee || "Blue")}</span>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", padding: "10px 0", borderBottom: "1px solid var(--line)" }}>
              <span className="muted" style={{ fontSize: 13.5, whiteSpace: "nowrap" }}>Tees</span>
              <span style={{ fontWeight: 700, fontSize: 14 }}>{member.tee || "Blue"} · {Y.teeByName(member.tee || "Blue").rating.toFixed(1)}/{Y.teeByName(member.tee || "Blue").slope}</span>
            </div>
            <div style={{ display: "flex", justifyContent: "space-between", padding: "10px 0" }}>
              <span className="muted" style={{ fontSize: 13.5, whiteSpace: "nowrap" }}>Home Club</span>
              <span style={{ fontWeight: 600, fontSize: 14 }}>{member.homeClub}</span>
            </div>
            <div style={{ marginTop: 14, padding: "12px 14px", background: "var(--surface-2)", borderRadius: "var(--radius-sm)", display: "flex", alignItems: "center", gap: 10 }}>
              <Icon name="shield" size={18} style={{ color: "var(--accent-deep)" }} />
              <div>
                <div style={{ fontSize: 11, fontWeight: 700, letterSpacing: ".08em", textTransform: "uppercase", color: "var(--ink-soft)", whiteSpace: "nowrap" }}>GHIN Number</div>
                <div style={{ fontFamily: "ui-monospace, monospace", fontSize: 17, fontWeight: 700, letterSpacing: ".05em" }}>{member.ghin}</div>
              </div>
            </div>
          </div>
        </div>

        {/* editable details */}
        <div className="card">
          <div className="card-head"><h3>Account details</h3>{dirty && <span className="pill pill-accent">Unsaved changes</span>}</div>
          <div className="card-pad">
            <div className="grid" style={{ gridTemplateColumns: "1fr 1fr" }}>
              <div className="field"><label>First name</label><input className="input" value={form.first} onChange={e => setForm({ ...form, first: e.target.value })} placeholder="First name" /></div>
              <div className="field"><label>Last name</label><input className="input" value={form.last} onChange={e => setForm({ ...form, last: e.target.value })} placeholder="Last name" /></div>
            </div>
            <div className="field">
              <label>Email address</label>
              <input className="input" type="email" value={member.email} disabled style={{ opacity: .7 }} />
              <div className="hint">Your sign-in email — can't be changed here.</div>
            </div>
            <div className="grid" style={{ gridTemplateColumns: "1fr 1fr" }}>
              <div className="field"><label>Mobile phone</label><input className="input" value={form.phone} onChange={e => setForm({ ...form, phone: Y.formatPhone(e.target.value) })} placeholder="(215) 555-0100" inputMode="tel" /></div>
              <div className="field">
                <label>Handicap Index</label>
                <input className="input" inputMode="decimal" value={form.handicapIndex} onChange={e => setForm({ ...form, handicapIndex: e.target.value.replace(/[^0-9.]/g, "").slice(0, 4) })} placeholder="e.g. 12.4" />
                <div className="hint">Your current USGA index. Your tour manager confirms handicaps each week.</div>
              </div>
            </div>
            <div className="field">
              <label>GHIN number</label>
              <input className="input" value={form.ghin} onChange={e => setForm({ ...form, ghin: e.target.value.replace(/[^0-9]/g, "").slice(0, 8) })} style={{ fontFamily: "ui-monospace, monospace" }} placeholder="8-digit GHIN" />
              <div className="hint">{ghinMsg || "Links your USGA handicap to weekend games. Your manager confirms your index each week."}</div>
            </div>
            <div className="field">
              <label>Default tees — used for your handicap</label>
              <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(96px, 1fr))", gap: 8, marginTop: 4 }}>
                {Y.TEES.map(t => {
                  const on = form.tee === t.name;
                  const dot = { Blue: "#2f5db0", White: "#c7c8b3", Green: "#3a7a4f", Gold: "#b08d4f", Red: "#9e3b2f" }[t.name];
                  return (
                    <button key={t.name} type="button" onClick={() => setForm({ ...form, tee: t.name })} style={{
                      display: "flex", flexDirection: "column", alignItems: "flex-start", gap: 4, padding: "10px 12px", borderRadius: 10, textAlign: "left",
                      border: "1.5px solid " + (on ? "var(--brand)" : "var(--line-strong)"),
                      background: on ? "var(--brand-soft)" : "var(--surface)", transition: "all .12s",
                    }}>
                      <span style={{ display: "flex", alignItems: "center", gap: 7 }}>
                        <span style={{ width: 12, height: 12, borderRadius: "50%", background: dot, border: "1px solid rgba(0,0,0,.15)" }}></span>
                        <span style={{ fontSize: 13, fontWeight: 700 }}>{t.name}</span>
                      </span>
                      <span className="faint" style={{ fontSize: 11, fontFamily: "ui-monospace, monospace" }}>{t.rating.toFixed(1)}/{t.slope}</span>
                      <span className="faint" style={{ fontSize: 11 }}>CH {member.handicapIndex == null ? "—" : Y.courseHandicapForTee(member.handicapIndex, t.name)}</span>
                    </button>
                  );
                })}
              </div>
              <div className="hint">Determines your course handicap and the strokes you get on each hole. Red &amp; Gold play to a different index than Blue/White.</div>
            </div>
            <div style={{ display: "flex", justifyContent: "flex-end", gap: 10, marginTop: 8, alignItems: "center", flexWrap: "wrap" }}>
              {saveState.msg && (
                <span style={{ marginRight: "auto", fontSize: 13, fontWeight: 600, color: saveState.ok ? "var(--ok)" : "var(--danger)", display: "flex", alignItems: "center", gap: 6 }}>
                  <Icon name={saveState.ok ? "checkCircle" : "info"} size={15} /> {saveState.msg}
                </span>
              )}
              <button className="btn btn-ghost" disabled={!dirty || saveState.busy} onClick={() => setForm({ first: member.first, last: member.last, phone: member.phone, ghin: member.ghin, tee: member.tee || "White", handicapIndex: member.handicapIndex ?? "" })}>Reset</button>
              <button className="btn btn-primary" disabled={!dirty || saveState.busy} onClick={save}><Icon name="check" size={16} /> {saveState.busy ? "Saving…" : "Save changes"}</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { ClaimModal, MoveSpotModal, ManagerMoveModal, AddPlayerModal, ConfirmModal, RequestChangeModal, MyBookings, Profile });
