const express  = require('express');
const bcrypt   = require('bcryptjs');
const jwt      = require('jsonwebtoken');
const pool     = require('../config/db');
const { geocodificar, buscarColonia } = require('../services/geocoding.service');

const router = express.Router();
const SECRET  = process.env.JWT_SECRET     || 'hackathon_celaya_2026_secret_key';
const EXPIRA  = process.env.JWT_EXPIRES_IN || '7d';

// ================================================================
//  POST /auth/registro
//  Body: { email?, phone?, password, alias, direccion_texto }
//
//  Flujo:
//  1. Valida campos
//  2. Hashea contraseña
//  3. Crea usuario en BD
//  4. Geocodifica domicilio con Nominatim
//  5. Busca colonia → obtiene routeId
//  6. Crea domicilio en BD
//  7. Genera JWT con routeId embebido
//  8. Retorna token + info básica
// ================================================================
router.post('/registro', async (req, res) => {
  const { email, phone, password, alias = 'Casa', direccion_texto } = req.body;

  // ── Validaciones básicas ───────────────────────────────────────
  if (!password)         return res.status(400).json({ error: 'La contraseña es requerida' });
  if (!email && !phone)  return res.status(400).json({ error: 'Email o teléfono es requerido' });
  if (!direccion_texto)  return res.status(400).json({ error: 'La dirección es requerida' });
  if (password.length < 6) return res.status(400).json({ error: 'La contraseña debe tener al menos 6 caracteres' });

  const client = await pool.connect();

  try {
    await client.query('BEGIN');

    // ── Hash de contraseña ─────────────────────────────────────
    const passwordHash = await bcrypt.hash(password, 10);

    // ── Crear usuario ──────────────────────────────────────────
    const { rows: [usuario] } = await client.query(
      `INSERT INTO users (email, phone, password_hash)
       VALUES ($1, $2, $3)
       RETURNING id, email, phone, rol`,
      [email || null, phone || null, passwordHash]
    );

    // ── Geocodificar domicilio ─────────────────────────────────
    let lat = null, lng = null, coloniaId = null, routeId = null, domicilioId = null;
    let validado = false;

    try {
      const geo = await geocodificar(direccion_texto);

      if (geo) {
        lat = geo.lat;
        lng = geo.lng;

        const colonia = await buscarColonia(geo.coloniaNombre);
        if (colonia) {
          coloniaId = colonia.coloniaId;
          routeId   = colonia.routeId;
          validado  = true;
        }
      }
    } catch (geoErr) {
      // Si Nominatim falla, seguimos sin coordenadas — no bloqueamos el registro
      console.warn('⚠️  Geocoding falló:', geoErr.message);
    }

    // ── Crear domicilio ────────────────────────────────────────
    // Solo si tenemos coordenadas; si no, guardamos con valores nulos
    if (lat !== null && lng !== null) {
      const wkt = `SRID=4326;POINT(${lng} ${lat})`;
      const { rows: [dom] } = await client.query(
        `INSERT INTO domicilios
             (user_id, alias, direccion_texto, lat, lng, coordenada, colonia_id, validado)
         VALUES ($1, $2, $3, $4, $5, $6::geography, $7, $8)
         RETURNING id`,
        [usuario.id, alias, direccion_texto, lat, lng, wkt, coloniaId, validado]
      );
      domicilioId = dom.id;
    } else {
      // Sin coordenadas: guardamos el domicilio sin punto geoespacial
      // (se puede validar después desde el panel admin)
      const { rows: [dom] } = await client.query(
        `INSERT INTO domicilios
             (user_id, alias, direccion_texto, lat, lng, coordenada, colonia_id, validado)
         VALUES ($1, $2, $3, 0, 0, ST_GeogFromText('SRID=4326;POINT(0 0)'), $4, false)
         RETURNING id`,
        [usuario.id, alias, direccion_texto, coloniaId]
      );
      domicilioId = dom.id;
    }

    await client.query('COMMIT');

    // ── Generar JWT con routeId embebido ───────────────────────
    const token = jwt.sign(
      {
        sub:         usuario.id,
        userId:      usuario.id,
        routeId,          // "RUTA-01" o null si no se validó
        rol:         usuario.rol,
        domicilioId,
      },
      SECRET,
      { expiresIn: EXPIRA }
    );

    return res.status(201).json({
      message: validado
        ? '✅ Usuario registrado y domicilio validado'
        : '⚠️ Usuario registrado. Domicilio pendiente de validación',
      token,
      usuario: {
        id:    usuario.id,
        email: usuario.email,
        phone: usuario.phone,
        rol:   usuario.rol,
      },
      domicilio: {
        id:        domicilioId,
        alias,
        validado,
        routeId,
      },
    });

  } catch (err) {
    await client.query('ROLLBACK');

    // Error de duplicado (email o teléfono ya existe)
    if (err.code === '23505') {
      return res.status(409).json({ error: 'El email o teléfono ya está registrado' });
    }

    console.error('❌ Error en registro:', err.message);
    return res.status(500).json({ error: 'Error interno del servidor' });

  } finally {
    client.release();
  }
});

