/**
 * "Como fala" — a voz da marca, e o que ela nunca diz (24 Set, migração 040).
 *
 * O mesmo padrão da identidade visual: a app propõe, a pessoa corrige o que
 * estiver errado e aceita (parecer do Codex, decisões 6 e 7). Poucos campos,
 * quase todos opcionais; sem nada, fica um padrão neutro, e diz-se que é o
 * padrão. Uma proposta que ninguém aceitou não chega às campanhas.
 *
 * "Evitar" orienta a escrita; "Nunca usar" bloqueia o texto. São coisas
 * diferentes, e o ecrã diz a diferença.
 */

const TRATAMENTOS_VOZ = [
  ['tu', 'Por tu'],
  ['voce', 'Por você'],
  ['neutro', 'Sem tratamento directo'],
];

const vazioVoz = { essencia: '', tratamento: null, tracos: [], publico: '', exemplos: [], evitar: [] };

/** A voz a editar: a aceite, ou a proposta, ou nada. */
function vozInicial(d) {
  if (d.voz) return { ...vazioVoz, ...d.voz, publico: d.voz.publico || '', essencia: d.voz.essencia || '' };
  const p = d.proposta;
  if (!p) return { ...vazioVoz };
  return {
    essencia: p.essencia ? p.essencia.texto : '',
    tratamento: p.tratamento || null,
    tracos: (p.tracos || []).map((x) => x.texto),
    publico: p.publico ? p.publico.texto : '',
    exemplos: (p.exemplos || []).map((x) => x.texto),
    evitar: (p.evitar || []).map((x) => x.texto),
  };
}

const mesmaVoz = (a, b) => JSON.stringify([a.essencia || '', a.tratamento, a.tracos, a.publico, a.exemplos, a.evitar])
  === JSON.stringify([b.essencia || '', b.tratamento, b.tracos, b.publico || '', b.exemplos, b.evitar]);

/** Uma lista curta de textos: cada um com "tirar", e um campo para acrescentar. */
function ListaCurta({ id, valores, maximo, marcador, podeMexer, onMudar, origem }) {
  const [novo, setNovo] = React.useState('');
  const acrescentar = () => {
    const t = novo.trim();
    if (!t || valores.includes(t) || valores.length >= maximo) return;
    onMudar([...valores, t]);
    setNovo('');
  };
  return (
    <div>
      <ul className="flex flex-wrap gap-1.5">
        {valores.map((v) => (
          // Pílula com o × num alvo de 20 px: o × de texto era pequeno demais
          // para o dedo (28 Set).
          <li key={v} className="flex items-center gap-1 rounded-full border border-border bg-[var(--campo-fundo)] py-0.5 pl-3 pr-1 text-xs text-foreground">
            <span>{v}</span>
            {podeMexer && (
              <button type="button" onClick={() => onMudar(valores.filter((x) => x !== v))} className="flex h-5 w-5 items-center justify-center rounded-full text-muted-foreground hover:bg-[hsl(var(--offline)/0.2)] hover:text-foreground" aria-label={`Tirar ${v}`}>
                <svg viewBox="0 0 16 16" className="h-3 w-3" aria-hidden="true"><path d="M4 4l8 8M12 4l-8 8" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" /></svg>
              </button>
            )}
          </li>
        ))}
      </ul>
      {/* De onde veio, à vista: no telemóvel não há rato para o title (cliente
          simulado, 24 Set). */}
      {origem && valores.some((v) => origem[v]) && (
        <ul className="mt-1 space-y-0.5">
          {valores.filter((v) => origem[v]).map((v) => (
            <li key={v} className="text-xs text-muted-foreground">{`${v}: dos teus ficheiros, «${origem[v]}»`}</li>
          ))}
        </ul>
      )}
      {podeMexer && valores.length < maximo && (
        <div className="mt-2 flex gap-2">
          <input
            id={id}
            value={novo}
            onChange={(e) => setNovo(e.target.value)}
            onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); acrescentar(); } }}
            placeholder={marcador}
            className="h-9 min-w-0 grow border border-border bg-background px-3 text-sm text-foreground outline-none"
          />
          <button type="button" onClick={acrescentar} disabled={!novo.trim()} className="h-9 shrink-0 border border-border px-3 text-sm disabled:opacity-50">
            Acrescentar
          </button>
        </div>
      )}
    </div>
  );
}

