// Pocket Marshal — Chat screen (presentational; AI state lives in pm-app.jsx)

function PMTypingDots({ theme }) {
  return (
    <div style={{ display: 'flex', gap: 5, padding: '14px 16px' }}>
      {[0, 1, 2].map((i) => (
        <span key={i} style={{
          width: 8, height: 8, borderRadius: '50%', background: theme.muted,
          animation: `pm-bounce 1.2s ${i * 0.18}s infinite ease-in-out`,
        }}></span>
      ))}
    </div>
  );
}

// Always 12-hour with AM/PM, whatever the phone's clock is set to — a record
// reads "2:15 PM", not "14:15". Recent days get a name, older ones a date.
function pmStampText(ms) {
  const d = new Date(ms);
  const now = new Date();
  const time = d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit', hour12: true });
  if (d.toDateString() === now.toDateString()) return 'Today ' + time;
  const y = new Date(now); y.setDate(y.getDate() - 1);
  if (d.toDateString() === y.toDateString()) return 'Yesterday ' + time;
  const days = (now - d) / 86400000;
  if (days < 7) return d.toLocaleDateString('en-US', { weekday: 'long' }) + ' ' + time;
  const sameYear = d.getFullYear() === now.getFullYear();
  const date = d.toLocaleDateString('en-US', sameYear
    ? { month: 'short', day: 'numeric' }
    : { month: 'short', day: 'numeric', year: 'numeric' });
  return date + ' \u00b7 ' + time;
}

function pmGapLabelShort(ms) {
  const mins = Math.round(ms / 60000);
  if (mins < 120) return Math.max(1, Math.round(mins / 15) * 15) + ' minutes';
  const hrs = Math.round(mins / 60);
  if (hrs < 24) return hrs + ' hours';
  const days = Math.round(hrs / 24);
  return days <= 1 ? 'a day' : days + ' days';
}

function PMTimeDivider({ at, theme, gapMs }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 10, margin: '2px 0' }}>
      <div style={{ flex: 1, height: 1, background: theme.line }}></div>
      <span style={{
        fontSize: '0.72em', fontWeight: 700, letterSpacing: '.06em', textTransform: 'uppercase',
        color: theme.muted, whiteSpace: 'nowrap',
      }}>{pmStampText(at)}</span>
      <div style={{ flex: 1, height: 1, background: theme.line }}></div>
    </div>
  );
}

function PMMessage({ msg, theme, t, onCite, onRate, inspectorName }) {
  const isUser = msg.role === 'user';
  if (isUser) {
    return (
      <div style={{ display: 'flex', justifyContent: 'flex-end' }}>
        <div style={{ maxWidth: '78%', display: 'flex', flexDirection: 'column', alignItems: 'flex-end', gap: 6 }}>
          {msg.photo && (
            <img src={msg.photo} alt="Inspection photo" style={{
              maxWidth: 240, maxHeight: 240, borderRadius: 14, border: `2px solid ${theme.line}`, display: 'block', objectFit: 'cover',
            }} />
          )}
          {msg.text && (
            <div style={{
              background: theme.userBubble, color: theme.userInk,
              borderRadius: '16px 16px 4px 16px', padding: '12px 16px',
              fontSize: '1em', lineHeight: 1.45, fontWeight: 500, whiteSpace: 'pre-wrap',
            }}>{msg.text}</div>
          )}
        </div>
      </div>
    );
  }
  if (msg.verdict) {
    return (
      <div style={{ display: 'flex', gap: 10, alignItems: 'flex-start' }}>
        {t.avatar !== 'none' && <MarshalAvatar styleKind={t.avatar} size={34} />}
        <div style={{ flex: 1, minWidth: 0, maxWidth: 560, display: 'flex', flexDirection: 'column', gap: 10 }}>
          {msg.text && (
            <div style={{
              alignSelf: 'flex-start', background: theme.paper, border: `1.5px solid ${theme.line}`,
              borderRadius: t.avatar === 'none' ? '16px 16px 16px 4px' : '4px 16px 16px 16px',
              padding: '12px 16px', color: theme.ink, fontSize: '1em',
            }}>
              <PMRichText text={msg.text} theme={theme} />
            </div>
          )}
          <PMVerdictCard verdict={msg.verdict} theme={theme} onCite={onCite} rating={msg.rating} onRate={onRate}
            onCopy={() => pmCopyOrShare(pmVerdictToText(msg.verdict, msg.text, { at: msg.at, model: msg.model }))}
            onEscalate={() => pmCopyOrShare(pmEscalationText(msg.verdict, msg.text, { at: msg.at }, inspectorName), 'Escalation \u2014 Pocket Marshal')} />
        </div>
      </div>
    );
  }
  return (
    <div style={{ display: 'flex', gap: 10, alignItems: 'flex-start' }}>
      {t.avatar !== 'none' && <MarshalAvatar styleKind={t.avatar} size={34} />}
      <div style={{
        maxWidth: '82%', background: theme.paper, border: `1.5px solid ${theme.line}`,
        borderRadius: t.avatar === 'none' ? '16px 16px 16px 4px' : '4px 16px 16px 16px',
        padding: '13px 16px', color: theme.ink, fontSize: '1em',
      }}>
        <PMRichText text={msg.text} theme={theme} />
      </div>
    </div>
  );
}

