/**
 * Os dois passos da autenticação em dois passos da equipa NetScreen.
 *
 * Não são rotas. Vivem dentro do `ScreenLogin`, porque só existem entre a
 * password e a sessão: uma rota `/mfa` seria alcançável por quem nunca
 * escreveu a password, e aí o ecrã tinha de decidir se devia estar ali — uma
 * decisão que alguém se esquece de escrever. Assim o problema não se põe.
 *
 * O servidor guarda quem está a meio em `req.session.mfaPendente`, e nunca em
 * `req.session.user`: uma sessão a meio não passa em nenhuma rota protegida.
 */

/** O segredo em grupos de quatro. Trinta e dois caracteres seguidos não se copiam à mão. */
function agruparSegredo(segredo) {
  return (segredo.match(/.{1,4}/g) || []).join(' ');
}

/**
 * O campo dos seis dígitos.
 *
 * `inputMode="numeric"` põe o teclado numérico no telemóvel, e
 * `autoComplete="one-time-code"` deixa o iOS oferecer o código. Filtra tudo o
 * que não seja dígito: quem copia do autenticador traz muitas vezes o espaço
 * do meio, e recusar por causa disso é mesquinho.
 */
function CampoCodigo({ valor, onChange, disabled, rotulo, descricao }) {
  return (
    <div>
      <label htmlFor="codigo" className="label-eyebrow block">
        {rotulo}
      </label>
      {descricao && (
        <p id="codigo-ajuda" className="mt-1 text-xs text-muted-foreground">
          {descricao}
        </p>
      )}
      <input
        id="codigo"
        name="codigo"
        type="text"
        inputMode="numeric"
        autoComplete="one-time-code"
        aria-describedby={descricao ? 'codigo-ajuda' : undefined}
        value={valor}
        onChange={e => onChange(e.target.value.replace(/\D/g, '').slice(0, 6))}
        disabled={disabled}
        autoFocus
        required
        className="mt-2 w-full border border-border bg-background px-3 py-2.5 text-center font-mono text-xl
                   tracking-[0.4em] text-foreground focus:border-primary focus:outline-none
                   disabled:opacity-50"
      />
    </div>
  );
}

/** Copiar o segredo para a área de transferência, com aviso de que resultou. */
function BotaoCopiar({ texto }) {
  const [copiado, setCopiado] = React.useState(false);

  async function copiar() {
    try {
      await navigator.clipboard.writeText(texto);
      setCopiado(true);
      setTimeout(() => setCopiado(false), 2000);
    } catch {
      // Sem permissão para a área de transferência (acontece fora de https).
      // O segredo está à vista e selecciona-se à mão — não vale um erro.
    }
  }

  return (
    <button
      type="button"
      onClick={copiar}
      className="shrink-0 border border-border px-2 py-1 text-xs text-muted-foreground
                 transition-colors hover:border-primary hover:text-foreground"
    >
      {copiado ? 'Copiado' : 'Copiar'}
      {/* Anunciado sem depender da cor nem da posição. */}
      <span className="sr-only">{copiado ? ' a chave' : ' a chave para a área de transferência'}</span>
    </button>
  );
}

/**
 * Primeiro passo, uma vez na vida: ler o QR e provar que a aplicação gera os
 * códigos certos.
 *
 * O `/setup` grava o segredo mas **não** activa nada. Quem fecha o ecrã aqui
 * não fica com a conta trancada: da próxima vez volta a este mesmo sítio com
 * um segredo novo.
 */
