/**
 * Back office — clientes.
 *
 * Lê da base de dados desde 21 Set 2026 (`/api/admin/accounts`). Criar um
 * cliente escreve na tabela e a lista volta a ser lida — recarregar a página
 * mostra o mesmo.
 *
 * O que ainda não tem tabela por baixo — o brand kit, e o estado online dos
 * painéis, que vive na VNNOX — mostra-se `—`. Nunca zero: zero diria que não
 * há, e a verdade é que ainda não sabemos. O custo de IA também chega a
 * `null` para quem não é Admin, e aí o `—` quer dizer "não é para ti".
 *
 * Duas coisas que este ecrã põe à vista de propósito:
 *
 *   1. **O custo por cliente é uma coluna**, porque foi o que o FC disse ser o
 *      mais importante do back office. Vem do `token_usage` desde 23 Set (o
 *      custo do mês a preço de tabela), e a margem é a mensalidade menos isso
 *   2. **Uma agência cria os anunciantes na mesma acção.** Cada um é uma conta
 *      `sub_client` ligada à agência por `parent_agency_id`, com o seu próprio
 *      brand kit — é o que resolve o caso que o schema antigo não suportava
 *
 * Criar um cliente é uma página (`screen_admin_cliente_novo.jsx`), e abrir um
 * também: a linha leva à ficha (`screen_admin_marca.jsx`), que tem as acções
 * todas. Até 23 Set havia um drawer de resumo pelo meio, que repetia metade da
 * ficha e não deixava fazer nada — a regra passou a ser "entidade abre em
 * página, acção abre em modal", e os drawers saíram.
 */

const PLANOS_BACKOFFICE = [
  { codigo: 'essencial', rotulo: 'Essencial' },
  { codigo: 'retail_pro', rotulo: 'Retail Pro' },
  { codigo: 'multi_loja', rotulo: 'Multi-loja' },
];

// Com separador de milhares (utils/format.js): «8400,00 €» lia-se mal (demo de 12 Out).
const euros = (v) => formatEuros(v);

/** "hoje", "há 2 dias", "há 41 dias" — o número é o que dispara o alerta. */
function desde(iso) {
  if (!iso) return null;
  const dias = Math.max(0, Math.round((Date.now() - new Date(iso)) / 86400000));
  return { dias, texto: dias === 0 ? 'hoje' : dias === 1 ? 'há 1 dia' : `há ${dias} dias` };
}

/** A conta que o ecrã existe para responder: a mensalidade cobre o consumo de IA? */
function margem(c) {
  // Só numa conta activa: uma por activar ainda não paga, e aparecia com margem (agentes, 20 Out).
  if (c.estado !== 'activo' || c.mensalidade == null || c.custo == null) return null;
  return {
    valor: c.mensalidade - c.custo,
    pct: c.mensalidade === 0 ? 0 : ((c.mensalidade - c.custo) / c.mensalidade) * 100,
  };
}

/** Campo de formulário. Vira primitivo <Campo> quando houver mais que um ecrã a usá-lo. */
function CampoTexto({ etiqueta, valor, aoMudar, tipo = 'text', dica, placeholder, obrigatorio }) {
  const id = React.useId();
  return (
    <div>
      <label htmlFor={id} className="block text-xs uppercase tracking-wider text-muted-foreground">
        {etiqueta}
        {obrigatorio && <span className="ml-1 text-primary">*</span>}
      </label>
      <input
        id={id}
        type={tipo}
        value={valor}
        placeholder={placeholder}
        onChange={(e) => aoMudar(e.target.value)}
        className="mt-1.5 w-full min-w-0 border border-border bg-background px-3 py-2 text-sm text-foreground outline-none placeholder:text-muted-foreground focus-visible:border-accent"
      />
      {dica && <p className="mt-1 text-xs text-muted-foreground">{dica}</p>}
    </div>
  );
}

