/**
 * Um processamento em curso: o que está a acontecer, a animação, e há quanto tempo.
 *
 * Regra do Ricardo (8 Out): o utilizador sabe sempre que alguma coisa está a trabalhar. Os
 * pedidos curtos tratam-se sozinhos (o vigia em utils/api.js); isto é para o que leva segundos ou
 * minutos no servidor ou no worker — a leitura da marca, o Agente PM a escrever, as cenas, o vídeo
 * a compor — e que até aqui era uma frase parada, ou uma caixa vazia.
 *
 *   <AProcessar texto="O Agente PM está a escrever os anúncios" detalhe="Leva uns 30 segundos." />
 *   <AProcessar variante="bloco" … />   no lugar de um conteúdo que ainda não chegou
 *
 * `desde` (data ou ISO) conta o tempo a partir de quando o trabalho começou de facto, e não de
 * quando o ecrã abriu.
 */
function AProcessar({ texto, detalhe = null, desde = null, variante = 'linha', className = '' }) {
  const inicio = React.useRef(desde ? new Date(desde).getTime() : Date.now());
  const [agora, setAgora] = React.useState(Date.now());
  React.useEffect(() => {
    if (desde) inicio.current = new Date(desde).getTime();
  }, [desde]);
  React.useEffect(() => {
    const t = setInterval(() => setAgora(Date.now()), 1000);
    return () => clearInterval(t);
  }, []);
  const s = Math.max(0, Math.round((agora - inicio.current) / 1000));
  // Só ao fim de uns segundos: um contador a 0 s, 1 s, 2 s distrai mais do que ajuda.
  const tempo = s < 4 ? null : s < 60 ? `${s} s` : `${Math.floor(s / 60)} min ${String(s % 60).padStart(2, '0')} s`;

  if (variante === 'bloco') {
    return (
      <div role="status" aria-live="polite" className={`loading-skeleton rounded-md border border-border px-4 py-5 ${className}`}>
        <p className="flex items-center gap-2 text-sm font-medium text-foreground">
          <span className="ns-a-trabalhar text-primary" aria-hidden="true" />
          {texto}
          {tempo && <span className="font-normal tabular-nums text-muted-foreground">· {tempo}</span>}
        </p>
        {detalhe && <p className="mt-1 pl-6 text-xs leading-relaxed text-muted-foreground">{detalhe}</p>}
      </div>
    );
  }
  return (
    <div role="status" aria-live="polite" className={`text-sm ${className}`}>
      <p className="flex items-center gap-2 text-muted-foreground">
        <span className="ns-a-trabalhar text-primary" aria-hidden="true" />
        <span className="text-foreground">{texto}</span>
        {tempo && <span className="tabular-nums">· {tempo}</span>}
      </p>
      {detalhe && <p className="mt-0.5 pl-6 text-xs leading-relaxed text-muted-foreground">{detalhe}</p>}
    </div>
  );
}

/**
 * Uma imagem que o servidor desenha (os exemplos da marca nos painéis): até chegar, o lugar dela
 * fica reservado com a caixa animada e «A desenhar…», e não vazio. `proporcao` é largura/altura.
 * A cada `src` novo (uma cor mudou) volta a mostrar que está a desenhar, por cima da anterior.
 */
function ImagemComEspera({ src, alt, proporcao, className = '', estilo = {} }) {
  const [carregada, setCarregada] = React.useState(null);
  const [falhou, setFalhou] = React.useState(null);
  const pronta = carregada === src;
  return (
    <div className={`relative ${className}`} style={{ aspectRatio: proporcao ? String(proporcao) : undefined, ...estilo }}>
      <img src={src} alt={alt} onLoad={() => setCarregada(src)} onError={() => { setCarregada(src); setFalhou(src); }}
        className={`block h-full w-full border border-border object-contain transition-opacity ${pronta && falhou !== src ? 'opacity-100' : 'opacity-0'}`} />
      {falhou === src && (
        <div role="img" aria-label={`${alt}: não se conseguiu desenhar`}
          className="absolute inset-0 flex items-center justify-center gap-1.5 border border-border bg-secondary text-xs text-muted-foreground">
          <IconAlerta size={14} /> {proporcao && proporcao < 0.6 ? '' : 'Não se conseguiu desenhar.'}
        </div>
      )}
      {!pronta && (
        <div role="status" className="loading-skeleton absolute inset-0 flex items-center justify-center gap-2 text-xs text-muted-foreground">
          <span className="ns-a-trabalhar text-primary" aria-hidden="true" />
          {proporcao && proporcao < 0.6 ? '' : 'A desenhar…'}
        </div>
      )}
    </div>
  );
}

/**
 * Uma fotografia do cliente (miniaturas dos materiais). Se o ficheiro não abre, fica uma caixa
 * neutra com o aviso no mesmo lugar, e não o ícone de imagem partida do browser (cliente simulado,
 * 18 Out). `texto={null}` para miniaturas pequenas demais para uma palavra.
 */
function ImagemOuAviso({ src, alt, className = '', texto = 'Sem imagem' }) {
  const [falhou, setFalhou] = React.useState(null);
  if (falhou === src) {
    return (
      <span role="img" aria-label={`${alt}: a imagem não se conseguiu abrir`} title="A imagem não se conseguiu abrir"
        className={`flex items-center justify-center gap-1 bg-secondary text-center text-[11px] leading-tight text-muted-foreground ${texto ? "min-h-16 p-2" : ""} ${className}`}>
        <IconAlerta size={14} />{texto}
      </span>
    );
  }
  return <img src={src} alt={alt} onError={() => setFalhou(src)} className={className} />;
}

/** O indicador sozinho, para pôr ao lado de um estado numa lista («A ler…»). */
function ATrabalhar({ className = '' }) {
  return <span className={`ns-a-trabalhar ${className}`} aria-hidden="true" />;
}
