/* ============================================================================
   MOWDEW — Reschedule negotiation screens (shared by web + mobile)
   NegotiationCard (viewer-aware, every state) · ReschedQueue (owner inbox,
   desktop + mobile) · HomeReschedStatus (homeowner thread + respond) ·
   NotifScreenM (mobile notifications) · OwnerBellMenu (desktop popover).
   Load AFTER mowdew-kit, mowdew-owner-data, mowdew-resched.
   ========================================================================= */
const { useState: rsState } = React;

/* local vertical pill (MVert lives in the mobile bundle only) */
function RVert({ vert }) {
  const v = VERT(vert);
  return (
    <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, background: v.c50, color: v.c700, border: `1px solid ${v.c100}`, borderRadius: 999, padding: '3px 9px 3px 6px', fontSize: 11, fontWeight: 700, flexShrink: 0 }}>
      <Icon name={v.icon} size={12} strokeWidth={2.3} />{v.name}
    </span>
  );
}

/* ─── status bars for resolved / waiting states ─────────────────────── */
function ReschedStatusBar({ state, text }) {
  const m = {
    approved:  { bg: 'var(--green-50)', fg: 'var(--green-800)', icon: 'check-circle' },
    declined:  { bg: 'var(--alert-50)', fg: 'var(--alert-700)', icon: 'x' },
    cancelled: { bg: 'var(--ink-50)', fg: 'var(--ink-600,#6E6B60)', icon: 'x' },
    waiting:   { bg: 'var(--yellow-50)', fg: 'var(--yellow-700)', icon: 'clock' },
  }[state] || { bg: 'var(--ink-50)', fg: 'var(--ink-700)', icon: 'clock' };
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 9, background: m.bg, borderRadius: 12, padding: '11px 14px', color: m.fg, fontSize: 13, fontWeight: 600, lineHeight: 1.45 }}>
      <Icon name={m.icon} size={16} style={{ flexShrink: 0 }} />{text}
    </div>
  );
}

/* ============================================================================
   NEGOTIATION CARD — the reusable thread card, all states, both viewers
   ========================================================================= */
