/**
 * PosicionGps Controller
 * ERP Transportistas
 *
 * REST API endpoints for GPS position tracking.
 * Adapted from erp-mecanicas-diesel MMD-014 GPS Integration
 * Module: MAI-006 Tracking
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import { PosicionGpsService, PosicionFilters } from '../services/posicion-gps.service';

interface TenantRequest extends Request {
  tenantId?: string;
  userId?: string;
}

export function createPosicionGpsController(dataSource: DataSource): Router {
  const router = Router();
  const service = new PosicionGpsService(dataSource);

  const extractTenant = (req: TenantRequest, res: Response, next: NextFunction) => {
    const tenantId = req.headers['x-tenant-id'] as string;
    if (!tenantId) {
      return res.status(400).json({ error: 'Tenant ID es requerido' });
    }
    req.tenantId = tenantId;
    req.userId = req.headers['x-user-id'] as string;
    next();
  };

  router.use(extractTenant);

  /**
   * Record a new GPS position
   * POST /api/gps/posiciones
   */
  router.post('/', async (req: TenantRequest, res: Response) => {
    try {
      const posicion = await service.create(req.tenantId!, {
        ...req.body,
        tiempoDispositivo: new Date(req.body.tiempoDispositivo),
        tiempoFix: req.body.tiempoFix ? new Date(req.body.tiempoFix) : undefined,
      });
      res.status(201).json(posicion);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Record multiple positions in batch
   * POST /api/gps/posiciones/batch
   */
  router.post('/batch', async (req: TenantRequest, res: Response) => {
    try {
      const posiciones = req.body.posiciones.map((p: any) => ({
        ...p,
        tiempoDispositivo: new Date(p.tiempoDispositivo),
        tiempoFix: p.tiempoFix ? new Date(p.tiempoFix) : undefined,
      }));
      const count = await service.createBatch(req.tenantId!, posiciones);
      res.status(201).json({ insertados: count });
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Get position history with filters
   * GET /api/gps/posiciones
   */
  router.get('/', async (req: TenantRequest, res: Response) => {
    try {
      const filters: PosicionFilters = {
        dispositivoId: req.query.dispositivoId as string,
        unidadId: req.query.unidadId as string,
        tiempoInicio: req.query.tiempoInicio ? new Date(req.query.tiempoInicio as string) : undefined,
        tiempoFin: req.query.tiempoFin ? new Date(req.query.tiempoFin as string) : undefined,
        velocidadMinima: req.query.velocidadMinima ? parseFloat(req.query.velocidadMinima as string) : undefined,
        velocidadMaxima: req.query.velocidadMaxima ? parseFloat(req.query.velocidadMaxima as string) : undefined,
        esValido: req.query.esValido === 'true' ? true : req.query.esValido === 'false' ? false : undefined,
      };

      const pagination = {
        page: parseInt(req.query.page as string, 10) || 1,
        limit: Math.min(parseInt(req.query.limit as string, 10) || 100, 500),
      };

      const result = await service.findAll(req.tenantId!, filters, pagination);
      res.json(result);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get last position for a device
   * GET /api/gps/posiciones/ultima/:dispositivoId
   */
  router.get('/ultima/:dispositivoId', async (req: TenantRequest, res: Response) => {
    try {
      const posicion = await service.getUltimaPosicion(req.tenantId!, req.params.dispositivoId);
      if (!posicion) {
        return res.status(404).json({ error: 'Posicion no encontrada' });
      }
      res.json(posicion);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get last positions for multiple devices
   * POST /api/gps/posiciones/ultimas
   */
  router.post('/ultimas', async (req: TenantRequest, res: Response) => {
    try {
      const { dispositivoIds } = req.body;
      const posiciones = await service.getUltimasPosiciones(req.tenantId!, dispositivoIds);
      res.json(posiciones);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get track for a device
   * GET /api/gps/posiciones/track/:dispositivoId
   */
  router.get('/track/:dispositivoId', async (req: TenantRequest, res: Response) => {
    try {
      const tiempoInicio = new Date(req.query.tiempoInicio as string);
      const tiempoFin = new Date(req.query.tiempoFin as string);
      const simplificar = req.query.simplificar === 'true';

      const track = await service.getTrack(
        req.tenantId!,
        req.params.dispositivoId,
        tiempoInicio,
        tiempoFin,
        simplificar
      );
      res.json(track);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Get track summary for a device
   * GET /api/gps/posiciones/track/:dispositivoId/resumen
   */
  router.get('/track/:dispositivoId/resumen', async (req: TenantRequest, res: Response) => {
    try {
      const tiempoInicio = new Date(req.query.tiempoInicio as string);
      const tiempoFin = new Date(req.query.tiempoFin as string);

      const resumen = await service.getResumenTrack(
        req.tenantId!,
        req.params.dispositivoId,
        tiempoInicio,
        tiempoFin
      );

      if (!resumen) {
        return res.status(404).json({ error: 'No hay posiciones en el rango de tiempo' });
      }
      res.json(resumen);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Calculate distance between two points
   * POST /api/gps/posiciones/distancia
   */
  router.post('/distancia', async (req: TenantRequest, res: Response) => {
    try {
      const { lat1, lng1, lat2, lng2 } = req.body;
      const distanciaKm = service.calcularDistancia(lat1, lng1, lat2, lng2);
      res.json({ distanciaKm });
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * Get position by ID
   * GET /api/gps/posiciones/:id
   */
  router.get('/:id', async (req: TenantRequest, res: Response) => {
    try {
      const posicion = await service.findById(req.tenantId!, req.params.id);
      if (!posicion) {
        return res.status(404).json({ error: 'Posicion no encontrada' });
      }
      res.json(posicion);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * Delete old positions
   * DELETE /api/gps/posiciones/antiguas
   */
  router.delete('/antiguas', async (req: TenantRequest, res: Response) => {
    try {
      const antesDe = new Date(req.query.antesDe as string);
      const eliminadas = await service.eliminarPosicionesAntiguas(req.tenantId!, antesDe);
      res.json({ eliminadas });
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  return router;
}
