/**
 * MinutaIA Client — Comunicação direta com www.minutaia.com.br
 *
 * Porta do backend/minutaia/client.py para JavaScript puro.
 * Usa fetch() com credentials:"include" — funciona porque a extensão
 * declara host_permissions para minutaia.com.br (CORS bypass).
 *
 * Fluxo Auth.js v5:
 *   1. GET / → cookies base
 *   2. GET /api/auth/csrf → csrfToken
 *   3. POST /api/auth/callback/credentials → login
 *   4. GET /api/auth/session → verificar sessão
 */

const MINUTAIA_BASE = "https://www.minutaia.com.br";

/** @type {boolean} */
let _authenticated = false;

/** @type {object} */
let _userInfo = {};

/**
 * Opções padrão para todos os fetch ao MinutaIA.
 * credentials:"include" garante envio/recebimento de cookies Auth.js.
 */
function fetchOpts(extra = {}) {
  return {
    credentials: "include",
    headers: {
      "Accept-Language": "pt-BR,pt;q=0.9",
      ...(extra.headers || {}),
    },
    ...extra,
  };
}

// ── Autenticação ────────────────────────────────────────────────────────

/**
 * Autentica no MinutaIA via Auth.js v5 credentials provider.
 * @param {string} email
 * @param {string} password
 * @returns {Promise<boolean>}
 */
export async function login(email, password) {
  try {
    // 1. Visitar página inicial para cookies base
    await fetch(`${MINUTAIA_BASE}/`, fetchOpts());

    // 2. Obter CSRF token
    const csrfResp = await fetch(
      `${MINUTAIA_BASE}/api/auth/csrf`,
      fetchOpts()
    );
    if (!csrfResp.ok) {
      console.error("[minutaia] Falha ao obter CSRF:", csrfResp.status);
      return false;
    }
    const { csrfToken } = await csrfResp.json();
    if (!csrfToken) {
      console.error("[minutaia] CSRF token vazio");
      return false;
    }

    // 3. Login — callbackUrl sem www (conforme Auth.js v5)
    const loginResp = await fetch(
      `${MINUTAIA_BASE}/api/auth/callback/credentials`,
      fetchOpts({
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: new URLSearchParams({
          email,
          password,
          csrfToken,
          callbackUrl: "https://minutaia.com.br/",
          json: "true",
        }),
        redirect: "manual", // Não seguir redirects automaticamente
      })
    );

    // Auth.js pode retornar 302 (redirect) ou 200 (JSON com url)
    if (loginResp.type === "opaqueredirect" || loginResp.status === 302) {
      // Redirect — verificar sessão para confirmar
    } else if (loginResp.status === 200) {
      try {
        const body = await loginResp.json();
        const url = body.url || "";
        if (url.includes("/error") || url.includes("/login")) {
          console.error("[minutaia] Login falhou — redirect para:", url);
          return false;
        }
      } catch {
        // Body não é JSON — ok, verificar sessão
      }
    } else if (!loginResp.ok) {
      console.error("[minutaia] Login retornou status:", loginResp.status);
      return false;
    }

    // 4. Verificar sessão
    const session = await checkSession();
    _authenticated = session !== null;
    if (_authenticated) {
      _userInfo = session.user || {};
    }
    return _authenticated;
  } catch (e) {
    console.error("[minutaia] Erro no login:", e);
    _authenticated = false;
    return false;
  }
}

/**
 * Verifica se a sessão Auth.js está ativa.
 * @returns {Promise<object|null>}
 */
export async function checkSession() {
  try {
    const resp = await fetch(
      `${MINUTAIA_BASE}/api/auth/session`,
      fetchOpts()
    );
    if (!resp.ok) return null;
    const data = await resp.json();
    if (data && data.user) {
      _authenticated = true;
      _userInfo = data.user;
      return data;
    }
    return null;
  } catch {
    return null;
  }
}

export function isAuthenticated() {
  return _authenticated;
}

export function getUserInfo() {
  return _userInfo;
}

/**
 * Faz logout no MinutaIA removendo cookies de sessao e limpando estado.
 * Nao apaga credenciais do chrome.storage — chame storage.clearMinutaiaCredentials
 * para isso.
 */
export async function logout() {
  try {
    // Auth.js v5 signOut: POST /api/auth/signout com csrfToken
    const csrfResp = await fetch(`${MINUTAIA_BASE}/api/auth/csrf`, fetchOpts());
    let csrfToken = "";
    if (csrfResp.ok) {
      try { csrfToken = (await csrfResp.json()).csrfToken || ""; } catch {}
    }
    if (csrfToken) {
      await fetch(`${MINUTAIA_BASE}/api/auth/signout`, fetchOpts({
        method: "POST",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
        body: new URLSearchParams({ csrfToken, callbackUrl: "https://minutaia.com.br/" }),
        redirect: "manual",
      }));
    }
  } catch (e) {
    console.warn("[minutaia] Erro ao fazer logout:", e);
  } finally {
    _authenticated = false;
    _userInfo = {};
  }
}

// ── Geração SSE ─────────────────────────────────────────────────────────

