// api-lavid.jsx — Cliente REAL del Estudio La Vid (backend FastAPI en aistudio).
//
// Contrato (backend: .gtm/carrusel-en-vivo en el servidor aistudio):
//   GET  /api/lavid/composers        catálogo ADORNADO: diseños, plantillas, ambientes
//   GET  /api/lavid/celulas          células reales (selector)
//   POST /api/lavid/componer         {tipo, datos, fondo?, con_a4} → trabajo_id
//   POST /api/lavid/fondo/generar    {clave, prompt|ambiente, seed} → trabajo_id
//   POST /api/lavid/fondo/subir      {clave, imagen_b64} → fondo efímero (TTL 2 h)
//   POST /api/lavid/prompt/redactar  {idea, tipo?} → prompt Qwen vía claude -p
//   GET  /api/trabajo/{id}           estado + imagen base64 cuando 'listo'
//   GET  /api/gpu/estado · POST /api/gpu/liberar · POST /api/gpu/arrancar
//
// REGLA DURA del proyecto: el servidor NO guarda ninguna generación. Lo que
// vuelve por /api/trabajo se persiste AQUÍ, en el dispositivo (IndexedDB);
// si no se guarda, se pierde para siempre.

const ESTUDIO_API_BASE = (() => {
  const h = location.hostname;
  // Desarrollo local: el backend corre en el propio Mac (launchd com.lavid.api).
  // Producción (Cloudflare Pages): por el túnel que también corre en el Mac.
  if (h === 'localhost' || h === '127.0.0.1') return 'http://127.0.0.1:8190';
  return 'https://api-lavid.lexusfx.com';
})();

// ─── Sesión: token en localStorage, enviado en cada petición ─────────────────
const TOKEN_KEY = 'lavid:token';
const _sesion = {
  get: () => { try { return localStorage.getItem(TOKEN_KEY); } catch { return null; } },
  set: (t) => { try { localStorage.setItem(TOKEN_KEY, t); } catch {} },
  limpiar: () => { try { localStorage.removeItem(TOKEN_KEY); } catch {} },
};

// Callback que el shell registra para reaccionar a una sesión caducada (401).
let _onSesionExpira = null;

async function _peticion(ruta, opciones = {}) {
  const token = _sesion.get();
  const cabeceras = { 'Content-Type': 'application/json', ...(opciones.headers || {}) };
  if (token) cabeceras['Authorization'] = 'Bearer ' + token;
  const res = await fetch(ESTUDIO_API_BASE + ruta, { ...opciones, headers: cabeceras });
  const datos = await res.json().catch(() => ({}));
  if (res.status === 401 && ruta !== '/api/auth/login') {
    _sesion.limpiar();
    if (_onSesionExpira) _onSesionExpira();
    throw new Error(datos.error || 'Sesión caducada. Entra de nuevo.');
  }
  if (!res.ok) throw new Error(datos.error || `Error ${res.status} del estudio.`);
  if (datos.error) throw new Error(datos.error);
  return datos;
}