// ================================================================
//  POST /auth/login
//  Body: { email?, phone?, password }
//
//  Flujo:
//  1. Busca usuario por email o teléfono
//  2. Compara contraseña con bcrypt
//  3. Obtiene su domicilio principal → colonia → routeId
//  4. Genera JWT con routeId embebido
//  5. Retorna token
// ================================================================
router.post('/login', async (req, res) => {
  const { email, phone, password } = req.body;

  if (!password)        return res.status(400).json({ error: 'Contraseña requerida' });
  if (!email && !phone) return res.status(400).json({ error: 'Email o teléfono requerido' });

  try {
    // ── Buscar usuario ─────────────────────────────────────────
    const { rows } = await pool.query(
      `SELECT id, email, phone, password_hash, rol, activo
       FROM users
       WHERE ($1::text IS NOT NULL AND email = $1)
          OR ($2::text IS NOT NULL AND phone = $2)
       LIMIT 1`,
      [email || null, phone || null]
    );

    if (rows.length === 0) {
      return res.status(401).json({ error: 'Credenciales incorrectas' });
    }

    const usuario = rows[0];

    if (!usuario.activo) {
      return res.status(403).json({ error: 'Cuenta desactivada' });
    }

    // ── Verificar contraseña ───────────────────────────────────
    const passwordOk = await bcrypt.compare(password, usuario.password_hash);
    if (!passwordOk) {
      return res.status(401).json({ error: 'Credenciales incorrectas' });
    }

    // ── Obtener domicilio principal y routeId ──────────────────
    const { rows: domRows } = await pool.query(
      `SELECT d.id AS domicilio_id, r.route_id
       FROM domicilios d
       LEFT JOIN colonias c ON c.id = d.colonia_id
       LEFT JOIN rutas    r ON r.id = c.ruta_id
       WHERE d.user_id = $1
       ORDER BY d.created_at ASC
       LIMIT 1`,
      [usuario.id]
    );

    const domicilioId = domRows[0]?.domicilio_id || null;
    const routeId     = domRows[0]?.route_id     || null;

    // ── Generar JWT ────────────────────────────────────────────
    const token = jwt.sign(
      {
        sub:         usuario.id,
        userId:      usuario.id,
        routeId,
        rol:         usuario.rol,
        domicilioId,
      },
      SECRET,
      { expiresIn: EXPIRA }
    );

    // Actualizar updated_at
    await pool.query('UPDATE users SET updated_at = NOW() WHERE id = $1', [usuario.id]);

    return res.json({
      message: 'Login exitoso',
      token,
      usuario: {
        id:    usuario.id,
        email: usuario.email,
        phone: usuario.phone,
        rol:   usuario.rol,
      },
    });

  } catch (err) {
    console.error('❌ Error en login:', err.message);
    return res.status(500).json({ error: 'Error interno del servidor' });
  }
});

module.exports = router;