// Tagging a conversation to a property is what lets Marshal see prior visits
// there. Kept explicit and inspector-controlled: nothing links two buildings
// unless someone says they're the same building.
function PMPropertyBar({ theme, property, onSetProperty, priorVisitCount }) {
  const [editing, setEditing] = React.useState(false);
  const [draft, setDraft] = React.useState(property || '');
  React.useEffect(() => { setDraft(property || ''); }, [property]);
  const commit = () => { onSetProperty(draft); setEditing(false); };
  if (editing) {
    return (
      <div style={{ display: 'flex', gap: 8, padding: '8px 16px', alignItems: 'center' }}>
        <input autoFocus value={draft} onChange={(e) => setDraft(e.target.value)}
          onKeyDown={(e) => { if (e.key === 'Enter') commit(); if (e.key === 'Escape') setEditing(false); }}
          placeholder="Business name or address" spellCheck="false"
          style={{
            flex: 1, minWidth: 0, boxSizing: 'border-box', minHeight: 44, padding: '0 12px',
            border: `2px solid ${theme.focusRing}`, borderRadius: 11, font: 'inherit',
            fontSize: '0.92em', fontWeight: 700, color: theme.ink, background: theme.paper, outline: 'none',
          }} />
        <button onClick={commit} style={{
          minHeight: 44, padding: '0 14px', borderRadius: 11, border: 'none', cursor: 'pointer',
          font: 'inherit', fontWeight: 800, fontSize: '0.86em', background: theme.cta, color: theme.ctaInk,
        }}>Save</button>
      </div>
    );
  }
  return (
    <div style={{ padding: '6px 16px 0' }}>
      <button onClick={() => setEditing(true)} style={{
        display: 'flex', alignItems: 'center', gap: 8, width: '100%', boxSizing: 'border-box',
        minHeight: 40, padding: '6px 10px', borderRadius: 10, cursor: 'pointer', font: 'inherit',
        textAlign: 'left', background: 'transparent',
        border: `1px ${property ? 'solid' : 'dashed'} ${theme.line}`,
      }}>
        <span style={{ color: theme.muted, display: 'grid', placeItems: 'center', flexShrink: 0 }}><IconBuilding size={16} /></span>
        <span style={{
          flex: 1, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
          fontWeight: property ? 750 : 600, fontSize: '0.83em',
          color: property ? theme.ink : theme.muted,
        }}>{property || 'Tag this property'}</span>
        {priorVisitCount > 0 && (
          <span style={{
            fontSize: '0.68em', fontWeight: 900, letterSpacing: '0.05em', textTransform: 'uppercase',
            color: theme.amberDark, background: theme.amberSoft, border: `1px solid ${theme.citeBorder}`,
            borderRadius: 5, padding: '2px 6px', whiteSpace: 'nowrap', flexShrink: 0,
          }}>{priorVisitCount} prior visit{priorVisitCount === 1 ? '' : 's'}</span>
        )}
      </button>
    </div>
  );
}