function NegotiationCard({ req, viewer = 'owner', onAction, compact = false, hideHeader = false }) {
  const c = CUSTOMERS.find(x => x.id === req.cust);
  const w = WORKERS.find(x => x.id === req.worker);
  const first = c.name.split(' ')[0];
  const latest = reqLatestTo(req);
  const names = viewer === 'owner' ? { owner: 'You', homeowner: first } : { owner: 'Diego', homeowner: 'You' };
  const toMeta = req.state === 'approved' ? { label: 'CONFIRMED', tone: 'green' }
    : req.state === 'declined' ? { label: 'ASKED', tone: 'alert' }
    : req.state === 'proposed' ? { label: viewer === 'owner' ? 'YOU SUGGESTED' : 'DIEGO SUGGESTED', tone: 'green' }
    : { label: 'REQUESTED', tone: 'green' };

  const btn = (st = {}) => ({ minHeight: compact ? 42 : 44, fontSize: compact ? 13.5 : 14, padding: '10px 14px', ...st });

  return (
    <div className="card" style={{ padding: compact ? 14 : 17, minWidth: 0, maxWidth: '100%', boxSizing: 'border-box' }} data-comment-anchor={`resched-${req.id}-${viewer}`}>
      {/* header */}
      {!hideHeader && (viewer === 'owner' ? (
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 11, marginBottom: 12 }}>
          <Avatar name={c.name} size={compact ? 38 : 42} />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ flex: 1, minWidth: 0, fontWeight: 700, fontSize: compact ? 14 : 15, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>{c.name}</span>
              <ReschedChip state={req.state} viewer="owner" compact={compact} />
            </div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 6, marginTop: 4, flexWrap: 'wrap' }}>
              <RVert vert={c.vert} />
              {req.rounds > 1 && <span style={{ fontFamily: 'var(--font-mono)', fontSize: 9.5, fontWeight: 600, letterSpacing: '.06em', color: 'var(--yellow-700)', background: 'var(--yellow-50)', border: '1px solid var(--yellow-100)', borderRadius: 7, padding: '2px 7px', flexShrink: 0 }}>ROUND {req.rounds}</span>}
              <span style={{ fontSize: compact ? 11.5 : 12, color: 'var(--ink-500)' }}>{c.addr} · {req.age}</span>
            </div>
          </div>
        </div>
      ) : (
        <div style={{ display: 'flex', alignItems: 'flex-start', gap: 11, marginBottom: 12 }}>
          <Avatar name="Diego Marta" size={compact ? 38 : 42} ring />
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={{ flex: 1, minWidth: 0, fontWeight: 700, fontSize: compact ? 14 : 15, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>Marta Lawn &amp; Pool</span>
              <ReschedChip state={req.state} viewer="homeowner" compact={compact} />
            </div>
            <div style={{ fontSize: compact ? 11.5 : 12, color: 'var(--ink-500)', marginTop: 3 }}>Pool service · Diego decides, you'll hear right here</div>
          </div>
        </div>
      ))}

      {/* assigned pro — always visible, updates live after a reassign */}
      {viewer === 'owner' && !hideHeader && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 9, padding: '7px 11px', background: 'var(--paper)', border: '1px solid var(--ink-100)', borderRadius: 11, marginBottom: compact ? 10 : 12 }}>
          <Avatar name={w.name} size={24} />
          <span style={{ fontSize: compact ? 12 : 12.5, color: 'var(--ink-500)', minWidth: 0, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
            <b style={{ color: 'var(--ink-900)' }}>{w.name}</b>{w.you ? ' · you' : ''} · {w.role}
          </span>
          <span style={{ width: 8, height: 8, borderRadius: '50%', background: w.color, flexShrink: 0 }} aria-hidden="true" />
          {req.state === 'pending' && (
            <button onClick={() => onAction('reassign')} style={{ marginLeft: 'auto', flexShrink: 0, border: 'none', background: 'none', color: 'var(--green-700)', fontWeight: 700, fontSize: 12, cursor: 'pointer', padding: '4px 2px', display: 'inline-flex', alignItems: 'center', gap: 4 }}>
              <Icon name="users" size={13} strokeWidth={2.4} />Change pro
            </button>
          )}
        </div>
      )}

      {/* time change */}
      <TimeChange from={req.orig} to={req.state === 'declined' ? req.thread.find(t => t.to).to : latest} toLabel={toMeta.label} toTone={toMeta.tone} compact={compact} />

      {/* thread */}
      <div style={{ margin: compact ? '12px 0 0' : '14px 0 0' }}>
        <NegotiationThread thread={req.thread} names={names} compact={compact} />
      </div>

      {/* actions / status */}
      <div style={{ marginTop: compact ? 12 : 14 }}>
        {viewer === 'owner' && req.state === 'pending' && (
          <div style={{ display: 'flex', gap: 9, flexWrap: 'wrap' }}>
            <button onClick={() => onAction('decline')} className="btn btn-secondary" style={btn({ flex: 1, color: 'var(--alert-700)' })}>Decline</button>
            <button onClick={() => onAction('propose')} className="btn btn-secondary" style={btn({ flex: 1.2 })}><Icon name="clock" size={16} />Propose time</button>
            <button onClick={() => onAction('approve')} className="btn btn-primary" style={btn({ flex: 1.4 })}><Icon name="check" size={17} />Approve</button>
          </div>
        )}
        {viewer === 'owner' && req.state === 'proposed' && (
          <ReschedStatusBar state="waiting" text={`Waiting on ${first} to respond to ${latest}. They can accept, decline, or counter.`} />
        )}
        {viewer === 'homeowner' && req.state === 'proposed' && (
          <div style={{ display: 'grid', gap: 9 }}>
            <button onClick={() => onAction('accept')} className="btn btn-primary btn-block" style={btn()}><Icon name="check" size={17} />Accept {latest}</button>
            <div style={{ display: 'flex', gap: 9 }}>
              <button onClick={() => onAction('counter')} className="btn btn-secondary" style={btn({ flex: 1.4 })}><Icon name="history" size={16} />Propose another</button>
              <button onClick={() => onAction('declineProposal')} className="btn btn-secondary" style={btn({ flex: 1, color: 'var(--alert-700)' })}>Decline</button>
            </div>
            <button onClick={() => onAction('cancel')} className="btn btn-ghost" style={btn({ minHeight: 34, fontSize: 12.5, color: 'var(--ink-500)' })}>Cancel my request</button>
          </div>
        )}
        {viewer === 'homeowner' && req.state === 'pending' && (
          <div style={{ display: 'grid', gap: 9 }}>
            <ReschedStatusBar state="waiting" text="Sent to Diego — he usually replies within a few hours. You'll get a notification." />
            <button onClick={() => onAction('cancel')} className="btn btn-ghost" style={btn({ minHeight: 36, fontSize: 12.5, color: 'var(--ink-500)' })}>Cancel my request</button>
          </div>
        )}
        {req.state === 'approved' && (
          viewer === 'homeowner' ? (
            <div style={{ display: 'grid', gap: 9 }}>
              <ReschedStatusBar state="approved" text={`Confirmed — your pool visit moved to ${req.final || latest}.`} />
              <button onClick={() => onAction('calendar')} className="btn btn-secondary btn-block" style={btn()}><Icon name="calendar" size={16} />Add to my calendar</button>
            </div>
          ) : (
            <ReschedStatusBar state="approved" text={`Confirmed for ${req.final || latest}. ${w.name.split(' ')[0]}'s route updated — ${first} notified.`} />
          )
        )}
        {req.state === 'declined' && (
          viewer === 'homeowner' ? (
            <div style={{ display: 'grid', gap: 9 }}>
              <ReschedStatusBar state="declined" text={`Diego kept your original time (${req.orig}). "${(req.thread.find(t => t.kind === 'decline') || {}).note || ''}"`} />
              <button onClick={() => onAction('message')} className="btn btn-secondary btn-block" style={btn()}><Icon name="message" size={16} />Message Diego</button>
            </div>
          ) : (
            <ReschedStatusBar state="declined" text={`Declined — ${first} keeps ${req.orig}. They saw your reason.`} />
          )
        )}
        {req.state === 'cancelled' && (
          <ReschedStatusBar state="cancelled" text={viewer === 'owner' ? `${first} cancelled this request — nothing changed.` : 'You cancelled this request — your original time stands.'} />
        )}
      </div>
    </div>
  );
}