function MfaConfigurar({ email, onEntrou, onCancelar }) {
  const [dados, setDados] = React.useState(null);
  const [codigo, setCodigo] = React.useState('');
  const [erro, setErro] = React.useState(null);
  const [aConfirmar, setAConfirmar] = React.useState(false);

  React.useEffect(() => {
    api
      .post('/api/auth/mfa/setup', {})
      .then(setDados)
      .catch(err => setErro(err.message));
  }, []);

  async function submeter(e) {
    e.preventDefault();
    setErro(null);
    setAConfirmar(true);
    try {
      await api.post('/api/auth/mfa/confirm', { codigo });
      onEntrou();
    } catch (err) {
      setErro(err.message);
      setCodigo('');
      setAConfirmar(false);
    }
  }

  return (
    <CartaoAuth
      sobretitulo="Segurança"
      titulo="Configura o segundo passo"
      rodape={
        <p className="mt-4 text-center text-xs text-muted-foreground">
          Perdeste o telemóvel? <span className="text-foreground">Fala com o Fábio</span> — a MFA tem
          de ser reposta no servidor.
        </p>
      }
    >
      <p className="mt-4 text-sm text-muted-foreground">
        O back office da NetScreen mexe em contas de clientes e em painéis instalados na rua. Uma
        password sozinha não chega, por isso a equipa entra sempre em dois passos.
      </p>

      {erro && !dados && (
        <div className="mt-6">
          <ErroAuth>{erro}</ErroAuth>
        </div>
      )}

      {!dados && !erro && (
        <div className="mt-6 h-48 animate-pulse bg-muted" aria-label="A preparar o código" />
      )}

      {dados && (
        <React.Fragment>
          <ol className="mt-6 space-y-5 text-sm">
            <li>
              <p className="text-foreground">
                <span className="label-eyebrow mr-2">1</span>
                Abre o Google Authenticator, o Microsoft Authenticator ou o 1Password e lê este
                código.
              </p>
              {/* Fundo branco fixo: um QR sobre o cinzento do cartão perde contraste
                  e há leitores que desistem dele. */}
              <div className="mt-3 flex justify-center border border-border bg-white p-4">
                {/* Decorativo: quem não o vê tem a chave em texto no passo 2. */}
                <img src={dados.qr} alt="" className="h-40 w-40" />
              </div>
            </li>

            <li>
              <p className="text-foreground">
                <span className="label-eyebrow mr-2">2</span>
                Não consegues ler o código? Escreve esta chave à mão, para a conta{' '}
                <span className="text-muted-foreground">{dados.email || email}</span>.
              </p>
              <div className="mt-3 flex items-center gap-2 border border-border bg-muted px-3 py-2">
                <code className="grow break-words font-mono text-xs tracking-wider text-foreground">
                  {agruparSegredo(dados.segredo)}
                </code>
                <BotaoCopiar texto={dados.segredo} />
              </div>
            </li>
          </ol>

          <form onSubmit={submeter} className="mt-6 space-y-4" noValidate>
            <CampoCodigo
              rotulo="3. Código da aplicação"
              descricao="Os seis dígitos que a aplicação mostra agora."
              valor={codigo}
              onChange={setCodigo}
              disabled={aConfirmar}
            />
            {erro && <ErroAuth>{erro}</ErroAuth>}
            <BotaoAuth disabled={aConfirmar || codigo.length < 6}>
              {aConfirmar ? 'A confirmar...' : 'Activar e entrar'}
            </BotaoAuth>
          </form>
        </React.Fragment>
      )}

      <button
        type="button"
        onClick={onCancelar}
        className="mt-6 text-xs text-muted-foreground underline underline-offset-2 hover:text-foreground"
      >
        Voltar ao início
      </button>
    </CartaoAuth>
  );
}

/** Segundo passo, em cada login: o código de quem já tem a MFA configurada. */
function MfaVerificar({ email, onEntrou, onCancelar }) {
  const [codigo, setCodigo] = React.useState('');
  const [erro, setErro] = React.useState(null);
  const [aVerificar, setAVerificar] = React.useState(false);

  async function submeter(e) {
    e.preventDefault();
    setErro(null);
    setAVerificar(true);
    try {
      await api.post('/api/auth/mfa/verify', { codigo });
      onEntrou();
    } catch (err) {
      setErro(err.message);
      // Limpar o campo: o código anterior já não serve nunca mais, e deixá-lo
      // lá convida a carregar outra vez no mesmo — que gasta uma tentativa.
      setCodigo('');
      setAVerificar(false);
    }
  }

  return (
    <CartaoAuth sobretitulo="Segundo passo" titulo="Código da aplicação">
      <p className="mt-4 text-sm text-muted-foreground">
        A entrar como <span className="text-foreground">{email}</span>.
      </p>

      <form onSubmit={submeter} className="mt-6 space-y-4" noValidate>
        <CampoCodigo
          rotulo="Código"
          descricao="Seis dígitos, do autenticador onde configuraste esta conta."
          valor={codigo}
          onChange={setCodigo}
          disabled={aVerificar}
        />
        {erro && <ErroAuth>{erro}</ErroAuth>}
        <BotaoAuth disabled={aVerificar || codigo.length < 6}>
          {aVerificar ? 'A verificar...' : 'Entrar'}
        </BotaoAuth>
      </form>

      <button
        type="button"
        onClick={onCancelar}
        className="mt-6 text-xs text-muted-foreground underline underline-offset-2 hover:text-foreground"
      >
        Entrar com outra conta
      </button>
    </CartaoAuth>
  );
}