function PMChat({ theme, t, messages, busy, onSend, onNewSession, onChip, onCite, onRate, inspectorName, property, onSetProperty, priorVisitCount, prefill, onPrefillConsumed }) {
  const scrollRef = React.useRef(null);
  // After a real break, offer a clean break — never take it automatically.
  const [gapDismissed, setGapDismissed] = React.useState(false);
  const lastAt = React.useMemo(() => {
    for (let i = messages.length - 1; i >= 0; i--) if (messages[i].at) return messages[i].at;
    return null;
  }, [messages]);
  // Inspectors read a determination with their hands full — don't let the screen sleep.
  React.useEffect(() => {
    if (!('wakeLock' in navigator) || messages.length === 0) return;
    let lock = null, released = false;
    const acquire = async () => {
      try { lock = await navigator.wakeLock.request('screen'); } catch (e) { /* denied or unsupported */ }
    };
    const onVisible = () => { if (document.visibilityState === 'visible' && !released) acquire(); };
    acquire();
    document.addEventListener('visibilitychange', onVisible);
    return () => {
      released = true;
      document.removeEventListener('visibilitychange', onVisible);
      try { lock && lock.release(); } catch (e) { /* noop */ }
    };
  }, [messages.length > 0]);

  const [now, setNow] = React.useState(() => Date.now());
  React.useEffect(() => {
    const id = setInterval(() => setNow(Date.now()), 60000);
    return () => clearInterval(id);
  }, []);
  React.useEffect(() => { setGapDismissed(false); }, [messages.length === 0]);
  const staleFor = lastAt ? now - lastAt : 0;
  const showNewStop = !busy && !gapDismissed && messages.length > 0 && staleFor >= 90 * 60000;
  React.useEffect(() => {
    const el = scrollRef.current;
    if (el) el.scrollTop = el.scrollHeight;
  }, [messages.length, busy]);

  const empty = messages.length === 0;
  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}>
      {/* Chat header */}
      <div style={{
        display: 'flex', alignItems: 'center', gap: 12, padding: '12px 20px',
        background: theme.headerBg, borderBottom: `1.5px solid ${theme.line}`,
        flexShrink: 0,
      }}>
        <MarshalAvatar styleKind={t.avatar === 'none' ? 'badge' : t.avatar} size={40} />
        <div style={{ flex: 1, minWidth: 0 }}>
          <div style={{ fontWeight: 800, fontSize: '1.1em', color: theme.headerInk, lineHeight: 1.2 }}>Marshal</div>
          <div style={{ fontSize: '0.8em', fontWeight: 600, color: theme.headerSub }}>Florida Fire Prevention Code · NFPA</div>
        </div>
        {messages.length > 0 && (
          <button onClick={onNewSession} style={{
            display: 'flex', alignItems: 'center', gap: 7, minHeight: 44, padding: '0 14px',
            borderRadius: 12, border: `2px solid ${theme.line}`,
            background: 'transparent', color: theme.headerInk, font: 'inherit', fontWeight: 700, fontSize: '0.9em', cursor: 'pointer',
          }}><IconPlusChat size={19} /> New</button>
        )}
      </div>

      {onSetProperty && (
        <div style={{ flexShrink: 0, maxWidth: 680, width: '100%', margin: '0 auto', boxSizing: 'border-box' }}>
          <PMPropertyBar theme={theme} property={property} onSetProperty={onSetProperty} priorVisitCount={priorVisitCount} />
        </div>
      )}

      {/* Messages */}
      <div ref={scrollRef} style={{ flex: 1, overflowY: 'auto', padding: '14px 20px 8px', scrollBehavior: 'smooth' }}>
        <div style={{ maxWidth: 680, margin: '0 auto', display: 'flex', flexDirection: 'column', gap: 16 }}>
          {empty && !busy && (
            <div style={{ textAlign: 'center', padding: '48px 16px 24px' }}>
              <div style={{ display: 'inline-block' }}><MarshalAvatar styleKind={t.avatar === 'none' ? 'badge' : t.avatar} size={t.avatar === 'mascot' ? 110 : 64} float={t.avatar === 'mascot'} /></div>
              <h2 style={{ margin: '16px 0 6px', fontSize: '1.35em', fontWeight: 800, color: theme.ink }}>I'm right here with you.</h2>
              <p style={{ margin: '0 auto', maxWidth: 420, color: theme.muted, fontSize: '0.98em', lineHeight: 1.5, fontWeight: 500, textWrap: 'pretty' }}>
                Tell me what you're seeing on site — or snap a photo and I'll walk through it with you — and we'll work out the right call together, code section and all.
              </p>
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 10, justifyContent: 'center', marginTop: 22 }}>
                {PM_CHIPS.map((c) => {
                  const Ic = c.icon;
                  return (
                    <button key={c.id} onClick={() => onChip(c)} data-chip={c.id} style={{
                      display: 'flex', alignItems: 'center', gap: 8, minHeight: 48, padding: '0 16px',
                      background: theme.paper, border: `2px solid ${theme.chipBorder}`, borderRadius: 24,
                      font: 'inherit', fontSize: '0.92em', fontWeight: 700, color: theme.ink, cursor: 'pointer',
                    }}>
                      <span style={{ color: theme.chipIcon, display: 'grid', placeItems: 'center' }}><Ic size={19} /></span>
                      {c.label}
                    </button>
                  );
                })}
              </div>
            </div>
          )}
          {messages.map((m, i) => {
            let divider = null;
            if (m.at) {
              let prevAt = null;
              for (let j = i - 1; j >= 0; j--) { if (messages[j].at) { prevAt = messages[j].at; break; } }
              const gap = prevAt ? m.at - prevAt : null;
              if (i === 0 || (gap != null && gap >= 30 * 60000)) {
                divider = <PMTimeDivider key={'d' + i} at={m.at} theme={theme} gapMs={gap} />;
              }
            }
            return (
              <React.Fragment key={i}>
                {divider}
                <PMMessage msg={m} theme={theme} t={t} onCite={onCite} inspectorName={inspectorName}
                  onRate={m.verdict && onRate ? (val) => onRate(i, val) : undefined} />
              </React.Fragment>
            );
          })}
          {busy && (
            <div style={{ display: 'flex', gap: 10, alignItems: 'center' }}>
              {t.avatar !== 'none' && <MarshalAvatar styleKind={t.avatar} size={34} float={t.avatar === 'mascot'} />}
              <div style={{ background: theme.paper, border: `1.5px solid ${theme.line}`, borderRadius: '4px 16px 16px 16px' }}>
                <PMTypingDots theme={theme} />
              </div>
            </div>
          )}
        </div>
      </div>

      {/* Composer */}
      <div style={{ flexShrink: 0, padding: '10px 20px 14px' }}>
        <div style={{ maxWidth: 680, margin: '0 auto' }}>
          {showNewStop && (
            <div style={{
              display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap',
              background: theme.paper, border: `1.5px solid ${theme.line}`,
              borderLeft: `4px solid ${theme.amber}`, borderRadius: 14,
              padding: '11px 14px', marginBottom: 10,
            }}>
              <span style={{ flex: 1, minWidth: 160, fontSize: '0.92em', fontWeight: 600, color: theme.ink, lineHeight: 1.35 }}>
                Been {pmGapLabelShort(staleFor)} — still the same inspection?
              </span>
              <div style={{ display: 'flex', gap: 8 }}>
                <button onClick={() => setGapDismissed(true)} style={{
                  minHeight: 44, padding: '0 14px', borderRadius: 11, cursor: 'pointer', font: 'inherit',
                  fontSize: '0.88em', fontWeight: 700, background: 'transparent',
                  border: `1.5px solid ${theme.line}`, color: theme.muted,
                }}>Same one</button>
                <button onClick={() => { setGapDismissed(true); onNewSession && onNewSession(); }} style={{
                  minHeight: 44, padding: '0 14px', borderRadius: 11, cursor: 'pointer', font: 'inherit',
                  fontSize: '0.88em', fontWeight: 800, background: theme.amber,
                  border: 'none', color: PM_NAVY,
                }}>New inspection</button>
              </div>
            </div>
          )}
          <PMComposer theme={theme} placeholder="What are you seeing?" onSend={onSend}
            prefill={prefill} onPrefillConsumed={onPrefillConsumed} />
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { PMChat });