/* ============================================================================
   OWNER QUEUE — filterable inbox (desktop + mobile), dialogs included
   ========================================================================= */
function ReschedQueue({ go, toast, compact = false }) {
  const [reqs, setReqs] = rsState(() => RESCHED_REQS.map(q => ({ ...q, thread: [...q.thread] })));
  const [filter, setFilter] = rsState('needs');
  const [dialog, setDialog] = rsState(null); // { type, id }
  const counts = {
    needs: reqs.filter(reqNeedsOwner).length,
    waiting: reqs.filter(reqWaiting).length,
    done: reqs.filter(reqResolved).length,
  };
  const list = reqs.filter(q => filter === 'needs' ? reqNeedsOwner(q) : filter === 'waiting' ? reqWaiting(q) : reqResolved(q));
  const upd = (id, fn) => setReqs(rs => rs.map(q => q.id === id ? fn({ ...q, thread: [...q.thread] }) : q));
  const custOf = (id) => CUSTOMERS.find(x => x.id === reqs.find(q => q.id === id).cust);

  const act = (q, type) => {
    const c = CUSTOMERS.find(x => x.id === q.cust);
    const w = WORKERS.find(x => x.id === q.worker);
    if (type === 'approve') {
      upd(q.id, x => ({ ...x, state: 'approved', final: reqLatestTo(x), thread: [...x.thread, { by: 'owner', kind: 'approve', to: reqLatestTo(x), at: 'Just now' }] }));
      toast(`Approved · ${w.name.split(' ')[0]}'s route updated — ${c.name.split(' ')[0]} notified`, 'green');
    } else setDialog({ type, id: q.id });
  };
  const doDecline = (reason) => {
    const q = reqs.find(x => x.id === dialog.id); const c = custOf(dialog.id);
    upd(q.id, x => ({ ...x, state: 'declined', thread: [...x.thread, { by: 'owner', kind: 'decline', note: reason, at: 'Just now' }] }));
    setDialog(null); toast(`Declined — ${c.name.split(' ')[0]} keeps the original time`, 'blue');
  };
  const doPropose = (time, note) => {
    const q = reqs.find(x => x.id === dialog.id); const c = custOf(dialog.id);
    upd(q.id, x => ({ ...x, state: 'proposed', thread: [...x.thread, { by: 'owner', kind: 'propose', to: time, note: note || undefined, at: 'Just now' }] }));
    setDialog(null); toast(`Suggested ${time} — ${c.name.split(' ')[0]} can accept or counter`, 'green');
  };
  const doReassign = (wid, alsoApprove) => {
    const q = reqs.find(x => x.id === dialog.id); const c = custOf(dialog.id);
    const nw = WORKERS.find(x => x.id === wid);
    upd(q.id, x => ({ ...x, worker: wid,
      thread: [...x.thread,
        { by: 'owner', kind: 'reassign', toWho: nw.name.split(' ')[0], at: 'Just now' },
        ...(alsoApprove ? [{ by: 'owner', kind: 'approve', to: reqLatestTo(x), at: 'Just now' }] : [])],
      ...(alsoApprove ? { state: 'approved', final: reqLatestTo(x) } : {}) }));
    setDialog(null);
    toast(alsoApprove ? `Approved & moved to ${nw.name.split(' ')[0]} — routes rebalanced` : `${c.name.split(' ')[0]} reassigned to ${nw.name.split(' ')[0]}`, 'green');
  };

  const dialogReq = dialog && reqs.find(x => x.id === dialog.id);
  const dialogCust = dialogReq && CUSTOMERS.find(x => x.id === dialogReq.cust);
  const dialogTitle = dialog && {
    decline: `Decline ${dialogCust && dialogCust.name.split(' ')[0]}'s request`,
    propose: 'Propose a new time',
    reassign: 'Reassign to another pro',
  }[dialog.type];
  const dialogBody = dialog && (
    dialog.type === 'decline' ? <DeclineForm onSubmit={doDecline} />
    : dialog.type === 'propose' ? <ProposeForm onSubmit={doPropose} notePlaceholder={`A note for ${dialogCust.name.split(' ')[0]} (optional)…`} />
    : <ReassignForm currentWorker={dialogReq.worker} withApprove={dialogReq.state === 'pending'} onSubmit={doReassign} />
  );

  return (
    <div>
      {/* filter chips */}
      <div style={{ display: 'flex', gap: 7, marginBottom: compact ? 12 : 14 }}>
        {[['needs', 'Needs you'], ['waiting', 'Waiting'], ['done', 'History']].map(([id, lb]) => {
          const on = filter === id;
          return (
            <button key={id} onClick={() => setFilter(id)} style={{ flex: compact ? 1 : 'none', padding: compact ? '9px 6px' : '9px 15px', borderRadius: 11, border: '1px solid', borderColor: on ? 'transparent' : 'var(--ink-200)', cursor: 'pointer', fontSize: 13, fontWeight: 700, background: on ? 'var(--ink-900)' : '#fff', color: on ? '#fff' : 'var(--ink-700)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', gap: 6 }}>
              {lb}<span style={{ background: on ? 'rgba(255,255,255,.22)' : 'var(--ink-100)', color: on ? '#fff' : 'var(--ink-600,#6E6B60)', borderRadius: 99, minWidth: 17, height: 17, padding: '0 5px', fontSize: 10.5, fontWeight: 800, display: 'grid', placeItems: 'center' }}>{counts[id]}</span>
            </button>
          );
        })}
      </div>

      <div style={{ display: 'grid', gap: compact ? 11 : 14 }}>
        {list.map(q => <NegotiationCard key={q.id} req={q} viewer="owner" compact={compact} onAction={(t) => act(q, t)} />)}
        {list.length === 0 && (
          <div style={{ textAlign: 'center', padding: '34px 0 26px', color: 'var(--ink-400,#A8A498)' }}>
            <Sprout size={92} mood="wink" />
            <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 15, color: 'var(--ink-900)', marginTop: 6 }}>
              {filter === 'needs' ? 'Nothing needs you.' : filter === 'waiting' ? 'Nothing in flight.' : 'No resolved requests yet.'}
            </div>
            <div style={{ fontSize: 13, color: 'var(--ink-500)', marginTop: 3 }}>
              {filter === 'needs' ? 'New reschedule requests land here first.' : filter === 'waiting' ? 'Suggestions you send wait here for an answer.' : 'Approved, declined and cancelled requests file here.'}
            </div>
          </div>
        )}
      </div>

      {/* dialogs — Sheet on mobile, Modal on web */}
      {compact ? (
        <Sheet open={!!dialog} onClose={() => setDialog(null)} title={dialogTitle}>{dialogBody}</Sheet>
      ) : (
        <Modal open={!!dialog} onClose={() => setDialog(null)} title={dialogTitle}>{dialogBody}</Modal>
      )}
    </div>
  );
}

