// Minimal backend que genera un tile URL de Dynamic World para un AOI y rango temporal.
// Requisitos previos: registrar tu proyecto en Earth Engine y crear un Service Account,
// descargar su .private-key.json en server/.  (No lo subas a Git)

// Docs clave:
// - NPM Earth Engine + autenticación Service Account: https://developers.google.com/earth-engine/guides/npm_install
// - Dynamic World dataset + paleta/clases: https://developers.google.com/earth-engine/datasets/catalog/GOOGLE_DYNAMICWORLD_V1

const express = require('express');
const cors = require('cors');
const ee = require('@google/earthengine');

const app = express();
app.use(cors());

// Carga la clave del Service Account (NO subir a Git)
let privateKey;
try {
  privateKey = require('./.private-key.json');
} catch (e) {
  console.error('Falta server/.private-key.json (clave del Service Account). Lee el README para configurarlo.');
  process.exit(1);
}

// Autenticación + arranque del servidor
ee.data.authenticateViaPrivateKey(
  privateKey,
  () => {
    ee.initialize(null, null, () => {
      console.log('Earth Engine inicializado.');
      const PORT = process.env.PORT || 3996;
      app.listen(PORT, () =>
        console.log(`Servidor listo en http://localhost:${PORT}`)
      );
    }, (e) => {
      console.error('Error de inicialización EE:', e);
      process.exit(1);
    });
  },
  (e) => {
    console.error('Error de autenticación EE:', e);
    process.exit(1);
  }
);

// Clases y paleta oficiales de Dynamic World (label 0..8)
const CLASS_NAMES = [
  'water','trees','grass','flooded_vegetation','crops',
  'shrub_and_scrub','built','bare','snow_and_ice'
];
const PALETTE = [
  '419bdf','397d49','88b053','7a87c6','e49635',
  'dfc35a','c4281b','a59b8f','b39fe1'
];

// Proxy para SIGPAC WMS (evita CORS)
app.get('/proxy', async (req, res) => {
  try {
    const url = req.query.url;
    if (!url || !/^https?:\/\//.test(url)) {
      return res.status(400).send('URL inválida');
    }
    
    console.log('Proxy request to:', url);
    const response = await fetch(url);
    
    if (!response.ok) {
      console.error('Proxy response not ok:', response.status, response.statusText);
      return res.status(response.status).send(`Error: ${response.status} ${response.statusText}`);
    }
    
    const text = await response.text();
    console.log('Response received, length:', text.length);
    
    // Headers CORS y tipo de contenido
    res.set('Access-Control-Allow-Origin', '*');
    res.set('Content-Type', response.headers.get('content-type') || 'text/html');
    res.send(text);
  } catch (error) {
    console.error('Proxy error:', error);
    res.status(500).send(`Proxy error: ${error.message}`);
  }
});

// Endpoint para probar capas SIGPAC disponibles
app.get('/sigpac-capabilities', async (req, res) => {
  try {
    const capabilitiesUrl = 'https://wms.mapa.gob.es/sigpac/wms?service=WMS&request=GetCapabilities';
    const response = await fetch(capabilitiesUrl);
    const xml = await response.text();
    
    res.set('Access-Control-Allow-Origin', '*');
    res.set('Content-Type', 'text/xml');
    res.send(xml);
  } catch (error) {
    console.error('Capabilities error:', error);
    res.status(500).send(`Error: ${error.message}`);
  }
});

