/* DigiTicket — painel flutuante: reports do utilizador, conversa e novo report */

const DigiTicket = ({ user }) => {
  const [open, setOpen] = React.useState(false);
  const [view, setView] = React.useState('list');
  const [mine, setMine] = React.useState([]);
  const [activeId, setActiveId] = React.useState(null);
  const [thread, setThread] = React.useState(null);
  const [threadLoading, setThreadLoading] = React.useState(false);
  const [reply, setReply] = React.useState('');
  const [text, setText] = React.useState('');
  const [status, setStatus] = React.useState('idle');
  const [errorMsg, setErrorMsg] = React.useState('');
  const [screenshot, setScreenshot] = React.useState(null);
  const mediaRef = React.useRef(null);
  const chunksRef = React.useRef([]);
  const fileRef = React.useRef(null);

  const statusLabel = { open: 'Aberto', in_progress: 'Em análise', resolved: 'Resolvido' };
  const fmtDate = (iso) => {
    if (!iso) return '';
    const [y, m, d] = String(iso).slice(0, 10).split('-');
    return `${d}/${m}`;
  };
  const fmtTime = (iso) => new Date(iso).toLocaleString('pt-PT', { day: '2-digit', month: '2-digit', hour: '2-digit', minute: '2-digit' });

  const loadMine = React.useCallback(() => {
    if (!user) return Promise.resolve();
    return fetch('/api/tickets/mine', { credentials: 'include' })
      .then(r => r.ok ? r.json() : [])
      .then(d => { const rows = Array.isArray(d) ? d : []; setMine(rows); return rows; })
      .catch(() => []);
  }, [user]);

  React.useEffect(() => {
    if (!user) return;
    loadMine();
    const t = setInterval(loadMine, 15000);
    const onFocus = () => loadMine();
    window.addEventListener('focus', onFocus);
    document.addEventListener('visibilitychange', onFocus);
    return () => {
      clearInterval(t);
      window.removeEventListener('focus', onFocus);
      document.removeEventListener('visibilitychange', onFocus);
    };
  }, [user, loadMine]);

  const openPanel = () => {
    setOpen(true);
    setErrorMsg('');
    loadMine().then(rows => {
      setView(rows && rows.length ? 'list' : 'compose');
    });
  };

  const closePanel = () => {
    if (status === 'recording' || status === 'processing') return;
    setOpen(false);
    resetForm();
    setReply('');
  };

  const openThread = (id) => {
    setActiveId(id);
    setView('thread');
    setReply('');
    setErrorMsg('');
    setThread(null);
    setThreadLoading(true);
    fetch(`/api/tickets/${id}/messages`, { credentials: 'include' })
      .then(r => r.ok ? r.json() : Promise.reject())
      .then(d => {
        const payload = Array.isArray(d) ? { messages: d } : (d || {});
        setThread({ ...payload, messages: (payload.messages || []).filter(Boolean) });
        setMine(rows => rows.map(t => t.id === id ? { ...t, unread: 0 } : t));
        setThreadLoading(false);
      })
      .catch(() => { setThreadLoading(false); setErrorMsg('Não foi possível abrir o report.'); });
  };

  const sendReply = async () => {
    const body = reply.trim();
    if (!body || !activeId) return;
    setStatus('processing');
    setErrorMsg('');
    try {
      const r = await fetch(`/api/tickets/${activeId}/messages`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        credentials: 'include',
        body: JSON.stringify({ body, kind: 'user' }),
      });
      const d = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(d.error || 'Erro ao enviar');
      setReply('');
      setMine(rows => rows.map(t => t.id === activeId ? { ...t, unread: 0 } : t));
      if (d.message) setThread(th => th ? { ...th, messages: [...(th.messages || []), d.message] } : th);
      else openThread(activeId);
      setStatus('idle');
      loadMine();
    } catch (e) {
      setErrorMsg(e.message);
      setStatus('idle');
    }
  };

  const resetForm = () => {
    setText('');
    setStatus('idle');
    setErrorMsg('');
    setScreenshot(null);
    chunksRef.current = [];
    if (fileRef.current) fileRef.current.value = '';
  };

  const afterCreate = () => {
    resetForm();
    loadMine().then(() => setView('list'));
  };

  const startRecording = async () => {
    setErrorMsg('');
    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      chunksRef.current = [];
      const mr = new MediaRecorder(stream);
      mr.ondataavailable = e => { if (e.data.size > 0) chunksRef.current.push(e.data); };
      mr.onstop = async () => {
        stream.getTracks().forEach(t => t.stop());
        setStatus('processing');
        const blob = new Blob(chunksRef.current, { type: 'audio/webm' });
        const fd = new FormData();
        fd.append('audio', blob, 'ticket.webm');
        fd.append('screen', window.location.hash);
        if (screenshot) fd.append('screenshot', screenshot, screenshot.name);
        try {
          const r = await fetch('/api/tickets', { method: 'POST', body: fd, credentials: 'include' });
          const d = await r.json();
          if (!r.ok) throw new Error(d.error || 'Erro ao submeter');
          setStatus('success');
          setTimeout(afterCreate, 1200);
        } catch (e) {
          setErrorMsg(e.message);
          setStatus('error');
        }
      };
      mr.start();
      mediaRef.current = mr;
      setStatus('recording');
    } catch (e) {
      setErrorMsg(e.name === 'NotAllowedError' ? 'Permissão de microfone negada. Usa a caixa de texto.' : ('Erro ao aceder ao microfone: ' + e.message));
      setStatus('idle');
    }
  };

  const stopRecording = () => {
    if (mediaRef.current && mediaRef.current.state === 'recording') mediaRef.current.stop();
  };

  const submitText = async () => {
    if (!text.trim()) return;
    setStatus('processing');
    setErrorMsg('');
    try {
      const fd = new FormData();
      fd.append('text', text.trim());
      fd.append('screen', window.location.hash);
      if (screenshot) fd.append('screenshot', screenshot, screenshot.name);
      const r = await fetch('/api/tickets', { method: 'POST', body: fd, credentials: 'include' });
      const d = await r.json();
      if (!r.ok) throw new Error(d.error || 'Erro ao submeter');
      setStatus('success');
      setTimeout(afterCreate, 1200);
    } catch (e) {
      setErrorMsg(e.message);
      setStatus('error');
    }
  };

  if (!user) return null;

  const unread = mine.reduce((n, t) => n + (Number(t.unread) || 0), 0);
  const isProcessing = status === 'processing';
  const isRecording = status === 'recording';
  const isSuccess = status === 'success';
  const active = mine.find(t => t.id === activeId);
  const ticket = thread?.ticket && thread.ticket.id === activeId ? thread.ticket : active;

  const headerBtn = (label, onClick) => (
    <button onClick={onClick} style={{ background: 'transparent', border: 'none', cursor: 'pointer', color: 'var(--dgd-fg-2, #64748b)', fontSize: 12, fontWeight: 600, padding: 0 }}>{label}</button>
  );

  return (
    <>
      <div style={{ position: 'fixed', bottom: 24, right: 24, zIndex: 1102 }}>
        <button
          onClick={() => open ? closePanel() : openPanel()}
          title={unread > 0 ? `${unread} mensagem${unread === 1 ? '' : 's'} nova${unread === 1 ? '' : 's'}` : 'Reports e feedback'}
          style={{ width: 44, height: 44, borderRadius: '50%', background: 'var(--dgd-bg-surface, #fff)', border: '1px solid var(--dgd-border-1, #e2e8f0)', boxShadow: '0 2px 12px rgba(0,0,0,0.12)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', color: unread > 0 ? '#dc2626' : 'var(--dgd-fg-3, #94a3b8)' }}
        >
          <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
            <path d="M4 15s1-1 4-1 5 2 8 2 4-1 4-1V3s-1 1-4 1-5-2-8-2-4 1-4 1z"/>
            <line x1="4" y1="22" x2="4" y2="15"/>
          </svg>
        </button>
        {unread > 0 && (
          <div style={{ position: 'absolute', top: -6, right: -6, minWidth: 18, height: 18, padding: '0 5px', boxSizing: 'border-box', borderRadius: 99, background: '#dc2626', color: '#fff', fontSize: 11, fontWeight: 800, lineHeight: '18px', textAlign: 'center', border: '2px solid #fff', animation: 'ticketNotify 1.6s ease-out infinite', pointerEvents: 'none' }}>
            {unread > 9 ? '9+' : unread}
          </div>
        )}
      </div>

      {open && (
        <div
          onClick={e => { if (e.target === e.currentTarget) closePanel(); }}
          style={{ position: 'fixed', inset: 0, zIndex: 1100, background: 'rgba(0,0,0,0.18)' }}
        >
          <div style={{ position: 'absolute', bottom: 80, right: 24, width: 400, maxWidth: 'calc(100vw - 32px)', maxHeight: 'min(640px, calc(100vh - 112px))', display: 'flex', flexDirection: 'column', background: 'var(--dgd-bg-surface, #fff)', border: '1px solid var(--dgd-border-1, #e2e8f0)', borderRadius: 12, boxShadow: '0 8px 32px rgba(0,0,0,0.18)', overflow: 'hidden' }}>
            <div style={{ padding: '12px 14px', borderBottom: '1px solid var(--dgd-border-1, #e2e8f0)', display: 'flex', alignItems: 'center', gap: 10 }}>
              {view !== 'list' && headerBtn('←', () => { setErrorMsg(''); setView(mine.length ? 'list' : 'compose'); })}
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 10, fontFamily: 'var(--dgd-font-mono, monospace)', color: 'var(--dgd-fg-3, #94a3b8)', letterSpacing: '0.08em' }}>FARBEN AI · FEEDBACK</div>
                <div style={{ fontSize: 13, fontWeight: 700, color: 'var(--dgd-fg-1, #1e293b)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                  {view === 'compose' ? 'Novo report' : view === 'thread' ? (ticket?.title || 'Report') : 'Os teus reports'}
                </div>
              </div>
              {view === 'list' && (
                <button onClick={() => { resetForm(); setView('compose'); }} style={{ padding: '5px 10px', borderRadius: 6, border: 'none', background: '#112954', color: '#fff', fontSize: 12, fontWeight: 600, cursor: 'pointer' }}>Novo</button>
              )}
              {!isRecording && !isProcessing && (
                <button onClick={closePanel} style={{ background: 'transparent', border: 'none', cursor: 'pointer', color: 'var(--dgd-fg-3, #94a3b8)', fontSize: 16 }}>×</button>
              )}
            </div>

            {view === 'list' && (
              <div style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: 10 }}>
                {mine.length === 0 && <div style={{ padding: 20, textAlign: 'center', fontSize: 13, color: 'var(--dgd-fg-3, #94a3b8)' }}>Ainda não tens reports.</div>}
                {mine.filter(t => t.status !== 'resolved').map(row => rowButton(row))}
                {mine.some(t => t.status === 'resolved') && (
                  <div style={{ marginTop: 8 }}>
                    <div style={{ fontSize: 10, fontWeight: 700, letterSpacing: '0.06em', color: 'var(--dgd-fg-3, #94a3b8)', padding: '6px 6px 4px' }}>RESOLVIDOS</div>
                    {mine.filter(t => t.status === 'resolved').map(row => rowButton(row))}
                  </div>
                )}
              </div>
            )}

            {view === 'thread' && (
              <>
                <div style={{ padding: '8px 14px', borderBottom: '1px solid var(--dgd-border-1, #e2e8f0)', fontSize: 12, color: 'var(--dgd-fg-2, #64748b)', display: 'flex', gap: 8, flexWrap: 'wrap' }}>
                  <span style={{ fontWeight: 700 }}>{statusLabel[ticket?.status] || '—'}</span>
                  {ticket?.due_date && ticket.status !== 'resolved' && <span>Previsto {fmtDate(ticket.due_date)}</span>}
                  {ticket?.resolved_at && <span>Resolvido {fmtDate(ticket.resolved_at)}</span>}
                </div>
                <div style={{ flex: 1, minHeight: 0, overflowY: 'auto', padding: 12 }}>
                  {ticket?.raw_text && (
                    <div style={{ marginBottom: 8, padding: '8px 10px', borderRadius: 8, background: 'var(--bg, #f8fafc)', border: '1px solid var(--dgd-border-1, #e2e8f0)' }}>
                      <div style={{ fontSize: 10, fontWeight: 700, color: 'var(--dgd-fg-3, #94a3b8)', marginBottom: 3 }}>O TEU REPORT · {fmtTime(ticket.created_at)}</div>
                      <div style={{ fontSize: 13, whiteSpace: 'pre-wrap', lineHeight: 1.45 }}>{ticket.raw_text}</div>
                    </div>
                  )}
                  {threadLoading && <div style={{ fontSize: 12, color: 'var(--dgd-fg-3, #94a3b8)' }}>A carregar...</div>}
                  {(thread?.messages || []).filter(Boolean).map(m => {
                    const mineMsg = m.kind === 'user';
                    return (
                      <div key={m.id} style={{ display: 'flex', justifyContent: mineMsg ? 'flex-end' : 'flex-start', marginBottom: 8 }}>
                        <div style={{ maxWidth: '88%', padding: '8px 10px', borderRadius: 8, background: mineMsg ? '#112954' : '#f0fdf4', color: mineMsg ? '#fff' : 'var(--dgd-fg-1, #1e293b)', border: mineMsg ? 'none' : '1px solid #bbf7d0' }}>
                          <div style={{ fontSize: 10, fontWeight: 700, opacity: 0.75, marginBottom: 3 }}>{mineMsg ? 'Tu' : 'Equipa'} · {fmtTime(m.created_at)}</div>
                          <div style={{ fontSize: 13, whiteSpace: 'pre-wrap', lineHeight: 1.45 }}>{m.body}</div>
                        </div>
                      </div>
                    );
                  })}
                </div>
                <div style={{ borderTop: '1px solid var(--dgd-border-1, #e2e8f0)', padding: 12 }}>
                  {errorMsg && <div style={{ fontSize: 12, color: '#dc2626', marginBottom: 6 }}>{errorMsg}</div>}
                  <textarea value={reply} onChange={e => setReply(e.target.value)} rows={2} placeholder="Responder..." disabled={isProcessing} style={{ width: '100%', boxSizing: 'border-box', fontSize: 13, padding: 8, borderRadius: 6, border: '1px solid var(--dgd-border-1, #e2e8f0)', resize: 'vertical', fontFamily: 'inherit' }} />
                  <button disabled={!reply.trim() || isProcessing} onClick={sendReply} style={{ marginTop: 8, width: '100%', padding: '8px', borderRadius: 6, border: 'none', fontWeight: 600, fontSize: 13, cursor: reply.trim() ? 'pointer' : 'not-allowed', background: reply.trim() ? '#112954' : 'var(--dgd-border-1, #e2e8f0)', color: reply.trim() ? '#fff' : 'var(--dgd-fg-3, #94a3b8)' }}>
                    {isProcessing ? 'A enviar...' : 'Enviar resposta'}
                  </button>
                </div>
              </>
            )}

            {view === 'compose' && (
              <div style={{ padding: 14, overflowY: 'auto' }}>
                {isSuccess ? (
                  <div style={{ textAlign: 'center', padding: '24px 0' }}>
                    <div style={{ fontSize: 13, fontWeight: 600, color: '#16a34a' }}>Report enviado</div>
                    <div style={{ fontSize: 12, color: 'var(--dgd-fg-3, #94a3b8)', marginTop: 4 }}>Vais receber confirmação por email.</div>
                  </div>
                ) : (
                  <>
                    <textarea
                      value={text}
                      onChange={e => setText(e.target.value)}
                      placeholder="Descreve o problema ou feedback..."
                      disabled={isProcessing || isRecording}
                      rows={4}
                      style={{ width: '100%', boxSizing: 'border-box', padding: '8px 10px', fontSize: 13, border: '1px solid var(--dgd-border-1, #e2e8f0)', borderRadius: 6, resize: 'vertical', outline: 'none', color: 'var(--dgd-fg-1, #1e293b)', background: 'var(--dgd-bg, #f8fafc)', marginBottom: 10, fontFamily: 'inherit' }}
                    />
                    <input ref={fileRef} type="file" accept="image/*" style={{ display: 'none' }} disabled={isProcessing || isRecording} onChange={e => setScreenshot(e.target.files?.[0] || null)} />
                    {screenshot ? (
                      <div style={{ display: 'flex', alignItems: 'center', gap: 8, padding: '6px 10px', background: '#f0fdf4', border: '1px solid #bbf7d0', borderRadius: 6, marginBottom: 10 }}>
                        <span style={{ fontSize: 11.5, color: '#166534', flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{screenshot.name}</span>
                        <button onClick={() => { setScreenshot(null); if (fileRef.current) fileRef.current.value = ''; }} style={{ background: 'none', border: 'none', cursor: 'pointer', color: '#dc2626', fontSize: 12 }}>Tirar</button>
                      </div>
                    ) : (
                      <button onClick={() => fileRef.current?.click()} disabled={isProcessing || isRecording} style={{ marginBottom: 10, padding: '6px 12px', borderRadius: 6, border: '1px solid var(--dgd-border-1, #e2e8f0)', fontSize: 12, cursor: 'pointer', background: 'transparent', color: 'var(--dgd-fg-2, #64748b)' }}>Anexar screenshot</button>
                    )}
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 10 }}>
                      <button onClick={isRecording ? stopRecording : startRecording} disabled={isProcessing} style={{ padding: '6px 12px', borderRadius: 6, border: '1px solid', fontSize: 12, cursor: 'pointer', fontWeight: 500, background: isRecording ? '#fee2e2' : 'transparent', borderColor: isRecording ? '#fca5a5' : 'var(--dgd-border-1, #e2e8f0)', color: isRecording ? '#dc2626' : 'var(--dgd-fg-2, #64748b)' }}>
                        {isRecording ? 'Parar gravação' : 'Gravar áudio'}
                      </button>
                      {isProcessing && <span style={{ fontSize: 12, color: 'var(--dgd-fg-3, #94a3b8)' }}>A processar...</span>}
                    </div>
                    {errorMsg && <div style={{ fontSize: 12, color: '#dc2626', background: '#fee2e2', border: '1px solid #fca5a5', borderRadius: 6, padding: '6px 10px', marginBottom: 10 }}>{errorMsg}</div>}
                    <button onClick={submitText} disabled={!text.trim() || isProcessing || isRecording} style={{ width: '100%', padding: '8px', borderRadius: 6, border: 'none', fontSize: 13, fontWeight: 600, cursor: (!text.trim() || isProcessing || isRecording) ? 'not-allowed' : 'pointer', background: (!text.trim() || isProcessing || isRecording) ? 'var(--dgd-border-1, #e2e8f0)' : '#112954', color: (!text.trim() || isProcessing || isRecording) ? 'var(--dgd-fg-3, #94a3b8)' : '#fff' }}>
                      {isProcessing ? 'A enviar...' : 'Enviar report'}
                    </button>
                  </>
                )}
              </div>
            )}
          </div>
        </div>
      )}
      <style>{`
        @keyframes ticketNotify {
          0% { transform: scale(1); box-shadow: 0 0 0 0 rgba(220,38,38,0.55); }
          70% { transform: scale(1.08); box-shadow: 0 0 0 8px rgba(220,38,38,0); }
          100% { transform: scale(1); box-shadow: 0 0 0 0 rgba(220,38,38,0); }
        }
      `}</style>
    </>
  );

  function rowButton(t) {
    return (
      <button key={t.id} onClick={() => openThread(t.id)} style={{ display: 'block', width: '100%', textAlign: 'left', cursor: 'pointer', border: 'none', borderBottom: '1px solid var(--dgd-border-1, #e2e8f0)', background: 'transparent', padding: '10px 8px' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--dgd-fg-1, #1e293b)', flex: 1, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{t.title || 'Sem título'}</span>
          {t.unread > 0 && <span style={{ width: 8, height: 8, borderRadius: '50%', background: '#dc2626', flexShrink: 0 }} />}
        </div>
        <div style={{ fontSize: 11, color: 'var(--dgd-fg-3, #94a3b8)', marginTop: 2 }}>
          {statusLabel[t.status] || t.status} · {fmtDate(t.created_at)}
          {t.due_date && t.status !== 'resolved' ? ` · previsto ${fmtDate(t.due_date)}` : ''}
        </div>
      </button>
    );
  }
};

window.DigiTicket = DigiTicket;
