/* Page: Requests — per-client portal tickets as a Kanban board (Execution
   layer). Columns by status. Agency drags cards to change status (PATCH);
   clients create cards + comment but do not drag. Click a card opens a modal
   with its thread. Visual reference: docs/superpowers/portal-mockup.html. */
const { useState: useStateTik } = React;
const KANBAN_COLS = ['new', 'in-progress', 'blocked', 'in-review', 'done'];
const TK_STATUS = { 'new': 'New', 'in-progress': 'In progress', 'blocked': 'Blocked', 'in-review': 'In review', 'done': 'Done' };

function TicketsView({ client }) {
  const [version, setVersion] = useStateTik(0);
  const { data, loading, error } = useApi(`/api/clients/${client.id}/tickets`, [client.id, version]);
  const [openId, setOpenId] = useStateTik(null);
  const me = window.__GE_USER__;
  const isAgency = !me || me.role === 'agency';
  const canWrite = isAgency || (me && me.role === 'client_admin');

  const [title, setTitle] = useStateTik('');
  const [type, setType] = useStateTik('request');
  const [priority, setPriority] = useStateTik('normal');
  const [saving, setSaving] = useStateTik(false);
  const [formErr, setFormErr] = useStateTik(null);
  const field = { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 4, padding: '6px 8px', color: 'var(--text)', fontSize: 13, width: '100%' };

  const [ann, setAnn] = useStateTik('');
  const [annBusy, setAnnBusy] = useStateTik(false);
  const [annNote, setAnnNote] = useStateTik('');
  const [digestMode, setDigestMode] = useStateTik(false);

  // Consume window.__GE_OPEN_TICKET__ set by the notifications bell
  React.useEffect(() => {
    const targetId = window.__GE_OPEN_TICKET__;
    if (!targetId || loading || !data) return;
    const match = (data || []).find(t => t.id === targetId);
    if (match) {
      setOpenId(match.id);
      window.__GE_OPEN_TICKET__ = null;
    }
  }, [loading, data]);

  if (loading) return <div className="loading-state">Loading requests...</div>;
  if (error) return <div className="error-state">Failed to load requests: {error}</div>;

  const tickets = data || [];
  const openTicket = openId ? tickets.find(t => t.id === openId) || null : null;

  const submit = (e) => {
    e.preventDefault();
    if (!title.trim()) { setFormErr('Title is required'); return; }
    setSaving(true); setFormErr(null);
    window.apiSend(`/api/clients/${client.id}/tickets`, 'POST', {
      title: title.trim(), type, priority,
    }).then(() => {
      setTitle(''); setType('request'); setPriority('normal'); setVersion(v => v + 1);
    }).catch(err => setFormErr(err.message)).finally(() => setSaving(false));
  };

  // Only agency may move cards. Drop calls the existing status PATCH endpoint.
  const onDrop = (e, status) => {
    e.preventDefault();
    e.currentTarget.classList.remove('dragover');
    if (!isAgency) return;
    const id = Number(e.dataTransfer.getData('text/plain'));
    const t = tickets.find(x => x.id === id);
    if (!t || t.status === status) return;
    window.apiSend(`/api/clients/${client.id}/tickets/${id}`, 'PATCH', { status })
      .then(() => setVersion(v => v + 1)).catch(() => {});
  };

  return (
    <>
      <div className="page-head">
        <div>
          <div className="eyebrow gold"><span className="dot"/>Requests · {tickets.length} on the board</div>
          <h1>Requests &amp; tasks</h1>
          <div className="sub">{isAgency ? 'Drag a card across columns to move it. ' : ''}Click a card to open its thread.{canWrite ? ' Create a request below.' : ''}</div>
        </div>
      </div>

      {canWrite && (
        <form onSubmit={submit} className="panel" style={{marginBottom: 16, padding: '16px 18px'}}>
          <div className="mono-label" style={{marginBottom: 10}}>New request</div>
          <div style={{display: 'flex', gap: 10, flexWrap: 'wrap', alignItems: 'flex-end'}}>
            <label style={{flex: '2 1 260px', display: 'flex', flexDirection: 'column', gap: 4}}>
              <span className="mono-label">Title</span>
              <input value={title} onChange={e => setTitle(e.target.value)} placeholder="e.g. Add schema to Tax page" style={field}/>
            </label>
            <label style={{flex: '1 1 130px', display: 'flex', flexDirection: 'column', gap: 4}}>
              <span className="mono-label">Type</span>
              <select value={type} onChange={e => setType(e.target.value)} style={field}>
                <option value="request">Request</option><option value="tech">Tech</option>
                <option value="content">Content</option><option value="adhoc">Ad hoc</option>
              </select>
            </label>
            <label style={{flex: '1 1 130px', display: 'flex', flexDirection: 'column', gap: 4}}>
              <span className="mono-label">Priority</span>
              <select value={priority} onChange={e => setPriority(e.target.value)} style={field}>
                <option value="low">Low</option><option value="normal">Normal</option>
                <option value="high">High</option><option value="urgent">Urgent</option>
              </select>
            </label>
            <button type="submit" className="btn btn-secondary" disabled={saving}>{saving ? 'Saving...' : 'Submit request'}</button>
          </div>
          {formErr && <div className="error-state" style={{marginTop: 8}}>{formErr}</div>}
        </form>
      )}

      {isAgency && (
        <div className="panel" style={{marginBottom: 16, padding: '16px 18px'}}>
          <div className="mono-label" style={{marginBottom: 10}}>Post to {client.name}&apos;s notifications</div>
          <textarea value={ann} onChange={e => setAnn(e.target.value)} rows={2}
            placeholder="Write an announcement, or pull this month's wins..." style={{...field, resize: 'vertical'}}/>
          <div style={{display: 'flex', gap: 8, marginTop: 8, alignItems: 'center', flexWrap: 'wrap'}}>
            <button type="button" className="btn btn-secondary" disabled={annBusy || !ann.trim()}
              onClick={() => {
                setAnnBusy(true); setAnnNote('');
                window.apiSend(`/api/clients/${client.id}/announcements`, 'POST', { message: ann.trim(), type: digestMode ? 'digest' : 'announcement' })
                  .then(() => { setAnn(''); setDigestMode(false); setAnnNote('Posted to the client bell.'); })
                  .catch(err => setAnnNote(err.message)).finally(() => setAnnBusy(false));
              }}>{annBusy ? 'Posting...' : 'Approve & post'}</button>
            <button type="button" className="btn btn-ghost" disabled={annBusy}
              onClick={() => {
                setAnnBusy(true); setAnnNote('');
                window.apiSend(`/api/clients/${client.id}/digest-draft`, 'GET')
                  .then(r => { setAnn(r.draft || ''); setDigestMode(!!r.draft); setAnnNote(r.draft ? 'Draft loaded. Edit, then Approve & post.' : 'No wins to report this month.'); })
                  .catch(err => setAnnNote(err.message)).finally(() => setAnnBusy(false));
              }}>Pull this month&apos;s wins</button>
            {annNote && <span className="mono" style={{fontSize: 11, color: 'var(--text-dim)'}}>{annNote}</span>}
          </div>
        </div>
      )}

      <div className="kanban">
        {KANBAN_COLS.map(col => {
          const cards = tickets.filter(t => t.status === col);
          return (
            <div className="kanban-col" key={col}
                 onDragOver={isAgency ? (e) => { e.preventDefault(); e.currentTarget.classList.add('dragover'); } : undefined}
                 onDragLeave={isAgency ? (e) => e.currentTarget.classList.remove('dragover') : undefined}
                 onDrop={isAgency ? (e) => onDrop(e, col) : undefined}>
              <div className="kanban-col-head">{TK_STATUS[col]}<span className="count">{cards.length}</span></div>
              <div className="kanban-cards">
                {cards.map(t => (
                  <div className={`kanban-card pri-${t.priority}`} key={t.id}
                       draggable={isAgency}
                       onDragStart={isAgency ? (e) => e.dataTransfer.setData('text/plain', t.id) : undefined}
                       onClick={() => setOpenId(t.id)}>
                    <div className="kc-title">{t.title}</div>
                    <div className="kc-meta"><span className="kc-type">{t.type}</span><span className={`kc-pri ${t.priority}`}>{t.priority}</span></div>
                    <div className="kc-foot">{t.created_by_role === 'agency' ? 'GE PH' : client.name} · {(t.created_at || '').slice(0, 10)}</div>
                  </div>
                ))}
              </div>
            </div>
          );
        })}
      </div>

      {openTicket && <TicketModal client={client} ticket={openTicket} canWrite={canWrite} onClose={() => setOpenId(null)} onChange={() => setVersion(v => v + 1)}/>}
    </>
  );
}