/**
 * Inicia geração via POST /api/chat e retorna a Response com stream SSE.
 * O caller deve consumir o ReadableStream.
 *
 * @param {object} payload — Payload Vercel AI SDK (de minutaia-payload.js)
 * @returns {Promise<Response>}
 */
export async function generateStream(payload) {
  const resp = await fetch(`${MINUTAIA_BASE}/api/chat`, fetchOpts({
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify(payload),
  }));

  if (!resp.ok) {
    const text = await resp.text().catch(() => "");
    throw new Error(`MinutaIA geração falhou: HTTP ${resp.status} — ${text.slice(0, 200)}`);
  }

  return resp;
}

/**
 * Consome SSE stream do MinutaIA e emite eventos tipados via callback.
 *
 * Eventos emitidos:
 *   {type:"chat_created", chatId}
 *   {type:"thinking", text}
 *   {type:"text", content}       (quando fetch_document retorna conteúdo)
 *   {type:"done", documentId, documentTitle}
 *   {type:"error", message}
 *
 * @param {Response} response
 * @param {function} onEvent — callback(eventObj)
 */
export async function consumeSSEStream(response, onEvent) {
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = "";
  let documentId = "";
  let documentTitle = "";
  let prevThinkingLen = 0;
  const phaseStart = Date.now();

  try {
    while (true) {
      const { done, value } = await reader.read();
      if (done) break;

      buffer += decoder.decode(value, { stream: true });
      const lines = buffer.split("\n");
      buffer = lines.pop() || "";

      for (const rawLine of lines) {
        const line = rawLine.trim();
        if (!line) continue;

        let dataStr = "";
        if (line.startsWith("data: ")) dataStr = line.slice(6);
        else if (line.startsWith("data:")) dataStr = line.slice(5);
        else continue;

        if (!dataStr || dataStr === "[DONE]") continue;

        let event;
        try {
          event = JSON.parse(dataStr);
        } catch {
          continue;
        }

        const type = event.type || "";

        if (type === "data-chat-created") {
          const chatId = (event.data || {}).chatId || "";
          if (chatId) onEvent({ type: "chat_created", chatId });

        } else if (type === "data-thoughts") {
          const thinking = event.data || "";
          if (thinking) {
            const newText = thinking.slice(prevThinkingLen);
            prevThinkingLen = thinking.length;
            if (newText.trim()) {
              const elapsed = ((Date.now() - phaseStart) / 1000).toFixed(0);
              for (const ln of newText.split("\n")) {
                const clean = ln.trim().replace(/^#+\s*/, "").replace(/^\*+|\*+$/g, "").trim();
                if (clean) {
                  onEvent({ type: "thinking", text: `[${elapsed}s] ${clean}` });
                }
              }
            }
          }

        } else if (type === "data-tool-result" || type === "data-tool-call") {
          const data = event.data || {};
          const result = data.result || data.input || {};
          if (typeof result === "object" && result.id && !documentId) {
            documentId = result.id;
            documentTitle = result.title || "";
          }

        } else if (type === "tool-output-available") {
          const output = event.output || {};
          if (typeof output === "object" && output.id) {
            documentId = output.id;
            documentTitle = output.title || "";
          }

        } else if (type === "finish") {
          onEvent({ type: "done", documentId, documentTitle });

        } else if (type === "error") {
          const msg = event.message || event.error || JSON.stringify(event);
          onEvent({ type: "error", message: msg });
        }
      }
    }
  } catch (e) {
    onEvent({ type: "error", message: `Erro no stream: ${e.message}` });
  }
}

// ── APIs auxiliares ──────────────────────────────────────────────────────

/**
 * Busca documento gerado pelo ID.
 * @param {string} documentId
 * @returns {Promise<object>}
 */
export async function fetchDocument(documentId) {
  try {
    const resp = await fetch(
      `${MINUTAIA_BASE}/api/document?id=${encodeURIComponent(documentId)}`,
      fetchOpts()
    );
    if (!resp.ok) return {};
    const data = await resp.json();
    const docs = data.documents || [];
    return docs.length > 0 ? docs[0] : {};
  } catch (e) {
    console.error("[minutaia] Erro ao buscar documento:", e);
    return {};
  }
}

/**
 * Lista modelos de referência do usuário.
 * @returns {Promise<Array>}
 */
export async function getModels() {
  try {
    const resp = await fetch(
      `${MINUTAIA_BASE}/api/models?autoLoad=true`,
      fetchOpts()
    );
    if (!resp.ok) return [];
    return await resp.json();
  } catch {
    return [];
  }
}

/**
 * Lista perfis de geração.
 * @returns {Promise<Array>}
 */
export async function getProfiles() {
  try {
    const resp = await fetch(
      `${MINUTAIA_BASE}/api/profiles`,
      fetchOpts()
    );
    if (!resp.ok) return [];
    return await resp.json();
  } catch {
    return [];
  }
}

/**
 * Informações da assinatura do usuário.
 * @returns {Promise<object>}
 */
export async function getUserSubscription() {
  try {
    const resp = await fetch(
      `${MINUTAIA_BASE}/api/user/subscription`,
      fetchOpts()
    );
    if (!resp.ok) return {};
    return await resp.json();
  } catch {
    return {};
  }
}
