/**
 * NetScreen AI — router e raiz da SPA.
 *
 * Routing multi-tenant no cliente: /:slug/:seccao/:id?
 * O Express devolve sempre o index.html — quem resolve a rota é este ficheiro.
 * O servidor valida sempre o slug na API (middleware requireSlug).
 */

/** Slugs que não podem ser contas — colidiriam com rotas do sistema. */
const SLUGS_RESERVADOS = ['admin', 'api', 'login', 'invite', 'repor', 'js', 'css', 'assets'];

function parseRota(pathname) {
  const partes = pathname.split('/').filter(Boolean);

  // /login com sessão é o início: quem entrava por /login ficava num 404 depois
  // de "Entrar", porque o endereço não mudava (cliente simulado, 24 Set).
  if (!partes.length || (partes.length === 1 && partes[0] === 'login')) return { tipo: 'raiz' };
  // /admin/:id/:sub — o back office precisa do terceiro segmento para a ficha
  // de um cliente: /admin/clientes/multioticas.
  if (partes[0] === 'admin') {
    return { tipo: 'admin', seccao: 'admin', id: partes[1] || null, sub: partes[2] || null };
  }
  if (SLUGS_RESERVADOS.includes(partes[0])) return { tipo: '404' };

  return {
    tipo: 'conta',
    slug: partes[0],
    seccao: partes[1] || 'dashboard',
    id: partes[2] || null,
    // /:slug/campanhas/:id/briefing (28 Set: o briefing passou a página).
    sub: partes[3] || null,
  };
}

/**
 * Quem pode mexer no que e da conta.
 *
 * O `viewer` ve e nao altera; a equipa NetScreen mexe em qualquer conta, que e
 * o que lhe permite montar a conta de um cliente antes de lha entregar. O
 * servidor valida na mesma -- isto so evita mostrar botoes que iam dar 403.
 */
function podeMexerAqui(me) {
  if (!me || !me.user) return false;
  if (me.user.tipo === 'netscreen') return true;
  return me.user.role === 'owner' || me.user.role === 'editor';
}

const SECCOES_VALIDAS = [
  'dashboard',
  'campanhas',
  'criar',
  'lojas',
  'paineis-pdv',
  'resultados',
  'configuracao',
  'conhecimento',
  'marca',
  'biblioteca',
];

const TITULOS = {
  campanhas: 'Campanhas',
  criar: 'Criar',
  lojas: 'Lojas',
  'paineis-pdv': 'Painéis e assistente',
  resultados: 'Resultados',
  configuracao: 'Conta',
  conhecimento: 'A minha marca',
  marca: 'A minha marca',
  biblioteca: 'Biblioteca',
  admin: 'Rede NetScreen',
};

function ErroArranque({ mensagem }) {
  return (
    <div className="flex min-h-screen items-center justify-center p-6">
      <div className="w-full max-w-md border border-border bg-card p-8">
        <p className="label-eyebrow">Erro</p>
        <h1 className="mt-2 font-display text-3xl leading-none">A aplicação não arrancou</h1>
        <p className="mt-3 text-sm text-muted-foreground">{mensagem}</p>
        <p className="mt-4 text-xs text-muted-foreground">
          Confirma que a base de dados está a correr: <code>npm run db:up</code> seguido de{' '}
          <code>npm run db:setup</code>.
        </p>
      </div>
    </div>
  );
}