function TicketModal({ client, ticket, canWrite, onClose, onChange }) {
  const [cVersion, setCVersion] = React.useState(0);
  const { data } = useApi(`/api/clients/${client.id}/tickets/${ticket.id}/comments`, [ticket.id, cVersion]);
  const [body, setBody] = React.useState('');
  const [saving, setSaving] = React.useState(false);
  const comments = data || [];
  const field = { background: 'var(--surface)', border: '1px solid var(--border)', borderRadius: 4, padding: '6px 8px', color: 'var(--text)', fontSize: 13, width: '100%' };
  const TK_LABEL = { 'new': 'New', 'in-progress': 'In progress', 'blocked': 'Blocked', 'in-review': 'In review', 'done': 'Done' };
  const STATUSES = ['new', 'in-progress', 'in-review', 'blocked', 'done'];
  const me = window.__GE_USER__;
  const isAgency = !me || me.role === 'agency';
  const [movingTo, setMovingTo] = React.useState(null);

  // Agency-only status change, straight from the modal. Routes through the same
  // PATCH the board drag uses, so it also fires the client bell notification.
  const moveStatus = (status) => {
    if (status === ticket.status || movingTo) return;
    setMovingTo(status);
    window.apiSend(`/api/clients/${client.id}/tickets/${ticket.id}`, 'PATCH', { status })
      .then(() => { if (onChange) onChange(); })
      .catch(() => {}).finally(() => setMovingTo(null));
  };

  const addComment = (e) => {
    e.preventDefault();
    if (!body.trim()) return;
    setSaving(true);
    window.apiSend(`/api/clients/${client.id}/tickets/${ticket.id}/comments`, 'POST', { body: body.trim() })
      .then(() => { setBody(''); setCVersion(v => v + 1); if (onChange) onChange(); })
      .catch(() => {}).finally(() => setSaving(false));
  };

  return (
    <div className="modal-overlay open" onClick={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{position: 'relative'}}>
        <span className="modal-x" onClick={onClose}>✕</span>
        <div style={{padding: '18px 20px', borderBottom: '1px solid var(--border-light)'}}>
          <h3 style={{fontSize: 16, margin: '0 0 8px', maxWidth: '90%'}}>{ticket.title}</h3>
          <div style={{display: 'flex', gap: 8, alignItems: 'center', flexWrap: 'wrap'}}>
            <span className={`serp-badge ${ticket.status === 'done' ? 'gold' : ''}`}>{TK_LABEL[ticket.status] || ticket.status}</span>
            <span className="mono" style={{fontSize: 10, textTransform: 'uppercase', color: 'var(--text-dim)'}}>{ticket.type} · {ticket.priority} priority</span>
          </div>
          {isAgency && (
            <div style={{display: 'flex', gap: 6, alignItems: 'center', marginTop: 12, flexWrap: 'wrap'}}>
              <span className="mono-label">Move to</span>
              {STATUSES.map(s => (
                <button key={s} type="button"
                  className={`btn ${ticket.status === s ? 'btn-secondary' : 'btn-ghost'}`}
                  style={{padding: '3px 10px', fontSize: 11}}
                  disabled={!!movingTo || ticket.status === s}
                  onClick={() => moveStatus(s)}>
                  {movingTo === s ? 'Saving...' : TK_LABEL[s]}
                </button>
              ))}
            </div>
          )}
          {ticket.description && <p style={{marginTop: 10, fontSize: 13, color: 'var(--text-dim)', lineHeight: 1.6}}>{ticket.description}</p>}
        </div>
        <div style={{padding: '18px 20px'}}>
          <div className="mono-label" style={{marginBottom: 10}}>Thread</div>
          {comments.length === 0
            ? <div style={{fontSize: 12, color: 'var(--text-dim)'}}>No comments yet.</div>
            : comments.map(c => (
              <div key={c.id} style={{marginBottom: 12}}>
                <div style={{display: 'flex', justifyContent: 'space-between', fontSize: 11, marginBottom: 2}}>
                  <span style={{fontWeight: 600, color: c.author_role === 'agency' ? 'var(--gold)' : 'var(--text)'}}>{c.author_role === 'agency' ? 'GE PH' : client.name}</span>
                  <span className="mono" style={{color: 'var(--text-dim)'}}>{(c.created_at || '').slice(0, 10)}</span>
                </div>
                <div style={{fontSize: 13, color: 'var(--text)', lineHeight: 1.6}}>{c.body}</div>
              </div>
            ))}
          {canWrite && (
            <form onSubmit={addComment} style={{marginTop: 12}}>
              <textarea value={body} onChange={e => setBody(e.target.value)} rows={2} placeholder="Add a reply..." style={{...field, resize: 'vertical'}}/>
              <button type="submit" className="btn btn-secondary" style={{marginTop: 8}} disabled={saving}>{saving ? 'Sending...' : 'Reply'}</button>
            </form>
          )}
        </div>
      </div>
    </div>
  );
}

window.TicketsView = TicketsView;