function Seccao({ numero, titulo, descricao, children }) {
  return (
    <section className="border-t border-border pt-5 first:border-t-0 first:pt-0">
      <div className="flex items-baseline gap-3">
        <span className="font-display text-lg leading-none text-muted-foreground">{numero}</span>
        <h3 className="font-display text-lg uppercase leading-none tracking-wide">{titulo}</h3>
      </div>
      {descricao && <p className="mt-1.5 text-xs text-muted-foreground">{descricao}</p>}
      <div className="mt-4 space-y-4">{children}</div>
    </section>
  );
}

const ROTULO_TIPO = { retalho: 'Retalho', agencia: 'Agência', sub_cliente: 'Anunciante', trial: 'Trial' };

/** Um valor que a API ainda não sabe (null) mostra-se como traço, nunca como zero. */
const semDado = <span className="text-muted-foreground">—</span>;

function ScreenAdminClientes({ onNavegar, onEntrarComo }) {
  const [clientes, setClientes] = React.useState(null);
  // null até a lista chegar: sem isto o Operator via o «Criar cliente» piscar.
  const [receitaVisivel, setReceitaVisivel] = React.useState(null);
  const [erro, setErro] = React.useState(null);
  const [toast, setToast] = React.useState(null);

  const carregar = React.useCallback(
    () =>
      api
        .get('/api/admin/accounts')
        .then((r) => {
          setClientes(r.contas);
          setReceitaVisivel(r.receita_visivel !== false);
          setErro(null);
        })
        // Sem a lista não se sabe o perfil: o botão aparece, e a rota decide (revisor, 20 Out).
        .catch((e) => { setErro(e.message || 'Não foi possível ler os clientes.'); setReceitaVisivel((v) => (v === null ? true : v)); }),
    []
  );

  React.useEffect(() => {
    carregar();

    // Vindo da página de criação: mostra o aviso e abre o resumo do cliente novo,
    // que é onde se vê o que falta fazer a seguir.
    try {
      const guardado = sessionStorage.getItem('flashClientes');
      if (guardado) {
        sessionStorage.removeItem('flashClientes');
        const { mensagem, abrir } = JSON.parse(guardado);
        setToast({ id: Date.now(), mensagem });
        if (abrir) onNavegar(`/admin/clientes/${abrir}`);
      }
    } catch { /* sem storage: sem aviso, a lista continua certa */ }
  }, [carregar]);


  const fecharToast = React.useCallback(() => setToast(null), []);

  const colunas = [
    {
      chave: 'nome', rotulo: 'Cliente', ordenavel: true, principal: true,
      // O tipo vive debaixo do nome em vez de ocupar coluna própria.
      render: (l) => (
        <span>
          {l.nome}
          <span className="mt-0.5 block text-xs font-normal text-muted-foreground">
            {l.agencia ? `${ROTULO_TIPO[l.tipo]} · ${l.agencia.nome}` : ROTULO_TIPO[l.tipo] || l.tipo}
          </span>
        </span>
      ),
    },
    {
      chave: 'plano', rotulo: 'Plano', ordenavel: true,
      render: (l) =>
        l.plano ? (
          <Badge variante={l.plano_codigo === 'essencial' ? 'contorno' : 'primario'}>{l.plano}</Badge>
        ) : (
          semDado
        ),
    },
    {
      chave: 'lojas', rotulo: 'Estrutura', ordenavel: true,
      render: (l) =>
        l.tipo === 'agencia'
          ? `${l.marcas} ${l.marcas === 1 ? 'marca' : 'marcas'} · ${l.lojas} ${l.lojas === 1 ? 'loja' : 'lojas'}`
          : `${l.lojas} ${l.lojas === 1 ? 'loja' : 'lojas'}`,
    },
    {
      chave: 'paineis', rotulo: 'Painéis', alinhamento: 'direita',
      valorOrdenacao: (l) => l.paineis.total,
      // O estado online vive na VNNOX e ainda não é sincronizado — só o total é conhecido.
      render: (l) =>
        l.paineis.total ? (
          <Badge variante="contorno">{String(l.paineis.total)}</Badge>
        ) : (
          <span className="text-muted-foreground">nenhum</span>
        ),
    },
    {
      chave: 'fontes', rotulo: 'Conhecimento',
      valorOrdenacao: (l) => (l.fontes ? l.fontes.total : null),
      render: (l) => {
        if (!l.fontes) return semDado;
        return l.fontes.total === 0 ? (
          <span className="text-muted-foreground">sem fontes</span>
        ) : l.fontes.erro ? (
          <Badge variante="erro">{`${l.fontes.lidas} de ${l.fontes.total} lidas · ${l.fontes.erro} com erro`}</Badge>
        ) : (
          // «1/1» não se percebia (agentes, 20 Out): são fontes da marca lidas.
          <Badge variante="sucesso">{`${l.fontes.lidas} de ${l.fontes.total} ${l.fontes.total === 1 ? 'lida' : 'lidas'}`}</Badge>
        );
      },
    },
    {
      chave: 'campanhas', rotulo: 'Campanhas', alinhamento: 'direita', ordenavel: true,
      render: (l) => (l.campanhas == null ? semDado : l.campanhas),
    },
    {
      chave: 'ultimaActividade', rotulo: 'Actividade',
      valorOrdenacao: (l) => (l.ultimaActividade ? new Date(l.ultimaActividade).getTime() : null),
      render: (l) => {
        const d = desde(l.ultimaActividade);
        if (!d) return <span className="text-muted-foreground">nunca</span>;
        // 30 dias é o limiar do alerta "conta inactiva" que o plano previa.
        return <span className={d.dias > 30 ? 'text-accent' : ''}>{d.texto}</span>;
      },
    },
    {
      chave: 'mensalidade', rotulo: 'Mensalidade', alinhamento: 'direita', ordenavel: true,
      render: (l) =>
        l.mensalidade == null ? (
          <span className="text-muted-foreground">sob consulta</span>
        ) : (
          euros(l.mensalidade)
        ),
    },
    {
      chave: 'custo', rotulo: 'Custo IA', alinhamento: 'direita',
      render: (l) => (l.custo == null ? semDado : <span className="whitespace-nowrap">{euros(l.custo)}</span>),
    },
    {
      chave: 'margem', rotulo: 'Margem', alinhamento: 'direita',
      valorOrdenacao: (l) => {
        const m = margem(l);
        return m ? m.valor : null;
      },
      render: (l) => {
        const m = margem(l);
        if (!m) return semDado;
        return (
          <span className={'whitespace-nowrap ' + (m.pct < 70 ? 'text-perigo-texto' : 'text-foreground')}>
            {euros(m.valor)}
            {/* 99,99% arredondava para 100%, que diz custo zero (agentes, 20 Out). */}
            <span className="ml-1.5 text-xs text-muted-foreground">{m.pct < 100 ? Math.min(99, Math.round(m.pct)) : 100}%</span>
          </span>
        );
      },
    },
  ];

  // A mensalidade, o custo e a margem são só do Admin: ao Operator a API manda-os a null, e a
  // mensalidade a null lia-se «sob consulta» (agentes, 20 Out). As colunas saem.
  const colunasVisiveis = receitaVisivel ? colunas : colunas.filter((c) => !['mensalidade', 'custo', 'margem'].includes(c.chave));

  const receita = clientes
    ? clientes.filter((c) => c.estado === 'activo' && c.mensalidade != null).reduce((s, c) => s + c.mensalidade, 0)
    : 0;

  if (erro) {
    return (
      <div className="space-y-6">
        <header>
          <h1 className="mt-1 font-display text-4xl uppercase leading-none tracking-wide">Clientes</h1>
        </header>
        <div className="border border-border bg-card px-6 py-12 text-center">
          <p className="font-display text-xl tracking-wide">Não deu para ler os clientes</p>
          <p className="mt-2 text-sm text-muted-foreground">{erro}</p>
        </div>
      </div>
    );
  }

  return (
    <div className="space-y-6">
      <header className="flex flex-wrap items-end justify-between gap-4">
        <div>
          <h1 className="mt-1 font-display text-4xl uppercase leading-none tracking-wide">Clientes</h1>
          {clientes && (
            <p className="mt-2 text-sm text-muted-foreground">
              {/* Diz o que soma: só as activas com mensalidade; as «sob consulta» ficam de fora (director virgem A4). */}
              {clientes.length} contas{receitaVisivel ? ` · ${euros(receita)} de receita mensal das contas activas${(() => { const n = clientes.filter((c) => c.estado === 'activo' && c.mensalidade == null).length; return n ? ` (sem ${n} ${n === 1 ? 'conta' : 'contas'} sob consulta)` : ''; })()}` : ''}
            </p>
          )}
          <p className="mt-1 text-xs text-muted-foreground">
            {receitaVisivel === null ? '' : receitaVisivel
              ? 'Custo de IA do mês a preço de tabela da Anthropic; a margem é a mensalidade menos esse custo.'
              : 'A mensalidade, o custo de IA e a margem são só para o Admin.'}
          </p>
        </div>
        {/* Criar clientes é do Admin, como a receita (a API decide os dois pelo mesmo papel): o
            Operator preenchia o formulário inteiro e só no fim lia «Sem acesso» (agentes, 20 Out). */}
        {receitaVisivel ? (
          <button
            type="button"
            onClick={() => onNavegar('/admin/clientes/novo')}
            className="bg-primary px-4 py-2 text-sm uppercase tracking-wider text-primary-foreground outline-none hover:bg-primary/90 focus-visible:ring-1 focus-visible:ring-accent"
          >
            Criar cliente
          </button>
        ) : (
          clientes && <p className="text-xs text-muted-foreground">Criar clientes é do Admin.</p>
        )}
      </header>

      <Tabela
        colunas={colunasVisiveis}
        linhas={clientes || []}
        carregando={!clientes}
        chaveLinha={(l) => l.slug}
        aoClicar={(l) => onNavegar(`/admin/clientes/${l.slug}`)}
        ordemInicial={{ chave: 'nome', sentido: 'asc' }}
        pesquisa={{ campos: ['nome', 'plano', 'slug'], placeholder: 'Pesquisar cliente' }}
        vazio={{
          titulo: 'Ainda não há clientes',
          descricao: 'As contas nascem aqui. É neste passo que se recolhe o que o agente do cliente precisa de saber.',
        }}
      />

      <Toast toast={toast} onFechar={fecharToast} />
    </div>
  );
}

