/* ============================================================
   EDUCARE — Exportar os dados da conta

   Isto é requisito legal, não conveniência: o titular do dado tem
   direito de acesso e de portabilidade (LGPD, art. 18), e a
   profissional tem dever de guarda do prontuário perante o conselho de
   classe dela. Por isso a exportação NÃO pergunta pela assinatura em
   ponto nenhum: conta em modo leitura exporta igual, e é justamente
   quem mais precisa. Do lado do banco isso já está garantido, porque
   exportar é SELECT e nenhuma policy de leitura fala de cobrança.

   Lê do servidor na hora, e não do que está em memória: a carga do
   boot traz o que as telas precisam, não necessariamente tudo, e uma
   exportação incompleta que se apresenta como completa é pior do que
   exportação nenhuma.

   Dois formatos, porque servem a coisas diferentes:
     JSON  um arquivo, tudo, estrutura preservada. É o que serve para
           levar os dados para outro sistema.
     CSV   um arquivo por tabela, para abrir no Excel e ler.

   Se qualquer tabela falhar, a exportação inteira falha com o nome da
   tabela. Baixar meio prontuário achando que baixou o prontuário
   inteiro é exatamente o erro que não pode acontecer aqui.
   ============================================================ */
(function () {
  const { useState } = React;
  const Icon = window.Icon;

  /* Mesma lista que app/db.jsx carrega, mais o cadastro da conta. A
     ordem é a de leitura humana: quem exporta abre "pacientes"
     primeiro. */
  const TABELAS = [
    ["pacientes",     "patients"],
    ["atendimentos",  "sessions"],
    ["avaliacoes",    "assessments"],
    ["planejamentos", "plans"],
    ["agenda",        "appointments"],
    ["recebimentos",  "payments"],
    ["despesas",      "expenses"],
    ["cobrancas",     "charges"],
    ["profissionais", "professionals"],
    /* Ficavam de fora, com a tela dizendo "tudo o que está registrado"
       (auditoria de 25/09/2026): a lista dos documentos do paciente (os
       arquivos em si seguem no Storage) e os rascunhos/perfil. */
    ["documentos",    "patient_documents"],
    ["rascunhos",     "user_state", "key"],
  ];

  /* Da assinatura sai só o que descreve a conta. Identificador de
     gateway é chave de sistema de terceiro: não é dado da cliente e
     não tem por que circular num arquivo que ela vai guardar ou
     enviar por e-mail. */
  const CAMPOS_DA_ASSINATURA = [
    "plan_id", "status", "billing_cycle", "trial_started_at", "trial_ends_at",
    "current_period_start", "current_period_end", "cancel_at_period_end", "created_at",
  ];

  /* ---------------- coleta ---------------- */

  async function coletar() {
    if (!window.sb) throw new Error("Sem conexão com o servidor.");

    const { data: sessao } = await window.sb.auth.getSession();
    const conta = sessao && sessao.session ? sessao.session.user : null;
    if (!conta) throw new Error("Sessão expirada. Entre novamente para exportar.");

    /* Paginado: o servidor devolve no máximo 1000 linhas por consulta,
       sem erro — a exportação saía cortada em silêncio. */
    const respostas = await Promise.all(
      TABELAS.map(([, tabela, ordem]) => window.EducareDB.buscarTudo(tabela, ordem || "id")));

    const falhou = respostas.findIndex((r) => r.error);
    if (falhou >= 0) {
      throw new Error(
        `Não foi possível exportar "${TABELAS[falhou][0]}": ${respostas[falhou].error.message}`);
    }

    const dados = {};
    TABELAS.forEach(([nome], i) => { dados[nome] = respostas[i].data || []; });

    /* O erro destas duas era ignorado e a exportação saía com
       "perfil: null" como se não houvesse perfil (auditoria 25/09/2026). */
    const { data: perfil, error: erroPerfil } = await window.sb
      .from("profiles").select("*").eq("id", conta.id).maybeSingle();
    if (erroPerfil) throw new Error(`Não foi possível exportar "perfil": ${erroPerfil.message}`);

    const { data: assinatura, error: erroAssinatura } = await window.sb
      .from("subscriptions").select(CAMPOS_DA_ASSINATURA.join(",")).eq("owner_id", conta.id).maybeSingle(); // admin enxerga todas: sem o filtro, maybeSingle falhava
    if (erroAssinatura) throw new Error(`Não foi possível exportar "assinatura": ${erroAssinatura.message}`);

    return {
      exportado_em: new Date().toISOString(),
      conta: { id: conta.id, email: conta.email || "", perfil: perfil || null },
      assinatura: assinatura || null,
      ...dados,
    };
  }

  /* ---------------- CSV ----------------
     Separador ponto e vírgula e BOM no começo porque o destino real
     deste arquivo é o Excel em português, que com vírgula joga a linha
     inteira numa célula só e sem BOM come os acentos. Fim de linha
     CRLF pelo mesmo motivo. */

  function celula(valor) {
    if (valor == null) return "";
    const texto = typeof valor === "object" ? JSON.stringify(valor) : String(valor);
    /* Campo entre aspas e aspas dobradas: é o escape do CSV. Sem isso,
       uma observação clínica com ponto e vírgula parte a planilha em
       colunas que não existem, e o dado sai errado sem avisar. */
    return /[";\r\n]/.test(texto) ? `"${texto.replace(/"/g, '""')}"` : texto;
  }

  /* Colunas: as da primeira linha e, depois, qualquer coluna que só
     apareça mais adiante. Linha com campo faltando vira campo vazio,
     nunca coluna deslocada. */
  function colunasDe(linhas) {
    const vistas = [];
    (linhas || []).forEach((linha) => {
      Object.keys(linha || {}).forEach((k) => { if (!vistas.includes(k)) vistas.push(k); });
    });
    return vistas;
  }

  function paraCSV(linhas) {
    const lista = linhas || [];
    if (!lista.length) return "";
    const colunas = colunasDe(lista);
    const cabecalho = colunas.map(celula).join(";");
    const corpo = lista.map((l) => colunas.map((c) => celula(l ? l[c] : null)).join(";"));
    return [cabecalho, ...corpo].join("\r\n");
  }

  /* ---------------- download ---------------- */

  function baixar(nome, conteudo, tipo) {
    const blob = new Blob([conteudo], { type: tipo });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = nome;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    /* Revogar na hora corta o download em alguns navegadores. */
    setTimeout(() => URL.revokeObjectURL(url), 30000);
  }

  const carimbo = () => new Date().toISOString().slice(0, 10);

  async function exportarJSON() {
    const dados = await coletar();
    baixar(`educare-dados-${carimbo()}.json`,
      JSON.stringify(dados, null, 2), "application/json;charset=utf-8");
    return dados;
  }

  async function exportarCSV() {
    const dados = await coletar();
    const arquivos = [];

    TABELAS.forEach(([nome]) => {
      const csv = paraCSV(dados[nome]);
      if (csv) arquivos.push([`educare-${nome}-${carimbo()}.csv`, csv]);
    });

    if (!arquivos.length) throw new Error("Não há nada registrado nesta conta para exportar.");

    /* Um arquivo por tabela, com respiro entre eles: navegador trata
       vários downloads seguidos como popup e engole os últimos. */
    for (let i = 0; i < arquivos.length; i++) {
      const [nome, csv] = arquivos[i];
      baixar(nome, "﻿" + csv, "text/csv;charset=utf-8");
      if (i < arquivos.length - 1) await new Promise((ok) => setTimeout(ok, 350));
    }
    return arquivos.map(([nome]) => nome);
  }

  /* ---------------- interface ---------------- */

  function ModalExportar({ onClose }) {
    const [ocupado, setOcupado] = useState("");
    const [erro, setErro] = useState("");
    const [pronto, setPronto] = useState("");

    async function rodar(formato) {
      setErro(""); setPronto(""); setOcupado(formato);
      try {
        if (formato === "json") {
          await exportarJSON();
          setPronto("Arquivo JSON gerado. Confira a pasta de downloads.");
        } else {
          const nomes = await exportarCSV();
          setPronto(`${nomes.length} arquivos CSV gerados, um por tipo de registro.`);
        }
      } catch (e) {
        console.error("[EducareExportar]", e);
        setErro((e && e.message) || "Não foi possível exportar agora.");
      } finally {
        setOcupado("");
      }
    }

    return (
      <div className="modal-scrim" onClick={onClose}>
        <div className="modal" onClick={(e) => e.stopPropagation()} style={{ maxWidth: 520 }}>
          <div className="modal-head">
            <div>
              <h3>Exportar meus dados</h3>
              <p>Tudo o que está registrado nesta conta, para você guardar ou levar.</p>
            </div>
            <button className="x" onClick={onClose} aria-label="Fechar"><Icon name="x" size={18} /></button>
          </div>
          <div className="modal-body">
            <button className="cta-secondary" disabled={!!ocupado} onClick={() => rodar("json")}>
              <span className="ci"><Icon name="download" size={22} /></span>
              <span className="ct">
                <b>{ocupado === "json" ? "Preparando…" : "Arquivo único (JSON)"}</b>
                <span>Um arquivo com tudo, para levar os dados para outro sistema.</span>
              </span>
            </button>
            <button className="cta-secondary" disabled={!!ocupado} onClick={() => rodar("csv")} style={{ marginTop: 10 }}>
              <span className="ci"><Icon name="download" size={22} /></span>
              <span className="ct">
                <b>{ocupado === "csv" ? "Preparando…" : "Planilhas (CSV)"}</b>
                <span>Um arquivo por tipo de registro, pronto para abrir no Excel.</span>
              </span>
            </button>

            {pronto && (
              <p style={{ marginTop: 12, fontSize: 13, fontWeight: 700, color: "var(--primary)" }}>{pronto}</p>
            )}
            {erro && (
              <p className="form-err" role="alert" style={{ marginTop: 12, color: "#EF4444", fontWeight: 700, fontSize: 13 }}>{erro}</p>
            )}

            <p style={{ marginTop: 14, fontSize: 12.5, color: "var(--text-3)", lineHeight: 1.55 }}>
              O arquivo tem dado de saúde de paciente. Guarde com o mesmo cuidado que você
              guarda o prontuário em papel.
            </p>
          </div>
        </div>
      </div>
    );
  }

  /* Botão pronto para as telas. A faixa de modo leitura e a aba
     Assinatura usam o mesmo, para não existirem duas exportações que
     um dia divergem. */
  function BotaoExportar({ className, rotulo }) {
    const [aberto, setAberto] = useState(false);
    return (
      <>
        <button className={className || "btn btn-ghost btn-sm"} onClick={() => setAberto(true)}>
          <Icon name="download" size={16} /> {rotulo || "Exportar meus dados"}
        </button>
        {aberto && <ModalExportar onClose={() => setAberto(false)} />}
      </>
    );
  }

  window.EducareExportar = {
    coletar, paraCSV, celula, colunasDe, exportarJSON, exportarCSV, TABELAS,
  };
  window.BotaoExportar = BotaoExportar;
})();
