/**
 * DeviceController - Controlador de Dispositivos
 *
 * Endpoints para gestion de dispositivos biometricos y sesiones.
 *
 * @module Biometrics
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import { DeviceService } from '../services';

export function createDeviceController(dataSource: DataSource): Router {
  const router = Router();
  const service = new DeviceService(dataSource);

  // ==================== DEVICE MANAGEMENT ====================

  /**
   * GET /
   * Lista dispositivos con filtros y paginacion
   */
  router.get('/', async (req: Request, res: Response, _next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const filters = {
        userId: req.query.userId as string,
        platform: req.query.platform as any,
        isActive: req.query.isActive === 'true' ? true : req.query.isActive === 'false' ? false : undefined,
        isTrusted: req.query.isTrusted === 'true' ? true : req.query.isTrusted === 'false' ? false : undefined,
        biometricEnabled: req.query.biometricEnabled === 'true' ? true : req.query.biometricEnabled === 'false' ? false : undefined,
        search: req.query.search as string,
      };

      const pagination = {
        page: parseInt(req.query.page as string) || 1,
        limit: parseInt(req.query.limit as string) || 20,
      };

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

  /**
   * GET /statistics
   * Obtiene estadisticas de dispositivos
   */
  router.get('/statistics', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const stats = await service.getStatistics(tenantId);
      res.json(stats);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /user/:userId
   * Lista dispositivos de un usuario
   */
  router.get('/user/:userId', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const pagination = {
        page: parseInt(req.query.page as string) || 1,
        limit: parseInt(req.query.limit as string) || 20,
      };

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

  /**
   * GET /:id
   * Obtiene un dispositivo por ID
   */
  router.get('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const device = await service.findById(tenantId, req.params.id);
      if (!device) {
        res.status(404).json({ error: 'Dispositivo no encontrado' });
        return;
      }

      res.json(device);
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /register
   * Registra un nuevo dispositivo o actualiza existente
   */
  router.post('/register', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const device = await service.registerDevice(tenantId, req.body);
      res.status(201).json(device);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * PUT /:id
   * Actualiza un dispositivo
   */
  router.put('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const device = await service.update(tenantId, req.params.id, req.body);
      if (!device) {
        res.status(404).json({ error: 'Dispositivo no encontrado' });
        return;
      }

      res.json(device);
    } catch (error) {
      next(error);
    }
  });

  /**
   * PATCH /:id/location
   * Actualiza la ubicacion del dispositivo
   */
  router.patch('/:id/location', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { latitude, longitude, ipAddress } = req.body;

      if (latitude === undefined || longitude === undefined) {
        res.status(400).json({ error: 'Se requieren latitude y longitude' });
        return;
      }

      const device = await service.updateLocation(tenantId, req.params.id, latitude, longitude, ipAddress);
      if (!device) {
        res.status(404).json({ error: 'Dispositivo no encontrado' });
        return;
      }

      res.json(device);
    } catch (error) {
      next(error);
    }
  });

  /**
   * PATCH /:id/biometric
   * Habilita/deshabilita autenticacion biometrica
   */
  router.patch('/:id/biometric', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { enabled, biometricType } = req.body;

      if (enabled === undefined) {
        res.status(400).json({ error: 'Se requiere el parametro enabled' });
        return;
      }

      const device = await service.toggleBiometric(tenantId, req.params.id, enabled, biometricType);
      if (!device) {
        res.status(404).json({ error: 'Dispositivo no encontrado' });
        return;
      }

      res.json(device);
    } catch (error) {
      next(error);
    }
  });

  /**
   * PATCH /:id/trust
   * Establece el nivel de confianza del dispositivo
   */
  router.patch('/:id/trust', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { isTrusted, trustLevel } = req.body;

      if (isTrusted === undefined) {
        res.status(400).json({ error: 'Se requiere el parametro isTrusted' });
        return;
      }

      const device = await service.setTrust(tenantId, req.params.id, isTrusted, trustLevel);
      if (!device) {
        res.status(404).json({ error: 'Dispositivo no encontrado' });
        return;
      }

      res.json(device);
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /:id/deactivate
   * Desactiva un dispositivo
   */
  router.post('/:id/deactivate', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const deactivated = await service.deactivate(tenantId, req.params.id);
      if (!deactivated) {
        res.status(404).json({ error: 'Dispositivo no encontrado' });
        return;
      }

      res.json({ success: true, message: 'Dispositivo desactivado exitosamente' });
    } catch (error) {
      next(error);
    }
  });

  /**
   * DELETE /:id
   * Elimina un dispositivo (soft delete)
   */
  router.delete('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const deleted = await service.delete(tenantId, req.params.id);
      if (!deleted) {
        res.status(404).json({ error: 'Dispositivo no encontrado' });
        return;
      }

      res.status(204).send();
    } catch (error) {
      next(error);
    }
  });

  // ==================== SESSION MANAGEMENT ====================

  /**
   * GET /:id/sessions
   * Lista sesiones activas del dispositivo
   */
  router.get('/:id/sessions', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const sessions = await service.getActiveSessions(tenantId, req.params.id);
      res.json(sessions);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /:id/sessions
   * Crea una nueva sesion
   */
  router.post('/:id/sessions', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const dto = {
        ...req.body,
        deviceId: req.params.id,
      };

      const session = await service.createSession(tenantId, dto);
      res.status(201).json(session);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /:id/sessions/revoke-all
   * Revoca todas las sesiones del dispositivo
   */
  router.post('/:id/sessions/revoke-all', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { reason } = req.body;

      const count = await service.revokeAllSessions(tenantId, req.params.id, reason);
      res.json({ success: true, revokedCount: count });
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * DELETE /sessions/:sessionId
   * Revoca una sesion especifica
   */
  router.delete('/sessions/:sessionId', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { reason } = req.body;

      const revoked = await service.revokeSession(tenantId, req.params.sessionId, reason);
      if (!revoked) {
        res.status(404).json({ error: 'Sesion no encontrada' });
        return;
      }

      res.json({ success: true, message: 'Sesion revocada exitosamente' });
    } catch (error) {
      next(error);
    }
  });

  // ==================== USER SESSIONS ====================

  /**
   * GET /user/:userId/sessions
   * Lista todas las sesiones de un usuario
   */
  router.get('/user/:userId/sessions', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      const pagination = {
        page: parseInt(req.query.page as string) || 1,
        limit: parseInt(req.query.limit as string) || 20,
      };

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

  /**
   * POST /user/:userId/sessions/revoke-all
   * Revoca todas las sesiones de un usuario (logout de todos los dispositivos)
   */
  router.post('/user/:userId/sessions/revoke-all', async (req: Request, res: Response): Promise<void> => {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const { reason } = req.body;

      const count = await service.revokeAllUserSessions(tenantId, req.params.userId, reason);
      res.json({ success: true, revokedCount: count });
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  // ==================== ACTIVITY LOG ====================

  /**
   * GET /:id/activity
   * Obtiene el log de actividad del dispositivo
   */
  router.get('/:id/activity', async (req: Request, res: Response): Promise<void> => {
    try {
      const pagination = {
        page: parseInt(req.query.page as string) || 1,
        limit: parseInt(req.query.limit as string) || 50,
      };

      const result = await service.getDeviceActivity(req.params.id, pagination);
      res.json(result);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /:id/activity
   * Registra una actividad del dispositivo
   */
  router.post('/:id/activity', async (req: Request, res: Response): Promise<void> => {
    try {
      const userId = (req as any).user?.id;

      const dto = {
        ...req.body,
        deviceId: req.params.id,
        userId,
      };

      const log = await service.logActivity(dto);
      res.status(201).json(log);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /user/:userId/activity
   * Obtiene el log de actividad de un usuario
   */
  router.get('/user/:userId/activity', async (req: Request, res: Response): Promise<void> => {
    try {
      const pagination = {
        page: parseInt(req.query.page as string) || 1,
        limit: parseInt(req.query.limit as string) || 50,
      };

      const result = await service.getUserActivity(req.params.userId, pagination);
      res.json(result);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  // ==================== MAINTENANCE ====================

  /**
   * POST /maintenance/cleanup-sessions
   * Limpia sesiones expiradas
   */
  router.post('/maintenance/cleanup-sessions', async (_req: Request, res: Response): Promise<void> => {
    try {
      const count = await service.cleanupExpiredSessions();
      res.json({ success: true, cleanedCount: count });
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  return router;
}
