/**
 * Back office — entregas.
 *
 * O que há por enviar e por confirmar, de todas as contas, agrupado por
 * campanha. No MVP a NetScreen envia à mão: descarrega o cartaz à medida do
 * painel, põe-no lá, e marca aqui. O cliente vê o mesmo estado na campanha.
 *
 * Confirmar pede evidência (o link de uma captura ou de um play log no nosso
 * armazém -- o da VNNOX expira em ~24h) ou uma nota a dizer como se confirmou.
 * Falhar pede o motivo, que é o que o cliente lê.
 */
/**
 * Os vídeos que saíram para painéis pela app, e se o painel confirmou (administrador virgem A6, 4 Nov:
 * «que vídeos já foram para painéis e se chegaram» não tinha resposta). Só leitura.
 */
function EnviadosParaPaineis({ onNavegar }) {
  const [envios, setEnvios] = React.useState(null);
  const [erro, setErro] = React.useState(null);
  React.useEffect(() => {
    api.get('/api/admin/vnnox/envios').then((r) => setEnvios(r.envios || [])).catch((e) => setErro(e.message || 'Não deu para ler os envios.'));
  }, []);
  const doPlayer = (e) => {
    if (e.estado !== 'enviado') return null;
    const p = e.player;
    if (!p) return { texto: 'O painel ainda não confirmou.', cor: 'text-muted-foreground' };
    if (p.estado === 'recebeu') return { texto: 'O painel confirmou que recebeu.', cor: 'text-foreground' };
    if (p.estado === 'a_descarregar') return { texto: `O painel está a descarregar (${Math.round(p.progresso * 100)}%).`, cor: 'text-muted-foreground' };
    return { texto: `O painel ${p.motivo}.`, cor: 'text-accent' };
  };
  const estado = { enviado: 'Saiu para a VNNOX', falhou: 'Não saiu', a_enviar: 'A enviar', por_confirmar: 'Por confirmar', interrompido: 'Interrompido' };
  return (
    <section aria-labelledby="enviados-paineis" className="border border-border bg-card p-5">
      <h2 id="enviados-paineis" className="text-sm font-medium text-foreground">Enviados para painéis</h2>
      <p className="mt-1 max-w-prose text-xs text-muted-foreground">Os vídeos que saíram pela app para um painel, e o que o painel disse depois.</p>
      {erro && <p className="mt-3 text-sm text-accent">{erro}</p>}
      {!envios && !erro && <div className="loading-skeleton mt-3 h-16" />}
      {envios && !envios.length && <p className="mt-3 text-sm text-muted-foreground">Ainda não saiu nenhum vídeo para um painel pela app.</p>}
      {envios && envios.length > 0 && (
        <ul className="mt-3 divide-y divide-border">
          {envios.map((e) => {
            const p = doPlayer(e);
            return (
              <li key={e.id} className="space-y-1 py-3">
                <p className="text-sm text-foreground">
                  {e.tema || 'Vídeo'} <span className="text-muted-foreground">({e.formato})</span>
                  {' → '}{e.painel || 'painel'}{e.loja ? `, ${e.loja}` : ''}
                </p>
                <p className="text-xs text-muted-foreground">
                  {e.conta_slug
                    ? <button type="button" onClick={() => onNavegar(`/admin/clientes/${e.conta_slug}`)} className="hover:text-foreground">{e.conta}</button>
                    : (e.conta || '')}
                  {' · '}{estado[e.estado] || e.estado}{e.simulado ? ' (simulação)' : ''}
                  {' · '}{formatMomento(e.criado_em)}{e.criado_por ? `, por ${e.criado_por}` : ''}
                </p>
                {e.estado === 'falhou' && e.aviso && <p className="text-xs text-accent">{e.aviso}</p>}
                {p && <p className={`text-xs ${p.cor}`}>{p.texto}</p>}
              </li>
            );
          })}
        </ul>
      )}
    </section>
  );
}