/**
 * Detalhe do cliente.
 *
 * O coração é a checklist de onboarding: de um cliente concreto, o que é que
 * ainda falta para ele poder arrancar. É aqui que se vê que uma conta foi
 * criada e nunca chegou a ter conteúdo.
 *
 * Estados por linha: feito (verde), com aviso (laranja), e por fazer ou por
 * ligar (neutro). Por fazer deixou de ser vermelho a 7 Out: um passo que ainda
 * não chegou não é uma falha.
 */

function LinhaChecklist({ feito, aviso, desconhecido, titulo, detalhe, accao, extra }) {
  // Por fazer fica neutro, como o desconhecido: um passo que ainda não chegou não é
  // uma falha, e o vermelho fazia-o parecer uma (ensaio da demo de 12 Out).
  const neutro = desconhecido || (!feito && !aviso);
  const cor = neutro
    ? 'var(--muted-foreground)'
    : feito
    ? 'var(--online)'
    : 'var(--accent)';
  return (
    <div className="flex items-start gap-3 border-t border-border py-3 first:border-t-0">
      <span
        className="mt-1.5 h-2 w-2 shrink-0"
        style={{ background: 'hsl(' + cor + ')', opacity: neutro ? 0.5 : 1 }}
        aria-hidden="true"
      />
      <div className="min-w-0 flex-1">
        <p className="text-sm text-foreground">
          {titulo}
          <span className="sr-only">
            {desconhecido ? ' — por ligar' : feito ? ' — feito' : aviso ? ' — com aviso' : ' — por fazer'}
          </span>
        </p>
        {detalhe && <p className="mt-0.5 text-xs text-muted-foreground">{detalhe}</p>}
        {extra}
      </div>
      {accao && !feito && !desconhecido && (
        <span className="shrink-0 text-xs uppercase tracking-wider text-muted-foreground">
          {accao}
        </span>
      )}
    </div>
  );
}