function App() {
  const [estado, setEstado] = React.useState({ fase: 'a-carregar' });
  const [pathname, setPathname] = React.useState(window.location.pathname);

  const carregarSessao = React.useCallback(() => {
    return api
      .get('/api/me')
      .then(me => setEstado({ fase: 'pronto', me }))
      .catch(err => {
        if (err.status === 401) return setEstado({ fase: 'sem-sessao' });
        setEstado({ fase: 'erro', mensagem: err.message });
      });
  }, []);

  // Carrega o utilizador da sessão ao arrancar
  React.useEffect(() => {
    carregarSessao();
  }, [carregarSessao]);

  // Botões voltar/avançar do browser
  // Com alterações por guardar, o "voltar" também pergunta (revisor, 24 Set). O
  // endereço já mudou quando o evento chega: se a pessoa fica, repõe-se.
  const ondeEstava = React.useRef(window.location.pathname);
  React.useEffect(() => { ondeEstava.current = pathname; }, [pathname]);
  React.useEffect(() => {
    const onPop = () => {
      if (window.__porGuardar && !window.confirm(`${window.__porGuardar} Sair sem guardar?`)) {
        window.history.pushState({}, '', ondeEstava.current);
        return;
      }
      if (window.__porGuardar) window.dispatchEvent(new Event('descartar-alteracoes'));
      window.__porGuardar = null;
      setPathname(window.location.pathname);
    };
    window.addEventListener('popstate', onPop);
    return () => window.removeEventListener('popstate', onPop);
  }, []);

  const navegar = React.useCallback(href => {
    if (href === window.location.pathname) return;
    // Um formulário com alterações por guardar regista-se em
    // `window.__porGuardar` (o briefing, 24 Set: saía-se pelo menu e perdia-se
    // tudo sem aviso). A confirmação do browser chega: é uma pergunta de sim ou não.
    if (window.__porGuardar && !window.confirm(`${window.__porGuardar} Sair sem guardar?`)) return;
    if (window.__porGuardar) window.dispatchEvent(new Event('descartar-alteracoes'));
    window.__porGuardar = null;
    window.history.pushState({}, '', href);
    // Só o caminho: com o `href` inteiro, "?ver=sinalizado" ia colado ao slug e
    // o ecrã dos dados da marca rebentava (fila "A tratar", 28 Set). A query lê-a
    // cada ecrã em `window.location.search`.
    setPathname(window.location.pathname);
  }, []);

  /**
   * "Ver como cliente" do back office.
   *
   * Fica no sessionStorage e não na rota, porque tem de sobreviver à navegação
   * dentro da área do cliente — o risco desta funcionalidade não é entrar, é
   * esquecer que se entrou. Por isso o AppShell mostra uma barra permanente.
   *
   * O routing já permitia à equipa NetScreen abrir o slug de outra conta; o
   * que faltava era dizê-lo a quem está a olhar, e ter por onde sair.
   */
  const [verComo, setVerComo] = React.useState(() => {
    try {
      const guardado = sessionStorage.getItem('verComo');
      return guardado ? JSON.parse(guardado) : null;
    } catch {
      return null;
    }
  });

  /**
   * Entrar como um cliente pede confirmação — é uma decisão curta que muda de
   * sítio e de identidade, e a regra em docs/padroes-interface.md é modal.
   *
   * Regista primeiro, entra depois: a faixa diz que a entrada fica registada e
   * tem de ser verdade, por isso se o registo falhar não se entra. E como isto
   * vive num modal, o erro aparece lá dentro — antes o botão simplesmente não
   * fazia nada, só um `console.error`.
   */
  const [pedidoVerComo, setPedidoVerComo] = React.useState(null);

  const pedirVerComo = React.useCallback(
    cliente => setPedidoVerComo({ cliente, aRegistar: false, erro: null }),
    []
  );

  // Não se cancela a meio do registo: fechar o modal não desfaz o pedido em curso.
  const cancelarVerComo = React.useCallback(
    () => setPedidoVerComo(p => (p && p.aRegistar ? p : null)),
    []
  );

  const confirmarVerComo = React.useCallback(
    async cliente => {
      setPedidoVerComo({ cliente, aRegistar: true, erro: null });
      try {
        await api.post(`/api/admin/accounts/${cliente.slug}/impersonate`, {});
      } catch (err) {
        setPedidoVerComo({ cliente, aRegistar: false, erro: err.message || 'Não foi possível registar a entrada.' });
        return;
      }
      try {
        sessionStorage.setItem('verComo', JSON.stringify(cliente));
      } catch { /* sessão sem storage: a barra não persiste, mas o resto funciona */ }
      setVerComo(cliente);
      setPedidoVerComo(null);
      // Da ficha do cliente pode vir-se para abrir uma campanha ou um vídeo: cai-se logo lá (4 Nov).
      navegar(cliente.destino && String(cliente.destino).startsWith(`/${cliente.slug}/`) ? cliente.destino : `/${cliente.slug}/dashboard`);
    },
    [navegar]
  );

  const sairDeVerComo = React.useCallback(() => {
    try {
      sessionStorage.removeItem('verComo');
    } catch { /* idem */ }
    // Volta à ficha de onde se partiu, e não à lista (agentes, 20 Out).
    setVerComo(null);
    navegar(verComo && verComo.slug ? `/admin/clientes/${verComo.slug}` : '/admin/clientes');
  }, [navegar, verComo]);

  // O convite vem antes de tudo. Quem chega por um link de convite não tem
  // sessão nenhuma — nem devia ter — e o ecrã não precisa de esperar pelo
  // `/api/me` para saber o que mostrar.
  // Os quatro caminhos que se abrem sem sessão nenhuma:
  //   /invite/:token         convite de cliente
  //   /invite/equipa/:token  convite de equipa
  //   /repor/:token          reposição de password de cliente
  //   /repor/equipa/:token   reposição de password de equipa
  if (pathname.startsWith('/invite/') || pathname.startsWith('/repor/')) {
    const partes = pathname.split('/').filter(Boolean);
    const repor = partes[0] === 'repor';
    const equipa = partes[1] === 'equipa';
    const token = (equipa ? partes[2] : partes[1]) || '';
    return token ? <ScreenConvite token={token} equipa={equipa} repor={repor} /> : <Screen404 />;
  }

  if (estado.fase === 'a-carregar') {
    return (
      <div className="flex h-screen items-center justify-center">
        <span role="status" className="flex items-center gap-3 font-display text-2xl tracking-wide text-muted-foreground">
          <ATrabalhar className="text-primary" />
          A CARREGAR
        </span>
      </div>
    );
  }

  if (estado.fase === 'sem-sessao') {
    return (
      <ScreenLogin
        onEntrou={() => {
          setEstado({ fase: 'a-carregar' });
          carregarSessao();
        }}
      />
    );
  }
  if (estado.fase === 'erro') return <ErroArranque mensagem={estado.mensagem} />;

  const me = estado.me;
  const rota = parseRota(pathname);

  // Raiz: a equipa NetScreen vai para o back office, o cliente para o seu
  // dashboard. Quem é da equipa não pertence a conta nenhuma — `me.account` é
  // null — por isso não há slug para onde o mandar.
  if (rota.tipo === 'raiz') {
    // A equipa começa no «A tratar», o que tem de fazer hoje; abria a Rede, com avisos técnicos (operadora virgem, 4 Nov).
    const destino = me.user.tipo === 'netscreen' ? '/admin/fila' : `/${me.account.slug}/dashboard`;
    window.history.replaceState({}, '', destino);
    setTimeout(() => setPathname(destino), 0);
    return null;
  }

  // O Conhecimento passou a ser "A minha marca" (23 Set). Um link antigo leva
  // lá, e o endereço muda também -- senão o menu não marcava a secção e um
  // link copiado dali continuava a ser o antigo.
  // A Biblioteca também (24 Set): passou a "Ficheiros e fontes", o primeiro
  // separador de "A minha marca".
  // E /conta, que é o nome que o menu e o rasto mostram: dava 404, e a página vive em /configuracao
  // (agentes, 20 Out).
  if (rota.tipo === 'conta' && (rota.seccao === 'conhecimento' || rota.seccao === 'biblioteca' || rota.seccao === 'conta')) {
    // Os Ficheiros têm endereço próprio desde que a marca é a entrada (28 Set).
    const destino = rota.seccao === 'conta' ? `/${rota.slug}/configuracao` : `/${rota.slug}/marca/fontes`;
    window.history.replaceState({}, '', destino);
    setTimeout(() => setPathname(destino), 0);
    return null;
  }

  // Sem conta (equipa NetScreen), o 404 manda para o back office.
  const slugDeRegresso = me.account ? me.account.slug : null;

  if (rota.tipo === '404') {
    return <Screen404 onNavigate={navegar} slug={slugDeRegresso} />;
  }

  // Um utilizador não entra no slug de uma conta a que não chega. Para quase
  // toda a gente é só a sua; uma agência chega também aos seus anunciantes, e
  // é o servidor que diz quais em `me.contas` — o mesmo cálculo que o
  // `requireSlug` faz (lib/contas.js), para o ecrã e a API não discordarem.
  // A equipa NetScreen passa (impersonação) e a API valida na mesma.
  const contasAcessiveis = me.contas || (me.account ? [{ slug: me.account.slug, nome: me.account.nome, propria: true }] : []);
  if (
    rota.tipo === 'conta' &&
    me.user.tipo !== 'netscreen' &&
    !contasAcessiveis.some((c) => c.slug === rota.slug)
  ) {
    return <Screen404 onNavigate={navegar} slug={slugDeRegresso} />;
  }

  if (rota.tipo === 'admin' && me.user.tipo !== 'netscreen') {
    return <Screen404 onNavigate={navegar} slug={slugDeRegresso} />;
  }

  if (rota.tipo === 'conta' && !SECCOES_VALIDAS.includes(rota.seccao)) {
    return <Screen404 onNavigate={navegar} slug={slugDeRegresso} />;
  }

  let ecra;
  // Back office: /admin (rede), /admin/clientes[/novo|/:slug] e /admin/hardware.
  if (rota.tipo === 'admin' && rota.id === 'clientes' && rota.sub === 'novo') {
    ecra = <ScreenAdminClienteNovo onNavegar={navegar} />;
  } else if (rota.tipo === 'admin' && rota.id === 'clientes' && rota.sub) {
    ecra = <ScreenAdminMarca slug={rota.sub} me={me} onNavegar={navegar} onEntrarComo={pedirVerComo} />;
  } else if (rota.tipo === 'admin' && rota.id === 'clientes') {
    ecra = <ScreenAdminClientes onNavegar={navegar} onEntrarComo={pedirVerComo} />;
  } else if (rota.tipo === 'admin' && rota.id === 'dossie' && rota.sub) {
    ecra = <ScreenAdminDossie slug={rota.sub} onNavegar={navegar} />;
  } else if (rota.tipo === 'admin' && rota.id === 'hardware') {
    ecra = <ScreenAdminHardware me={me} />;
  } else if (rota.tipo === 'admin' && rota.id === 'planos') {
    ecra = <ScreenAdminPlanos me={me} />;
  } else if (rota.tipo === 'admin' && rota.id === 'equipa') {
    ecra = <ScreenAdminEquipa me={me} />;
  } else if (rota.tipo === 'admin' && rota.id === 'fila') {
    ecra = <ScreenAdminFila me={me} onNavegar={navegar} />;
  } else if (rota.tipo === 'admin' && rota.id === 'entregas') {
    ecra = <ScreenAdminEntregas onNavegar={navegar} />;
  } else if (rota.tipo === 'admin' && rota.id === 'auditoria') {
    ecra = <ScreenAdminAuditoria onNavegar={navegar} />;
  } else if (rota.tipo === 'admin' && !rota.id) {
    ecra = <ScreenAdminRede onNavegar={navegar} />;
  } else if (rota.seccao === 'dashboard') {
    // A agência vê no Início os seus clientes (ronda 13 dos virgens).
    ecra = <ScreenDashboard slug={rota.slug} podeMexer={podeMexerAqui(me)} onNavegar={navegar} criarActivo={!!me.criar_activo} clientesDaAgencia={(contasAcessiveis.find((c) => c.slug === rota.slug) || {}).propria ? contasAcessiveis.filter((c) => !c.propria) : []} />;
  } else if (rota.seccao === 'configuracao') {
    ecra = <ScreenConfiguracao slug={rota.slug} plano={((me.contas || []).find((c) => c.slug === rota.slug) || (me.account && me.account.slug === rota.slug ? me.account : {})).plano} />;
  } else if (rota.seccao === 'marca') {
    ecra = <ScreenMarca slug={rota.slug} separador={rota.id} podeMexer={podeMexerAqui(me)} onNavegar={navegar} criarActivo={!!me.criar_activo} marcaDeCliente={(() => { const c = contasAcessiveis.find((x) => x.slug === rota.slug); return c && c.propria === false ? c.nome : null; })()} />;
  } else if (rota.seccao === 'conhecimento') {
    // O Conhecimento passou a ser "A minha marca" (23 Set); os links antigos continuam a funcionar.
    ecra = <ScreenMarca slug={rota.slug} separador="fontes" podeMexer={podeMexerAqui(me)} onNavegar={navegar} criarActivo={!!me.criar_activo} />;
  } else if (rota.seccao === 'lojas') {
    ecra = <ScreenLojas slug={rota.slug} onNavegar={navegar} />;
  } else if (rota.seccao === 'campanhas') {
    ecra = <ScreenCampanhas podeMexer={podeMexerAqui(me)} slug={rota.slug} idAberta={rota.id} sub={rota.sub} onNavegar={navegar} criarActivo={!!me.criar_activo} />;
  } else if(rota.seccao==='criar'){
    ecra=<ScreenCriar key={rota.slug+':'+me.user.tipo+':'+me.user.id} slug={rota.slug} donoRascunho={me.user.tipo+':'+me.user.id} onNavegar={navegar} podeMexer={podeMexerAqui(me)} equipaAdmin={me.user.tipo==='netscreen'&&me.user.role==='admin'} />;
  } else if (rota.seccao === 'resultados') {
    ecra = <ScreenResultados slug={rota.slug} />;
  } else if (rota.seccao === 'paineis-pdv') {
    ecra = <ScreenPaineisPdv slug={rota.slug} onNavegar={navegar} />;
  } else {
    ecra = <ScreenPlaceholder seccao={rota.seccao} titulo={TITULOS[rota.seccao] || rota.seccao} />;
  }

  const cliente = pedidoVerComo && pedidoVerComo.cliente;

  return (
    <>
      <AppShell me={me} rota={rota} onNavigate={navegar} verComo={verComo} onSairDeVerComo={sairDeVerComo}>
        {ecra}
      </AppShell>

      <Modal
        aberto={!!pedidoVerComo}
        onFechar={cancelarVerComo}
        titulo="Ver como cliente"
        acoes={
          <>
            <button
              type="button"
              data-foco-inicial
              onClick={cancelarVerComo}
              disabled={!!(pedidoVerComo && pedidoVerComo.aRegistar)}
              className="border border-border px-4 py-2 text-sm uppercase tracking-wider text-muted-foreground outline-none hover:text-foreground focus-visible:ring-1 focus-visible:ring-accent disabled:opacity-40"
            >
              Cancelar
            </button>
            <button
              type="button"
              onClick={() => confirmarVerComo(cliente)}
              disabled={!cliente || pedidoVerComo.aRegistar}
              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 disabled:cursor-not-allowed disabled:opacity-40"
            >
              {pedidoVerComo && pedidoVerComo.aRegistar ? 'A entrar…' : 'Entrar como cliente'}
            </button>
          </>
        }
      >
        {cliente && (
          <>
            <p className="text-sm text-foreground">
              Vais ver a plataforma como <strong>{cliente.nome}</strong> a vê. Estás na área do cliente, não na tua.
            </p>
            <p className="mt-3 text-xs text-muted-foreground">
              A entrada e o que mudares lá dentro ficam registados com o teu nome e a hora. O cliente não é avisado.
            </p>
            {pedidoVerComo.erro && (
              <div
                className="mt-4 border border-[hsl(var(--offline))] border-l-2 bg-[hsl(var(--offline)/0.08)] p-3"
                role="alert"
              >
                <p className="text-xs text-foreground">{pedidoVerComo.erro} Não se entrou.</p>
              </div>
            )}
          </>
        )}
      </Modal>
    </>
  );
}

// Envolvido no <ErroFatal>: sem ele, um erro em qualquer componente desmonta a
// árvore toda e deixa a página em branco — sem mensagem e sem saída.
ReactDOM.createRoot(document.getElementById('root')).render(
  <ErroFatal>
    <App />
  </ErroFatal>
);