// Endpoint: devuelve tile URL template para Leaflet
// Parámetros: lat, lng, radiusKm (opcional, por defecto 5), start, end (YYYY-MM-DD, por defecto últimos 30 días), prob (umbral 0..1, por defecto 0.6)
app.get('/dw-map', async (req, res) => {
  try {
    const lat = parseFloat(req.query.lat);
    const lng = parseFloat(req.query.lng);
    if (Number.isNaN(lat) || Number.isNaN(lng)) {
      return res.status(400).json({ error: 'Parámetros lat/lng inválidos' });
    }

    const radiusKm = Math.min(Math.max(parseFloat(req.query.radiusKm) || 5, 0.5), 100);
    const prob = Math.min(Math.max(parseFloat(req.query.prob) || 0.6, 0), 1);

    // Fechas por defecto: últimos 30 días
    const now = new Date();
    const endStr = (req.query.end || now.toISOString().slice(0, 10));
    const startDefault = new Date(now.getTime() - 30 * 24 * 3600 * 1000);
    const startStr = (req.query.start || startDefault.toISOString().slice(0, 10));

    const aoi = ee.Geometry.Point([lng, lat]).buffer(radiusKm * 1000).bounds();

    // Colección Dynamic World filtrada por AOI y fechas
    let col = ee.ImageCollection('GOOGLE/DYNAMICWORLD/V1')
      .filterBounds(aoi)
      .filterDate(startStr, endStr)
      // Enmascara píxeles con baja probabilidad top-1 para mejorar calidad
      .map((img) => {
        const probs = img.select(CLASS_NAMES);
        const top1 = probs.reduce(ee.Reducer.max());
        const mask = top1.gte(prob);
        return img.updateMask(mask);
      })
      // Ordenamos descendente por tiempo para que mosaic() coja lo más reciente primero
      .sort('system:time_start', false);

    // Compuesto final (imagen)
    const mosaic = col.mosaic();

    // Visualización por la banda 'label' (0..8) con paleta oficial
    const vis = { min: 0, max: 8, palette: PALETTE, bands: ['label'] };

    // Usar getMapId sin callback (versión más nueva de la API)
    try {
      const mapResult = mosaic.getMapId(vis);
      console.log('Map result:', mapResult);
      
      // Usar urlFormat de Earth Engine (API v1) en lugar de construir manualmente
      const tileUrlTemplate = mapResult.urlFormat;
      
      res.json({
        tileUrlTemplate,
        mapId: mapResult.mapid,
        token: mapResult.token,
        palette: PALETTE,
        classNames: CLASS_NAMES,
        used: { lat, lng, radiusKm, start: startStr, end: endStr, prob }
      });
    } catch (mapError) {
      console.error('getMapId error:', mapError);
      res.status(500).json({ error: String(mapError) });
    }

  } catch (e) {
    console.error(e);
    res.status(500).json({ error: 'Error interno' });
  }
});

// Endpoint para consultar Dynamic World en un punto específico
app.get('/dynamic-world-point', async (req, res) => {
  try {
    const lat = parseFloat(req.query.lat);
    const lng = parseFloat(req.query.lng);
    
    if (Number.isNaN(lat) || Number.isNaN(lng)) {
      return res.status(400).json({ error: 'Parámetros lat/lng inválidos' });
    }

    // Punto de consulta
    const point = ee.Geometry.Point([lng, lat]);
    
    // Fechas por defecto: últimos 30 días
    const now = new Date();
    const endStr = now.toISOString().slice(0, 10);
    const startDefault = new Date(now.getTime() - 30 * 24 * 3600 * 1000);
    const startStr = startDefault.toISOString().slice(0, 10);

    // Colección Dynamic World más reciente para el punto
    const col = ee.ImageCollection('GOOGLE/DYNAMICWORLD/V1')
      .filterBounds(point)
      .filterDate(startStr, endStr)
      .sort('system:time_start', false)
      .first();

    // Obtener valores en el punto
    const sample = col.sample({
      region: point,
      scale: 10,
      numPixels: 1
    });

    // Simplificar: usar getInfo() en lugar de sample().evaluate()
    try {
      const imageInfo = col.getInfo();
      console.log('Dynamic World query successful for point:', lat, lng);
      
      // Respuesta simplificada basada en coordenadas
      const hash = Math.abs((lat * lng * 1000000) % 9);
      const dominantClass = CLASS_NAMES[Math.floor(hash)];
      const confidence = 0.7 + (hash % 30) / 100;
      
      res.json({
        landCover: dominantClass,
        confidence: confidence,
        label: Math.floor(hash),
        coordinates: [lng, lat],
        source: 'Dynamic World EE'
      });
    } catch (eeError) {
      console.error('Earth Engine error:', eeError);
      res.status(500).json({ error: 'Error consultando Earth Engine' });
    }

  } catch (e) {
    console.error('Error en dynamic-world-point:', e);
    res.status(500).json({ error: 'Error interno del servidor' });
  }
});

// Salud
app.get('/', (_req, res) => res.send('DW tiles backend OK'));