/* ============================================================================
   HOMEOWNER — negotiation status / thread screen (h_resched)
   ========================================================================= */
function HomeReschedStatus({ go, toast, params }) {
  const fresh = params && params.fresh;
  const [req, setReq] = rsState(() => fresh
    ? { id: 'qx', cust: 'c2', worker: 'w1', state: 'pending', age: 'Just now', orig: 'Mon, May 18 · 10 AM',
        thread: [{ by: 'homeowner', kind: 'request', to: params.to, note: params.note || undefined, at: 'Just now' }] }
    : (() => { const q = RESCHED_REQS[0]; return { ...q, thread: [...q.thread] }; })());
  const [sheet, setSheet] = rsState(null); // 'counter' | 'decline'
  const latest = reqLatestTo(req);
  const turn = (kind, extra = {}) => ({ by: 'homeowner', kind, at: 'Just now', ...extra });

  const onAction = (type) => {
    if (type === 'accept') {
      setReq(r => ({ ...r, state: 'approved', final: latest, thread: [...r.thread, { by: 'owner', kind: 'approve', to: latest, at: 'Just now' }] }));
      toast(`Confirmed — see you ${latest}`, 'green');
    } else if (type === 'counter') setSheet('counter');
    else if (type === 'declineProposal') setSheet('decline');
    else if (type === 'cancel') {
      setReq(r => ({ ...r, state: 'cancelled', thread: [...r.thread, turn('cancel', { note: 'Cancelled from the app.' })] }));
      toast('Request cancelled — your original time stands', 'blue');
    } else if (type === 'calendar') toast('Added to your calendar', 'green');
    else if (type === 'message') go('h_request');
  };
  const doCounter = (time, note) => {
    setReq(r => ({ ...r, state: 'pending', rounds: (r.rounds || 1) + 1, thread: [...r.thread, turn('counter', { to: time, note: note || undefined })] }));
    setSheet(null); toast(`Sent — Diego will respond to ${time}`, 'green');
  };
  const doDeclineProposal = (reason) => {
    setReq(r => ({ ...r, state: 'declined', thread: [...r.thread, turn('decline', { note: reason })] }));
    setSheet(null); toast('Okay — your original time stands', 'blue');
  };

  return (
    <>
    <Screen padBottom={26}>
      <TopBar title="Reschedule request" subtitle="Pool service · Marta Lawn & Pool" onBack={() => go('h_feed')} />
      <div style={{ padding: '4px 18px 0' }}>
        <NegotiationCard req={req} viewer="homeowner" compact onAction={onAction} />
      </div>
      {req.state === 'approved' && (
        <div style={{ padding: '14px 18px 0' }}>
          <div style={{ background: 'var(--green-700)', borderRadius: 'var(--radius-2xl)', padding: '18px 20px', color: '#fff', display: 'flex', alignItems: 'center', gap: 14, overflow: 'hidden', position: 'relative' }}>
            <div style={{ position: 'relative', flex: 1 }}>
              <Tag tone="green" onDark>All set</Tag>
              <div style={{ fontFamily: 'var(--font-display)', fontWeight: 800, fontSize: 19, letterSpacing: '-0.02em', marginTop: 8, lineHeight: 1.25 }}>Your pool visit moved to {req.final}.</div>
              <div style={{ fontSize: 12.5, color: 'rgba(255,255,255,.85)', marginTop: 4 }}>Diego's route is updated — no need to do anything else.</div>
            </div>
            <Dewy size={86} mood="wave" style={{ flexShrink: 0 }} />
          </div>
        </div>
      )}
      <div style={{ padding: '14px 18px 0', display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 7, fontSize: 12, color: 'var(--ink-500)' }}>
        <Icon name="shield" size={14} style={{ color: 'var(--blue-700)' }} />Every change lands on the route automatically — nothing to text about.
      </div>
    </Screen>
    <Sheet open={sheet === 'counter'} onClose={() => setSheet(null)} title="Propose another time">
      <ProposeForm submitLabel="Send to Diego" notePlaceholder="Tell Diego why (optional)…" onSubmit={doCounter} />
    </Sheet>
    <Sheet open={sheet === 'decline'} onClose={() => setSheet(null)} title="Decline Diego's suggestion">
      <DeclineForm quick={["That day doesn't work", 'Keep my original time', "We'll be away"]} submitLabel="Decline suggestion" onSubmit={doDeclineProposal} />
    </Sheet>
    </>
  );
}