// `daEquipa`: aberta na ficha do back office, em terceira pessoa (demo de 12 Out, P10).
function MarcaVoz({ slug, podeMexer, onMudou, daEquipa = false }) {
  const [d, setD] = React.useState(null);
  const [voz, setVoz] = React.useState(null);
  const [ocupado, setOcupado] = React.useState(false);
  const [aviso, setAviso] = React.useState(null);
  const [regra, setRegra] = React.useState({ texto: '', motivo: '' });
  const [frase, setFrase] = React.useState('');

  // `repor` põe o formulário como está guardado. As regras gravam logo, noutra
  // tabela: acrescentar uma não pode apagar a voz que ainda não se guardou
  // (advogado da simplicidade, 24 Set).
  const carregar = React.useCallback((repor = true) => api.get(`/api/${slug}/marca/voz`)
    .then((r) => { setD(r); if (repor) setVoz(vozInicial(r)); })
    .catch((e) => setD({ erro: e.message || 'sem resposta' })), [slug]);
  React.useEffect(() => { setD(null); setAviso(null); carregar(); }, [carregar]);

  if (!d) return <div className="loading-skeleton h-40" />;
  if (d.erro) return <p className="text-sm text-accent" role="status">Não deu para ler a voz da marca: {d.erro}</p>;

  const origem = {};
  if (d.proposta && !d.voz) {
    for (const campo of ['tracos', 'exemplos', 'evitar']) {
      for (const x of d.proposta[campo] || []) origem[x.texto] = x.excerto;
    }
  }
  const aceite = d.voz ? vozInicial({ voz: d.voz }) : null;
  // Uma proposta que não trouxe nada não se diz «tirada do que lemos» (agentes, 20 Out).
  const propostaVazia = Boolean(d.proposta && !d.voz && !d.proposta.essencia && !d.proposta.tratamento && !d.proposta.publico
    && !(d.proposta.tracos || []).length && !(d.proposta.exemplos || []).length && !(d.proposta.evitar || []).length);
  const jaRegras = new Set(d.regras.map((r) => r.texto.toLowerCase()));
  const sugeridas = ((d.proposta && d.proposta.nunca) || []).filter((s) => !jaRegras.has(s.texto.toLowerCase()));
  // As duas listas (28 Set, migração 051): o que nunca se escreve e o que se escreve sempre.
  const regrasNunca = d.regras.filter((r) => r.tipo !== 'sempre');
  const regrasSempre = d.regras.filter((r) => r.tipo === 'sempre');
  const sempreSugeridas = ((d.proposta && d.proposta.sempre) || []).filter((s) => !jaRegras.has(s.texto.toLowerCase()));
  // Sem nada escrito nem proposta, não há o que guardar: o botão só aparece
  // com alguma coisa (visto no Edge, 24 Set).
  const temAlgo = Boolean(voz.essencia.trim() || voz.tratamento || voz.publico.trim() || voz.tracos.length || voz.exemplos.length || voz.evitar.length);
  const alterado = aceite ? !mesmaVoz(voz, aceite) : temAlgo;
  const mudou = (campo, valor) => { setVoz({ ...voz, [campo]: valor }); setAviso(null); };

  const accao = async (fn, mensagem, repor = true) => {
    setOcupado(true);
    setAviso(null);
    try {
      await fn();
      await carregar(repor);
      if (mensagem) setAviso(mensagem);
      if (onMudou) onMudou();
    } catch (e) {
      setAviso(e.message);
    } finally {
      setOcupado(false);
    }
  };

  const guardar = () => accao(() => api.put(`/api/${slug}/marca/voz`, voz),
    'Guardado. As próximas campanhas escrevem assim.');
  const criarRegra = () => accao(async () => {
    await api.post(`/api/${slug}/marca/regras`, { texto: regra.texto, motivo: regra.motivo || null });
    setRegra({ texto: '', motivo: '' });
  }, null, false);
  const retirarRegra = (r) => accao(() => api.del(`/api/${slug}/marca/regras/${r.id}`), null, false);

  return (
    <div className="space-y-6">
      <div className="max-w-prose space-y-1 text-sm text-muted-foreground">
        <p>{daEquipa
          ? 'É como as campanhas desta conta escrevem: o tratamento, a maneira de escrever, para quem falam.'
          : 'É como as campanhas escrevem por ti: o tratamento, a maneira de escrever, para quem falam.'}</p>
        {d.voz ? (
          <p>
            {`Guardada a ${formatData(d.voz.aceite_em)} por ${d.voz.aceite_por_nome || d.voz.aceite_por}`}
            {d.voz.aceite_por_tipo === 'netscreen' ? ' (NetScreen)' : ''}.{daEquipa ? ' Pode ser corrigida a qualquer momento.' : ' Podes corrigir quando quiseres.'}
          </p>
        ) : propostaVazia ? (
          <p className="text-foreground">{daEquipa
            ? 'Não encontrámos nos ficheiros como a marca fala. Preenche o que se souber; sem nada, as campanhas usam um tom neutro e tratam por tu.'
            : 'Não encontrámos nos teus ficheiros como a marca fala. Preenche o que souberes; sem nada, as campanhas usam um tom neutro e tratam por tu.'}</p>
        ) : d.proposta ? (
          <p className="text-foreground">{daEquipa
            ? 'Isto é uma proposta, tirada do que lemos. Só conta depois de alguém a guardar.'
            : 'Isto é uma proposta, tirada do que lemos. Só conta depois de guardares.'}</p>
        ) : (
          <p>Ainda não está definida: as campanhas usam um tom neutro e tratam por tu.</p>
        )}
      </div>

      {/* O botão de propor está no topo da Identidade: uma proposta só para
          como aparece e como fala (parecer do Codex). */}

      {/* Uma coluna de formulário só, com a mesma largura para todos os campos (28 Set). */}
      <section className="max-w-2xl space-y-6">
        {/* O que ficou do dossiê (24 Set): quem a marca é, numa ou duas frases.
            Orienta o tom das campanhas; não é fonte do que se afirma. */}
        <div>
          <label htmlFor="voz-essencia" className="ns-rotulo">A marca numa frase</label>
          <textarea
            id="voz-essencia"
            rows={3}
            maxLength={300}
            value={voz.essencia}
            disabled={!podeMexer}
            onChange={(e) => mudou('essencia', e.target.value)}
            // Exemplos que sirvam a qualquer negócio, e não só a um café (agentes, 20 Out: numa óptica não ajudavam).
            placeholder="Ex.: Uma loja de família, no bairro há 30 anos, que conhece os clientes pelo nome."
            className="w-full border border-border bg-background px-3 py-2 text-sm text-foreground outline-none"
          />
          <p className="ns-ajuda">Quem são, dito como dirias a um cliente novo.</p>
          {d.proposta && !d.voz && d.proposta.essencia && (
            <p className="text-xs text-muted-foreground">{`Dos teus ficheiros: «${d.proposta.essencia.excerto}»`}</p>
          )}
        </div>

        <div>
          <p className="ns-rotulo">Tratamento</p>
          <div className="flex flex-wrap gap-1.5" role="radiogroup" aria-label="Tratamento">
            {TRATAMENTOS_VOZ.map(([v, t]) => (
              <button
                key={v}
                type="button"
                role="radio"
                aria-checked={voz.tratamento === v}
                disabled={!podeMexer}
                onClick={() => mudou('tratamento', voz.tratamento === v ? null : v)}
                className="ns-chip"
              >
                {t}
              </button>
            ))}
          </div>
          {!voz.tratamento && <p className="ns-ajuda">Por escolher. Sem tratamento escolhido, as campanhas tratam por tu.</p>}
        </div>

        <div>
          <label htmlFor="voz-tracos" className="ns-rotulo">Maneira de escrever</label>
          <ListaCurta id="voz-tracos" valores={voz.tracos} maximo={3} marcador="Ex.: próxima" podeMexer={podeMexer} origem={origem} onMudar={(v) => mudou('tracos', v)} />
          <p className="ns-ajuda">Até três palavras. Ex.: próxima, simples, com humor.</p>
        </div>

        <div>
          <label htmlFor="voz-publico" className="ns-rotulo">Para quem falamos</label>
          <input
            id="voz-publico"
            value={voz.publico}
            disabled={!podeMexer}
            onChange={(e) => mudou('publico', e.target.value)}
            placeholder="Ex.: famílias da zona, que querem ser bem atendidas"
            className="h-9 w-full border border-border bg-background px-3 text-sm text-foreground outline-none"
          />
        </div>

        <div>
          <label htmlFor="voz-exemplos" className="ns-rotulo">Soa assim</label>
          <ListaCurta id="voz-exemplos" valores={voz.exemplos} maximo={2} marcador="Ex.: Passa cá, nós ajudamos-te a escolher." podeMexer={podeMexer} origem={origem} onMudar={(v) => mudou('exemplos', v)} />
          <p className="ns-ajuda">Uma ou duas frases no teu estilo. Ensinam o estilo; os preços e as ofertas vêm sempre do briefing.</p>
          {/* Uma frase que fala do que se retirou já não vai às campanhas
              (lib/voz.js, conflitosDaVoz); diz-se qual, para a tirar ou reescrever. */}
          {(d.conflitos || []).filter((c) => voz.exemplos.includes(c.texto) || voz.essencia === c.texto).map((c) => (
            <p key={c.texto} className="mt-1.5 border-l-2 border-accent pl-3 text-xs text-foreground">
              {`«${c.texto}» fala do mesmo que «${c.facto}», que ${c.estado === 'proibido' ? 'nunca se escreve' : 'foi retirado'}. As campanhas já não usam esta frase: tira-a ou reescreve-a.`}
            </p>
          ))}
        </div>

        <div>
          <label htmlFor="voz-evitar" className="ns-rotulo">Preferimos evitar</label>
          <ListaCurta id="voz-evitar" valores={voz.evitar} maximo={10} marcador="Ex.: imperdível" podeMexer={podeMexer} origem={origem} onMudar={(v) => mudou('evitar', v)} />
          <p className="ns-ajuda">O texto tenta não usar. Se for mesmo proibido, põe em "Nunca usar", em baixo.</p>
        </div>

        {podeMexer && alterado && (
          <div className="flex flex-wrap gap-2">
            <button type="button" disabled={ocupado} onClick={guardar} className="bg-primary px-4 py-2 text-sm text-primary-foreground hover:bg-primary/90 disabled:bg-secondary disabled:text-muted-foreground">
              {d.voz ? 'Guardar as correcções' : 'Guardar como a marca fala'}
            </button>
            {d.voz && (
              <button type="button" onClick={() => setVoz(vozInicial(d))} className="border border-border px-4 py-2 text-sm hover:bg-secondary">
                Desfazer
              </button>
            )}
          </div>
        )}
      </section>

      <section className="max-w-2xl space-y-3 border-t border-border pt-6">
        <div>
          <h3 className="ns-seccao-titulo">Nunca usar</h3>
          <p className="text-xs text-muted-foreground">
            Um texto de uma campanha com isto é recusado, mesmo corrigido à mão. Ex.: uma certificação que já não tens.
          </p>
        </div>
        {/* O que o manual proíbe, sugerido: um clique acrescenta, com o excerto
            como motivo. Não se acrescenta sozinho -- bloqueia textos. */}
        {podeMexer && sugeridas.length > 0 && (
          <div className="border-l-2 border-accent bg-[hsl(var(--accent)/0.08)] px-3 py-2">
            <p className="text-xs text-foreground">O teu manual diz para nunca usar:</p>
            <ul className="mt-1 space-y-1">
              {sugeridas.map((s) => (
                <li key={s.texto} className="flex flex-wrap items-baseline gap-x-1.5 text-sm">
                  <span className="text-foreground">{s.texto}</span>
                  <span className="text-xs text-muted-foreground">{`«${s.excerto}»`}</span>
                  <button
                    type="button"
                    disabled={ocupado}
                    onClick={() => accao(() => api.post(`/api/${slug}/marca/regras`, { texto: s.texto, motivo: `Do manual: «${s.excerto}»` }), null, false)}
                    className="ns-btn ns-btn-sm ns-btn-suave text-xs disabled:opacity-50"
                  >
                    Acrescentar
                  </button>
                </li>
              ))}
            </ul>
          </div>
        )}
        {regrasNunca.length > 0 && (
          <ul className="space-y-1.5">
            {regrasNunca.map((r) => (
              <li key={r.id} className="flex flex-wrap items-baseline gap-x-3 gap-y-0.5 text-sm">
                <span className="text-foreground">{r.texto}</span>
                {r.motivo && <span className="text-xs text-muted-foreground">{r.motivo}</span>}
                {podeMexer && (
                  <button type="button" disabled={ocupado} onClick={() => retirarRegra(r)} className="text-xs text-muted-foreground underline underline-offset-2 hover:text-foreground">
                    Retirar
                  </button>
                )}
              </li>
            ))}
          </ul>
        )}
        {podeMexer && (
          <div className="flex flex-wrap gap-2">
            <input
              aria-label="O que nunca se usa"
              value={regra.texto}
              onChange={(e) => setRegra({ ...regra, texto: e.target.value })}
              placeholder="Ex.: o nome de um concorrente"
              className="h-9 min-w-[10rem] border border-border bg-background px-3 text-sm text-foreground outline-none"
            />
            <input
              aria-label="Porquê (opcional)"
              value={regra.motivo}
              onChange={(e) => setRegra({ ...regra, motivo: e.target.value })}
              placeholder="Porquê (opcional)"
              className="h-9 min-w-[12rem] grow border border-border bg-background px-3 text-sm text-foreground outline-none"
            />
            <button type="button" disabled={ocupado || regra.texto.trim().length < 2} onClick={criarRegra} className="h-9 border border-border px-3 text-sm disabled:opacity-50">
              Acrescentar
            </button>
          </div>
        )}
      </section>

      {/* As frases obrigatórias (28 Set, migração 051): entram em todas as
          peças, tal como estão, pelo sistema -- "Beba com moderação", um aviso legal. */}
      <section className="max-w-2xl space-y-3 border-t border-border pt-6">
        <div>
          <h3 className="ns-seccao-titulo">Leva sempre</h3>
          <p className="text-xs text-muted-foreground">
            Uma frase que tem de estar em todas as peças, tal como está. Entra no post, no texto legal dos painéis e no fim do vídeo.
          </p>
        </div>
        {podeMexer && sempreSugeridas.length > 0 && (
          <div className="border-l-2 border-accent bg-[hsl(var(--accent)/0.08)] px-3 py-2">
            <p className="text-xs text-foreground">O teu manual obriga a:</p>
            <ul className="mt-1 space-y-1">
              {sempreSugeridas.map((s) => (
                <li key={s.texto} className="flex flex-wrap items-baseline gap-x-1.5 text-sm">
                  <span className="text-foreground">{s.texto}</span>
                  <button
                    type="button"
                    disabled={ocupado}
                    onClick={() => accao(() => api.post(`/api/${slug}/marca/regras`, { texto: s.texto, motivo: 'Do manual da marca.', tipo: 'sempre' }), null, false)}
                    className="ns-btn ns-btn-sm ns-btn-suave text-xs disabled:opacity-50"
                  >
                    Acrescentar
                  </button>
                </li>
              ))}
            </ul>
          </div>
        )}
        {regrasSempre.length > 0 && (
          <ul className="space-y-1.5">
            {regrasSempre.map((r) => (
              <li key={r.id} className="flex flex-wrap items-baseline gap-x-3 text-sm">
                <span className="text-foreground">{r.texto}</span>
                {podeMexer && (
                  <button type="button" disabled={ocupado} onClick={() => retirarRegra(r)} className="text-xs text-muted-foreground underline underline-offset-2 hover:text-foreground">
                    Retirar
                  </button>
                )}
              </li>
            ))}
          </ul>
        )}
        {podeMexer && (
          <div className="flex flex-wrap gap-2">
            <input
              aria-label="Uma frase que leva sempre"
              value={frase}
              onChange={(e) => setFrase(e.target.value)}
              placeholder="Ex.: Seja responsável. Beba com moderação."
              className="h-9 min-w-[16rem] grow border border-border bg-background px-3 text-sm text-foreground outline-none"
            />
            <button
              type="button"
              disabled={ocupado || frase.trim().length < 2}
              onClick={() => accao(async () => { await api.post(`/api/${slug}/marca/regras`, { texto: frase, tipo: 'sempre' }); setFrase(''); }, null, false)}
              className="h-9 border border-border px-3 text-sm disabled:opacity-50"
            >
              Acrescentar
            </button>
          </div>
        )}
      </section>

      {aviso && <p className="text-sm text-muted-foreground" role="status">{aviso}</p>}
    </div>
  );
}