function ScreenAdminEntregas({ onNavegar }) {
  const [lista, setLista] = React.useState(null);
  const [erro, setErro] = React.useState(null);
  const [aMarcar, setAMarcar] = React.useState(null); // { entrega, estado }
  const [nota, setNota] = React.useState('');
  const [evidencia, setEvidencia] = React.useState('');
  const [ocupado, setOcupado] = React.useState(false);
  const [aviso, setAviso] = React.useState(null);

  const carregar = React.useCallback(
    () => api.get('/api/admin/entregas').then((r) => { setLista(r.entregas); setErro(null); })
      .catch((e) => setErro(e.message || 'Não foi possível ler as entregas.')),
    []
  );
  React.useEffect(() => { carregar(); }, [carregar]);
  // Vindo do sino ou do «A tratar» com `?campanha=…`, vai-se à campanha do aviso, e não ao topo (teste de raiz,
  // 9 Out: abria com a NESCAFÉ primeiro e era preciso procurar).
  const [destacada] = React.useState(() => {
    try { return new URLSearchParams(window.location.search).get('campanha'); } catch { return null; }
  });
  const jaFoi = React.useRef(false);
  React.useEffect(() => {
    if (!destacada || !lista || jaFoi.current) return;
    const el = document.getElementById(`entregas-${destacada}`);
    if (el) { jaFoi.current = true; el.scrollIntoView({ behavior: 'smooth', block: 'start' }); }
  }, [destacada, lista]);
  // Um pedido de publicação novo aparece sem recarregar; o componente do lado
  // do cliente já perguntava, este não (parecer do Codex, 24 Set). Pára com
  // uma entrega a ser marcada, para não perder a nota.
  useActualizar(carregar, { activo: !aMarcar && !ocupado });

  async function marcar(entrega, estado, extra) {
    setOcupado(true);
    setAviso(null);
    try {
      // `de`: o estado que este ecrã viu. Se outra pessoa o mudou entretanto,
      // o servidor recusa em vez de sobrescrever (reavaliação do Codex).
      await api.patch(`/api/admin/entregas/${entrega.id}`, { estado, de: entrega.estado, ...(extra || {}) });
      setAMarcar(null);
      await carregar();
    } catch (e) {
      setAviso(e.message || 'Não foi possível marcar.');
    } finally {
      setOcupado(false);
    }
  }

  const grupos = React.useMemo(() => {
    const m = new Map();
    for (const e of lista || []) {
      if (!m.has(e.campanha_id)) m.set(e.campanha_id, { campanha: e.campanha_titulo, slug: e.conta_slug, conta: e.conta_nome, id: e.campanha_id, inicio: e.campanha_inicio, fim: e.campanha_fim, entregas: [] });
      m.get(e.campanha_id).entregas.push(e);
    }
    return [...m.values()];
  }, [lista]);

  const textoDoPost = (p) => [p.legenda, (p.hashtags || []).map((h) => (h.startsWith('#') ? h : `#${h}`)).join(' ')].filter(Boolean).join('\n\n');
  const cartaz = (g, e) => `/api/${g.slug}/campanhas/${g.id}/criativos/${e.criativo_id}/dooh.png?largura=${e.largura_px}&altura=${e.altura_px}`;

  return (
    <div className="space-y-6">
      <header>
        <h1 className="mt-1 font-display text-4xl uppercase leading-none tracking-wide">Entregas</h1>
        <p className="mt-3 max-w-prose text-sm leading-relaxed text-muted-foreground">
          O que as campanhas activas ainda não têm no destino. Descarrega, envia para cada destino e marca
          aqui: o cliente vê o mesmo estado na campanha.
        </p>
      </header>

      {erro && <p className="text-sm text-accent">{erro}</p>}
      {aviso && <p className="text-sm text-accent" role="status">{aviso}</p>}
      {!lista && !erro && <div className="loading-skeleton h-40" />}
      {lista && !lista.length && (
        <p className="text-sm text-muted-foreground">Nada por enviar, por confirmar ou falhado.</p>
      )}

      {grupos.map((g) => (
        <section key={g.id} id={`entregas-${g.id}`} className={`border bg-card p-5 ${destacada === g.id ? 'border-primary' : 'border-border'}`}>
          <div className="flex flex-wrap items-baseline justify-between gap-2">
            <h2 className="text-sm font-medium text-foreground">
              {g.campanha}
              {/* Quando passa: o operador não sabia até quando a entrega tinha valor (operador virgem, 3 Nov). */}
              {g.inicio && g.fim && <span className="ml-2 font-normal text-muted-foreground">de {formatDataCurta(g.inicio)} a {formatDataCurta(g.fim)}</span>}
            </h2>
            <button type="button" onClick={() => onNavegar(`/admin/clientes/${g.slug}`)} className="text-xs text-muted-foreground hover:text-foreground">
              {g.conta}
            </button>
          </div>
          <ul className="mt-3 divide-y divide-border">
            {g.entregas.map((e) => (
              <li key={e.id} className="flex flex-wrap items-center justify-between gap-3 py-3">
                <div className="min-w-0 space-y-1">
                  <p className="text-sm text-foreground">{e.destino}</p>
                  <EstadoEntrega entrega={e} />
                  {e.estado === 'enviado' && (
                    // A impressão do ficheiro fica no title: serve para conferir, não para ler (demo de 12 Out).
                    <p className="text-xs text-muted-foreground" title={e.ficheiro_md5 ? `md5 ${e.ficheiro_md5}` : undefined}>
                      Enviado por {e.actualizado_por_nome || e.actualizado_por}, {formatMomento(e.actualizado_em)}
                    </p>
                  )}
                  {e.estado === 'falhou' && (
                    <p className="text-xs text-accent">
                      Falhou{e.nota ? `: ${e.nota}` : ''} ({formatMomento(e.actualizado_em)}). O cliente está a ver isto.
                    </p>
                  )}
                  {e.post && e.post.legenda && (
                    <details className="max-w-prose text-xs">
                      <summary className="cursor-pointer text-muted-foreground hover:text-foreground">O texto do post</summary>
                      <p className="mt-1 whitespace-pre-line text-foreground">{textoDoPost(e.post)}</p>
                      <button type="button" onClick={() => navigator.clipboard && navigator.clipboard.writeText(textoDoPost(e.post)).then(() => setAviso('Texto do post copiado.'))} className="mt-1 text-muted-foreground underline underline-offset-2 hover:text-foreground">
                        Copiar
                      </button>
                    </details>
                  )}
                  {/* O texto repete um dado que deixou de valer depois do pedido
                      (28 Set, D2): o servidor recusa o envio, e diz-se antes. */}
                  {e.sem_garantia && (
                    <p className="text-xs text-accent">
                      Não enviar: o ficheiro foi aprovado antes de a frase obrigatória da marca estar garantida. O cliente tem de rever os cartazes na campanha.
                    </p>
                  )}
                  {e.repete && e.repete.length > 0 && (
                    <p className="text-xs text-accent">
                      Não enviar: repete {e.repete.map((d) => `«${d.afirmacao.replace(/[.!]$/, '')}»`).join(', ')}
                      {' '}({e.repete.map((d) => ({ retirado: 'o cliente retirou', recusado: 'a NetScreen recusou', proibido: 'proibido' }[d.motivo])).join(', ')}).
                      {' '}Combina com o cliente se se corrige ou se encerra.
                    </p>
                  )}
                </div>
                {/* Numa fila de trabalho, o próximo passo de cada linha é "suave"
                    (moldura laranja) e fica no fim; o laranja cheio em todas as
                    linhas deixava de dizer qual era a acção (28 Set). */}
                <div className="flex flex-wrap items-center gap-2">
                  {e.canal === 'dooh' && e.criativo_id && e.largura_px && (
                    <a href={cartaz(g, e)} download={`${g.campanha}-${e.largura_px}x${e.altura_px}.png`} className="border border-border px-3 py-1.5 text-xs">
                      Descarregar {e.largura_px}×{e.altura_px}
                    </a>
                  )}
                  {/* O post leva a imagem que o cliente viu ao aprovar (28 Set). */}
                  {e.canal === 'social' && e.criativo_id && (
                    <a href={`/api/${g.slug}/campanhas/${g.id}/criativos/${e.criativo_id}/imagem.png`} download={`${g.campanha}-post.png`} className="border border-border px-3 py-1.5 text-xs">
                      Descarregar a imagem do post
                    </a>
                  )}
                  {/* O MP4 composto a partir do storyboard aprovado (V0, 2 Out). */}
                  {e.canal === 'video' && e.video_id && (
                    <a href={`/api/${g.slug}/campanhas/${g.id}/videos/${e.video_id}/ficheiro?descarregar=1`} className="border border-border px-3 py-1.5 text-xs">
                      Descarregar o vídeo (MP4)
                    </a>
                  )}
                  {/* Um vídeo bloqueado: o que falta, e tentar outra vez quando é uma imagem
                      reposta (Codex, 3 Out, #2). Sem IA; o servidor confere tudo outra vez. */}
                  {e.canal === 'video' && !e.video_id && e.video_problema && (
                    <span className="flex flex-wrap items-center gap-2 text-xs">
                      <span className="text-perigo-texto">{`Não se compôs: ${e.video_problema.erro}`}</span>
                      {e.video_problema.codigo === 'ENTRADA_EM_FALTA' && (
                        <button
                          type="button"
                          disabled={ocupado}
                          onClick={() => api.post(`/api/admin/campanhas/${g.id}/videos/tentar`, {})
                            .then(() => { setAviso('O vídeo voltou à fila: aparece aqui quando estiver composto.'); carregar(); })
                            .catch((x) => setAviso(x.message))}
                          className="ns-btn ns-btn-sm ns-btn-suave text-xs"
                        >
                          Tentar outra vez
                        </button>
                      )}
                    </span>
                  )}
                  {e.estado !== 'falhou' && (
                    <button type="button" disabled={ocupado} onClick={() => { setAMarcar({ entrega: e, estado: 'falhou' }); setNota(''); setEvidencia(''); }} className="ns-btn ns-btn-sm ns-btn-fantasma text-xs">
                      Marcar falha
                    </button>
                  )}
                  {/* As acções seguem as transições do servidor (lib/entregas.js):
                      confirmar só depois de enviado, e uma falha tenta-se outra vez. */}
                  {(e.estado === 'por_enviar' || e.estado === 'falhou') && (
                    <button type="button" disabled={ocupado || e.sem_garantia || Boolean(e.video_problema) || (e.canal === 'video' && !e.video_id)} title={e.canal === 'video' && !e.video_id && !e.video_problema ? 'O vídeo ainda não está composto: não há ficheiro para enviar' : e.sem_garantia ? 'O cliente tem de rever os cartazes primeiro' : e.video_problema ? 'O vídeo não se compôs: não há o que enviar' : undefined} onClick={() => marcar(e, 'enviado')} className="ns-btn ns-btn-sm ns-btn-suave text-xs disabled:opacity-50">
                      {e.estado === 'falhou' ? 'Tentar outra vez (enviado)' : 'Marcar enviado'}
                    </button>
                  )}
                  {e.estado === 'enviado' && (
                    <button type="button" disabled={ocupado} onClick={() => { setAMarcar({ entrega: e, estado: 'confirmado' }); setNota(''); setEvidencia(''); }} className="ns-btn ns-btn-sm ns-btn-suave text-xs">
                      Confirmar
                    </button>
                  )}
                </div>
              </li>
            ))}
          </ul>
        </section>
      ))}

      <Modal
        aberto={!!aMarcar}
        onFechar={() => setAMarcar(null)}
        titulo={aMarcar && aMarcar.estado === 'confirmado' ? 'Confirmar a entrega' : 'A entrega falhou'}
        acoes={
          <>
            <button type="button" onClick={() => setAMarcar(null)} className="border border-border px-4 py-2 text-sm hover:bg-secondary">Cancelar</button>
            <button
              type="button"
              disabled={ocupado || (aMarcar && aMarcar.estado === 'falhou' ? !nota.trim() : !nota.trim() && !evidencia.trim())}
              onClick={() => marcar(aMarcar.entrega, aMarcar.estado, { nota, evidencia_url: evidencia })}
              className="bg-primary px-4 py-2 text-sm text-primary-foreground hover:bg-primary/90 disabled:bg-secondary disabled:text-muted-foreground"
            >
              {aMarcar && aMarcar.estado === 'confirmado' ? 'Confirmar' : 'Marcar como falhada'}
            </button>
          </>
        }
      >
        {aMarcar && (
          <div className="space-y-3">
            <p className="text-sm text-foreground">{aMarcar.entrega.destino}</p>
            {aMarcar.estado === 'confirmado' && (
              <>
                <label htmlFor="entrega-evidencia" className="label-eyebrow">Evidência (link)</label>
                <input
                  id="entrega-evidencia"
                  value={evidencia}
                  onChange={(e) => setEvidencia(e.target.value)}
                  placeholder="https://… a captura ou o play log, no nosso armazém"
                  className="w-full border border-border bg-background px-3 py-2 text-sm text-foreground outline-none focus-visible:border-primary"
                />
                <p className="text-xs text-muted-foreground">
                  O link de captura da VNNOX expira em cerca de 24 horas: guarda a imagem primeiro.
                </p>
              </>
            )}
            <label htmlFor="entrega-nota" className="label-eyebrow">
              {aMarcar.estado === 'confirmado' ? 'Nota (ou como se confirmou)' : 'Porque falhou (o cliente lê isto)'}
            </label>
            <textarea
              id="entrega-nota"
              rows={3}
              maxLength={1000}
              value={nota}
              onChange={(e) => setNota(e.target.value)}
              className="w-full border border-border bg-background px-3 py-2 text-sm text-foreground outline-none focus-visible:border-primary"
            />
          </div>
        )}
      </Modal>

      <EnviadosParaPaineis onNavegar={onNavegar} />
    </div>
  );
}