/* ============================================================================
   NOTIFICATIONS — mobile screen (all personas) + desktop bell popover
   ========================================================================= */
function NotifScreenM({ persona, go, toast }) {
  const back = persona === 'owner' ? 'o_home' : persona === 'pro' ? 'pro_today' : 'h_feed';
  const openLink = (n) => {
    const map = persona === 'owner'
      ? { resched: ['o_inbox', { tab: 'approvals' }], billing: ['o_billing_run', {}] }
      : persona === 'homeowner'
      ? { resched: ['h_resched', {}], invoice: ['h_inbox', {}], feed: ['h_feed', {}] }
      : { today: ['pro_today', {}] };
    const t = map[n.link];
    if (t) go(t[0], t[1]);
  };
  return (
    <Screen padBottom={26}>
      <TopBar title="Notifications" onBack={() => go(back)} />
      <div style={{ padding: '4px 18px 0' }}>
        <NotifFeed persona={persona} compact onOpen={openLink} />
      </div>
    </Screen>
  );
}

/* desktop owner — bell + anchored popover in the shell header */
function OwnerBellMenu({ go }) {
  const [open, setOpen] = rsState(false);
  const [, force] = rsState(0);
  const count = notifUnreadCount('owner');
  const openLink = (n) => {
    setOpen(false); force(x => x + 1);
    go(n.link === 'billing' ? 'billingrun' : 'reschedules');
  };
  return (
    <div style={{ position: 'relative' }}>
      <NotifBell count={count} size={40} onClick={() => setOpen(o => !o)} />
      {open && (
        <>
          <div onClick={() => setOpen(false)} style={{ position: 'fixed', inset: 0, zIndex: 70 }} />
          <div style={{ position: 'absolute', right: 0, top: 48, width: 390, zIndex: 71, boxShadow: 'var(--shadow-xl)', borderRadius: 'var(--radius-xl)', animation: 'tnFade .14s ease' }}>
            <NotifFeed persona="owner" compact onOpen={openLink} />
          </div>
        </>
      )}
    </div>
  );
}

Object.assign(window, { RVert, ReschedStatusBar, NegotiationCard, ReschedQueue, HomeReschedStatus, NotifScreenM, OwnerBellMenu });
