/* ============================================================
   EDUCARE — Documentos do paciente

   O laudo do neuropediatra, o relatório da escola, o encaminhamento, a
   audiometria. Antes isso ficava fora do sistema — no e-mail ou numa
   pasta do computador — e quem precisava do papel meses depois, numa
   devolutiva ou numa reavaliação, não o achava junto da criança.

   O ARQUIVO vai para o bucket paciente-documentos; O QUE ELE É vai para
   a tabela patient_documents. A descrição é o que transforma um monte de
   PDF numa pasta utilizável: "Laudo neuro — Dr. X, mar/2026" diz o que
   "documento_3.pdf" nunca diria.

   Bucket privado: o acesso sai por URL assinada de validade curta,
   pedida com o JWT da própria conta. Nada aqui fica em endereço público.
   ============================================================ */
(function () {
  const { useState, useEffect, useRef } = React;
  const Icon = window.Icon;

  const BUCKET = "paciente-documentos";
  const TABELA = "patient_documents";
  const TETO_BYTES = 25 * 1024 * 1024;
  const VALIDADE_URL = 60; // segundos: tempo de abrir, não de compartilhar

  const TIPOS_ACEITOS = [
    "application/pdf",
    "image/jpeg", "image/png", "image/webp", "image/heic", "image/heif",
    "application/msword",
    "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  ];
  const ACCEPT = ".pdf,.jpg,.jpeg,.png,.webp,.heic,.heif,.doc,.docx";

  /* Alguns navegadores (iPad com HEIC, Windows com .doc) mandam o arquivo
     com type vazio, e ele era recusado (auditoria de 25/09/2026). Sem
     type, vale a extensão. */
  const TIPO_POR_EXTENSAO = {
    pdf: "application/pdf", jpg: "image/jpeg", jpeg: "image/jpeg", png: "image/png", webp: "image/webp",
    heic: "image/heic", heif: "image/heif", doc: "application/msword",
    docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  };
  function tipoDoArquivo(arquivo) {
    if (arquivo.type) return arquivo.type;
    const ext = String(arquivo.name || "").split(".").pop().toLowerCase();
    return TIPO_POR_EXTENSAO[ext] || "";
  }

  const sb = () => window.sb;

  function tamanhoLegivel(bytes) {
    if (!bytes && bytes !== 0) return "—";
    if (bytes < 1024) return bytes + " B";
    if (bytes < 1024 * 1024) return Math.round(bytes / 1024) + " KB";
    return (bytes / (1024 * 1024)).toFixed(1).replace(".", ",") + " MB";
  }

  // O conjunto de ícones do app só tem fileText e folderHeart — pedir um
  // nome inexistente renderiza vazio, e vale mais um ícone certo que um
  // ícone ausente por tipo de arquivo.
  const ICONE_DOC = "fileText";

  function dataLegivel(iso) {
    if (!iso) return "—";
    const d = String(iso).slice(0, 10);
    return window.fmtLongDate ? window.fmtLongDate(d) : d;
  }

  /* ---------------- acesso ao servidor ---------------- */

  async function donoAtual() {
    if (!sb()) return null;
    const { data } = await sb().auth.getSession();
    return (data && data.session && data.session.user && data.session.user.id) || null;
  }

  async function listar(patientId) {
    const { data, error } = await sb().from(TABELA)
      .select("id, file_name, mime_type, size_bytes, description, storage_path, created_at")
      .eq("patient_id", patientId)
      .order("created_at", { ascending: false });
    if (error) throw error;
    return data || [];
  }

  /* O arquivo sobe ANTES da linha de metadados. Se a ordem fosse a
     inversa, uma falha no upload deixaria no prontuário um documento que
     não existe — e clicar nele daria erro sem explicação. Na ordem
     correta, a falha do segundo passo deixa um arquivo órfão no bucket,
     que é invisível e inofensivo; e ainda assim o removemos. */
  async function enviar(patientId, arquivo, descricao) {
    const dono = await donoAtual();
    if (!dono) throw new Error("Sessão expirada — entre novamente.");
    if (arquivo.size > TETO_BYTES) throw new Error("O arquivo passa de 25 MB. Comprima ou divida antes de anexar.");
    const tipo = tipoDoArquivo(arquivo);
    if (TIPOS_ACEITOS.indexOf(tipo) === -1) {
      throw new Error("Tipo de arquivo não aceito. Use PDF, imagem (JPG/PNG) ou Word.");
    }

    const id = (window.EducareDB && window.EducareDB.novoId) ? window.EducareDB.novoId() : String(Date.now());
    const caminho = dono + "/" + patientId + "/" + id;

    // O supabase-js usa o type do próprio arquivo: sem ele, reembrulha com o tipo certo.
    const corpo = arquivo.type ? arquivo : new File([arquivo], arquivo.name, { type: tipo });
    const up = await sb().storage.from(BUCKET).upload(caminho, corpo, {
      contentType: tipo, upsert: false,
    });
    if (up.error) throw up.error;

    const { error } = await sb().from(TABELA).insert({
      id, owner_id: dono, patient_id: patientId, storage_path: caminho,
      file_name: arquivo.name, mime_type: tipo, size_bytes: arquivo.size,
      description: (descricao || "").trim() || null,
    });
    if (error) {
      try { await sb().storage.from(BUCKET).remove([caminho]); } catch (e) { /* órfão inofensivo */ }
      throw error;
    }
    return id;
  }

  // URL assinada: o bucket é privado, então não há link fixo a guardar.
  async function abrirUrl(storagePath) {
    const { data, error } = await sb().storage.from(BUCKET).createSignedUrl(storagePath, VALIDADE_URL);
    if (error || !data) throw (error || new Error("Não foi possível abrir o documento."));
    return data.signedUrl;
  }

  /* Arquivo primeiro, metadado depois — o inverso do envio. Apagar só a
     linha deixaria o arquivo no bucket ocupando espaço e fora de
     qualquer listagem, ou seja, impossível de remover pela tela. */
  async function apagar(doc) {
    // O erro do Storage era ignorado: a linha sumia e o arquivo ficava órfão (auditoria 25/09).
    const r = await sb().storage.from(BUCKET).remove([doc.storage_path]);
    if (r.error) throw r.error;
    const { error } = await sb().from(TABELA).delete().eq("id", doc.id);
    if (error) throw error;
  }

  async function renomear(id, descricao) {
    const { error } = await sb().from(TABELA).update({ description: (descricao || "").trim() || null }).eq("id", id);
    if (error) throw error;
  }

  window.EducareDocs = { listar, enviar, abrirUrl, apagar, renomear, TETO_BYTES, ACCEPT };

  /* ---------------- tela ---------------- */

  function DocumentosDoPaciente({ patientId }) {
    /* Modo leitura: anexar e renomear somem (o banco recusaria). Apagar e
       abrir continuam: tirar documento de saúde é direito, com ou sem
       assinatura. */
    const podeEscrever = window.usarAssinatura ? window.usarAssinatura().podeEscrever : true;
    const [itens, setItens] = useState(null); // null = carregando
    const [erro, setErro] = useState("");
    const [enviando, setEnviando] = useState(false);
    const [descricao, setDescricao] = useState("");
    const [editando, setEditando] = useState(null);
    const [textoEdicao, setTextoEdicao] = useState("");
    const inputRef = useRef(null);

    async function recarregar() {
      try { setItens(await listar(patientId)); setErro(""); }
      catch (e) { setItens([]); setErro("Não foi possível carregar os documentos: " + ((e && e.message) || "erro")); }
    }
    useEffect(() => { recarregar(); }, [patientId]);

    async function aoEscolher(e) {
      const arquivo = e.target.files && e.target.files[0];
      e.target.value = ""; // permite reenviar o mesmo arquivo depois
      if (!arquivo) return;
      setEnviando(true); setErro("");
      try {
        await enviar(patientId, arquivo, descricao);
        setDescricao("");
        await recarregar();
      } catch (err) {
        const tratado = window.EducareBilling && window.EducareBilling.traduzirErro(err);
        setErro((tratado && tratado.message) || (err && err.message) || "Não foi possível anexar o documento.");
      } finally { setEnviando(false); }
    }

    async function ver(doc) {
      /* A janela abre ANTES do await: depois dele o Safari/iPad já não
         considera o clique e bloqueia o pop-up (auditoria de 25/09/2026). */
      const janela = window.open("", "_blank");
      try {
        const url = await abrirUrl(doc.storage_path);
        if (janela) { janela.opener = null; janela.location.href = url; }
        else window.open(url, "_blank", "noopener");
      } catch (e) {
        if (janela) janela.close();
        setErro("Não foi possível abrir este documento.");
      }
    }

    async function remover(doc) {
      const nome = doc.description || doc.file_name;
      if (!window.confirm('Apagar "' + nome + '"?\n\nO arquivo sai do prontuário e não há como recuperar.')) return;
      try { await apagar(doc); await recarregar(); }
      catch (e) { setErro("Não foi possível apagar o documento."); }
    }

    async function salvarDescricao(doc) {
      try { await renomear(doc.id, textoEdicao); setEditando(null); await recarregar(); }
      catch (e) { setErro("Não foi possível salvar a descrição."); }
    }

    return (
      <>
        {podeEscrever && <div className="form-card">
          <div className="panel-head"><h3>Anexar documento</h3></div>
          <p className="help-text" style={{ marginTop: 0 }}>
            Laudos, relatórios da escola, encaminhamentos e exames. PDF, imagem ou Word, até 25 MB.
          </p>
          <div className="fld">
            <label>Descrição (opcional)</label>
            <input className="ctrl" value={descricao} onChange={(e) => setDescricao(e.target.value)}
              placeholder="Ex.: Laudo neuropediatra — Dr. Silva, mar/2026" disabled={enviando} />
          </div>
          <input ref={inputRef} type="file" accept={ACCEPT} onChange={aoEscolher} style={{ display: "none" }} />
          <button className="btn btn-primary btn-sm" disabled={enviando} onClick={() => inputRef.current && inputRef.current.click()}>
            <Icon name="plus" size={16} /> {enviando ? "Enviando…" : "Escolher arquivo"}
          </button>
          {erro && <p role="alert" style={{ color: "#DC2626", fontWeight: 700, fontSize: 13, marginTop: 10 }}>{erro}</p>}
        </div>}
        {!podeEscrever && erro && <p role="alert" style={{ color: "#DC2626", fontWeight: 700, fontSize: 13 }}>{erro}</p>}

        {itens === null ? (
          <p className="help-text">Carregando documentos…</p>
        ) : !itens.length ? (
          <div className="an-status todo" style={{ alignItems: "center" }}>
            <span className="ai"><Icon name="fileText" size={24} /></span>
            <div style={{ flex: 1 }}>
              <b>Nenhum documento anexado</b>
              <span>Guarde aqui os laudos e relatórios que você recebe sobre esta criança.</span>
            </div>
          </div>
        ) : (
          <div className="mstack">
            {itens.map((doc) => (
              <div className="mcard row" key={doc.id}>
                <span className="mi"><Icon name={ICONE_DOC} size={20} /></span>
                <div style={{ flex: 1, minWidth: 0 }}>
                  {editando === doc.id ? (
                    <div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
                      <input className="ctrl" style={{ flex: 1, minWidth: 180 }} value={textoEdicao}
                        onChange={(e) => setTextoEdicao(e.target.value)} placeholder="Descrição" />
                      <button className="btn btn-primary btn-xs" onClick={() => salvarDescricao(doc)}>Salvar</button>
                      <button className="btn btn-ghost btn-xs" onClick={() => setEditando(null)}>Cancelar</button>
                    </div>
                  ) : (
                    <>
                      <h4 style={{ overflow: "hidden", textOverflow: "ellipsis" }}>{doc.description || doc.file_name}</h4>
                      <p>{dataLegivel(doc.created_at)} · {tamanhoLegivel(doc.size_bytes)}{doc.description ? " · " + doc.file_name : ""}</p>
                    </>
                  )}
                </div>
                {editando !== doc.id && (
                  <>
                    <button className="btn btn-ghost btn-xs" onClick={() => ver(doc)}>Abrir</button>
                    {podeEscrever && <button className="btn btn-ghost btn-xs" onClick={() => { setEditando(doc.id); setTextoEdicao(doc.description || ""); }}>Renomear</button>}
                    <button className="btn btn-ghost btn-xs" style={{ color: "#DC2626" }} onClick={() => remover(doc)}>Apagar</button>
                  </>
                )}
              </div>
            ))}
          </div>
        )}
      </>
    );
  }

  window.DocumentosDoPaciente = DocumentosDoPaciente;
})();