const estudioAPI = {
  base: ESTUDIO_API_BASE,

  // ── Sesión / usuarios ──────────────────────────────────────────────────────
  login: async (usuario, clave) => {
    const d = await _peticion('/api/auth/login', {
      method: 'POST', body: JSON.stringify({ usuario, clave }),
    });
    _sesion.set(d.token);
    return d;   // {token, usuario, rol}
  },
  logout: () => _sesion.limpiar(),
  haySesion: () => !!_sesion.get(),
  yo: () => _peticion('/api/auth/yo'),
  alExpirarSesion: (cb) => { _onSesionExpira = cb; },
  // Gestión de usuarios (solo dueño)
  usuarios: () => _peticion('/api/auth/usuarios'),
  guardarUsuario: (usuario, clave, rol = 'editor') => _peticion('/api/auth/usuarios', {
    method: 'POST', body: JSON.stringify({ usuario, clave, rol }),
  }),
  borrarUsuario: (usuario) => _peticion(`/api/auth/usuarios/${usuario}`, { method: 'DELETE' }),

  composers: () => _peticion('/api/lavid/composers'),
  celulas:   () => _peticion('/api/lavid/celulas'),

  // A4 desactivado: el usuario solo usa el PNG (Instagram/stories). El backend
  // sigue pudiendo generar A4 si algún día se pide (con_a4:true), pero por
  // defecto NO, para ahorrar trabajo y peso en la galería.
  componer: (tipo, datos, fondo = null, conA4 = false) =>
    _peticion('/api/lavid/componer', {
      method: 'POST',
      body: JSON.stringify({ tipo, datos, fondo, con_a4: conA4 }),
    }),

  generarFondo: ({ clave, prompt = null, ambiente = null, seed = 42 }) =>
    _peticion('/api/lavid/fondo/generar', {
      method: 'POST',
      body: JSON.stringify({ clave, prompt, ambiente, seed }),
    }),

  subirFoto: (clave, imagenB64) =>
    _peticion('/api/lavid/fondo/subir', {
      method: 'POST',
      body: JSON.stringify({ clave, imagen_b64: imagenB64 }),
    }),

  redactarPrompt: (idea, tipo = null) =>
    _peticion('/api/lavid/prompt/redactar', {
      method: 'POST',
      body: JSON.stringify({ idea, tipo }),
    }),

  trabajo: (id) => _peticion(`/api/trabajo/${id}`),

  // Polling hasta 'listo'/'error'. `alCambiar(estado)` informa a la UI.
  // La generación de un fondo Qwen a 50 steps puede tardar 1-2 min (y más si
  // ComfyUI arranca en frío tras la liberación de VRAM) → margen de 6 min.
  esperarTrabajo: async (id, alCambiar = null, maxMs = 6 * 60 * 1000) => {
    const t0 = Date.now();
    let ultimo = '';
    while (Date.now() - t0 < maxMs) {
      const d = await estudioAPI.trabajo(id);
      if (d.estado !== ultimo) { ultimo = d.estado; alCambiar && alCambiar(d.estado); }
      if (d.estado === 'listo') return d;
      if (d.estado === 'error') throw new Error(d.error || 'El trabajo falló.');
      await new Promise(r => setTimeout(r, 1600));
    }
    throw new Error('El trabajo tardó demasiado. Reintenta.');
  },

  // ── Catálogo dinámico (mini-SaaS): células y ambientes administrables ──────
  guardarCelula: (c) => _peticion('/api/lavid/celulas', {
    method: 'POST', body: JSON.stringify(c),
  }),
  borrarCelula: (clave) => _peticion(`/api/lavid/celulas/${clave}`, { method: 'DELETE' }),
  ambientes: () => _peticion('/api/lavid/ambientes'),
  guardarAmbiente: (a) => _peticion('/api/lavid/ambientes', {
    method: 'POST', body: JSON.stringify(a),
  }),
  borrarAmbiente: (clave) => _peticion(`/api/lavid/ambientes/${clave}`, { method: 'DELETE' }),

  // ── Editor de imagen (pipeline de pasos estilo n8n, Pillow en backend) ─────
  operacionesImagen: () => _peticion('/api/imagen/operaciones'),
  presetsImagen: () => _peticion('/api/imagen/presets'),
  editarImagen: ({ fuente, pasos, salida }) => _peticion('/api/imagen/editar', {
    method: 'POST',
    body: JSON.stringify({ fuente, pasos, salida: salida || { formato: 'png' } }),
  }),

  gpuEstado:  () => _peticion('/api/gpu/estado'),
  gpuLiberar: (dura = true) => _peticion('/api/gpu/liberar', {
    method: 'POST', body: JSON.stringify({ dura }),
  }),
};

// ─── Galería en Postgres (vía API) — la ÚNICA persistencia de las piezas ─────
// Decisión 2026-06-10: la galería vive en el Postgres local del Mac. El muro
// carga MINIATURAS (ligeras); la imagen completa se pide solo al abrir/descargar.
const galeriaDB = {
  // pieza: {id, tipo, titulo, subtitulo, imagen(dataURL), a4(dataURL|null)}
  guardar: (pieza) => _peticion('/api/galeria', {
    method: 'POST',
    body: JSON.stringify({
      id: pieza.id, tipo: pieza.tipo, titulo: pieza.titulo,
      subtitulo: pieza.subtitulo || '', imagen: pieza.imagen, a4: pieza.a4 || null,
    }),
  }),
  // En el muro, `imagen` es la miniatura (el visor pide la completa aparte).
  listar: async () => {
    const d = await _peticion('/api/galeria');
    return (d.piezas || []).map(p => ({ ...p, imagen: p.miniatura }));
  },
  obtener: (id) => _peticion(`/api/galeria/${id}`),
  borrar: (id) => _peticion(`/api/galeria/${id}`, { method: 'DELETE' }),
};

// Descarga un data-URL al dispositivo (la pieza es del usuario, no del servidor).
function descargarDataURL(dataURL, nombre) {
  const a = document.createElement('a');
  a.href = dataURL;
  a.download = nombre;
  document.body.appendChild(a);
  a.click();
  a.remove();
}

Object.assign(window, { estudioAPI, galeriaDB, descargarDataURL });
