/**
 * BiometricCredentialController - Controlador de Credenciales Biometricas
 *
 * Endpoints para gestion de credenciales biometricas (huella, Face ID, etc).
 *
 * @module Biometrics
 */

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

export function createBiometricCredentialController(dataSource: DataSource): Router {
  const router = Router();
  const service = new BiometricCredentialService(dataSource);

  // ==================== CREDENTIAL MANAGEMENT ====================

  /**
   * POST /
   * Registra una nueva credencial biometrica
   */
  router.post('/', async (req: Request, res: Response): Promise<void> => {
    try {
      const credential = await service.register(req.body);
      res.status(201).json(credential);
    } catch (error) {
      res.status(400).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /device/:deviceId
   * Lista credenciales de un dispositivo
   */
  router.get('/device/:deviceId', async (req: Request, res: Response): Promise<void> => {
    try {
      const credentials = await service.findByDevice(req.params.deviceId);
      res.json(credentials);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /device/:deviceId/primary
   * Obtiene la credencial primaria de un dispositivo
   */
  router.get('/device/:deviceId/primary', async (req: Request, res: Response): Promise<void> => {
    try {
      const credential = await service.getPrimaryCredential(req.params.deviceId);
      if (!credential) {
        res.status(404).json({ error: 'No hay credencial primaria configurada' });
        return;
      }
      res.json(credential);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /user/:userId
   * Lista credenciales de un usuario
   */
  router.get('/user/:userId', 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) || 20,
      };

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

  /**
   * GET /user/:userId/stats
   * Obtiene estadisticas de credenciales de un usuario
   */
  router.get('/user/:userId/stats', async (req: Request, res: Response): Promise<void> => {
    try {
      const stats = await service.getUserStats(req.params.userId);
      res.json(stats);
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /:id
   * Obtiene una credencial por ID
   */
  router.get('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const credential = await service.findById(req.params.id);
      if (!credential) {
        res.status(404).json({ error: 'Credencial no encontrada' });
        return;
      }

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

  /**
   * PUT /:id
   * Actualiza una credencial
   */
  router.put('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const credential = await service.update(req.params.id, req.body);
      if (!credential) {
        res.status(404).json({ error: 'Credencial no encontrada' });
        return;
      }

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

  /**
   * PATCH /:id/set-primary
   * Establece una credencial como primaria
   */
  router.patch('/:id/set-primary', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const credential = await service.update(req.params.id, { isPrimary: true });
      if (!credential) {
        res.status(404).json({ error: 'Credencial no encontrada' });
        return;
      }

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

  /**
   * DELETE /:id
   * Elimina una credencial (soft delete)
   */
  router.delete('/:id', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const deleted = await service.delete(req.params.id);
      if (!deleted) {
        res.status(404).json({ error: 'Credencial no encontrada' });
        return;
      }

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

  /**
   * DELETE /device/:deviceId
   * Elimina todas las credenciales de un dispositivo
   */
  router.delete('/device/:deviceId', async (req: Request, res: Response): Promise<void> => {
    try {
      const count = await service.deleteByDevice(req.params.deviceId);
      res.json({ success: true, deletedCount: count });
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  // ==================== AUTHENTICATION ====================

  /**
   * POST /verify
   * Verifica una credencial biometrica
   */
  router.post('/verify', async (req: Request, res: Response): Promise<void> => {
    try {
      const { credentialId } = req.body;

      if (!credentialId) {
        res.status(400).json({ error: 'Se requiere credentialId' });
        return;
      }

      // Check if locked
      const isLocked = await service.isLocked(credentialId);
      if (isLocked) {
        res.status(423).json({
          error: 'Credencial bloqueada temporalmente',
          locked: true,
        });
        return;
      }

      // Get credential for verification
      const credential = await service.findByCredentialId(credentialId);
      if (!credential) {
        res.status(404).json({ error: 'Credencial no encontrada' });
        return;
      }

      // Note: In a real implementation, the verification would happen here
      // using the public key and signature from the client
      // For now, we just return the credential info

      res.json({
        credentialId: credential.credentialId,
        biometricType: credential.biometricType,
        publicKey: credential.publicKey,
        algorithm: credential.algorithm,
      });
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /auth/success
   * Registra una autenticacion exitosa
   */
  router.post('/auth/success', async (req: Request, res: Response): Promise<void> => {
    try {
      const { credentialId } = req.body;

      if (!credentialId) {
        res.status(400).json({ error: 'Se requiere credentialId' });
        return;
      }

      const credential = await service.recordSuccess(credentialId);
      if (!credential) {
        res.status(404).json({ error: 'Credencial no encontrada' });
        return;
      }

      res.json({
        success: true,
        useCount: credential.useCount,
        lastUsedAt: credential.lastUsedAt,
      });
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * POST /auth/failure
   * Registra un intento fallido de autenticacion
   */
  router.post('/auth/failure', async (req: Request, res: Response): Promise<void> => {
    try {
      const { credentialId } = req.body;

      if (!credentialId) {
        res.status(400).json({ error: 'Se requiere credentialId' });
        return;
      }

      const result = await service.recordFailure(credentialId);
      if (!result.credential) {
        res.status(404).json({ error: 'Credencial no encontrada' });
        return;
      }

      res.json({
        success: false,
        isLocked: result.isLocked,
        remainingAttempts: result.remainingAttempts,
        lockoutUntil: result.lockoutUntil,
      });
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  /**
   * GET /check-locked/:credentialId
   * Verifica si una credencial esta bloqueada
   */
  router.get('/check-locked/:credentialId', async (req: Request, res: Response): Promise<void> => {
    try {
      const isLocked = await service.isLocked(req.params.credentialId);
      res.json({ locked: isLocked });
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  // ==================== ADMIN OPERATIONS ====================

  /**
   * POST /:id/unlock
   * Desbloquea una credencial (funcion admin)
   */
  router.post('/:id/unlock', async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const unlocked = await service.resetFailedAttempts(req.params.id);
      if (!unlocked) {
        res.status(404).json({ error: 'Credencial no encontrada' });
        return;
      }

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

  /**
   * POST /maintenance/unlock-expired
   * Desbloquea credenciales con bloqueo expirado
   */
  router.post('/maintenance/unlock-expired', async (_req: Request, res: Response): Promise<void> => {
    try {
      const count = await service.unlockExpiredLockouts();
      res.json({ success: true, unlockedCount: count });
    } catch (error) {
      res.status(500).json({ error: (error as Error).message });
    }
  });

  return router;
}
