import { Request, Response, NextFunction, Router } from 'express';
import { OperadoresService, CreateOperadorDto, UpdateOperadorDto } from '../services/operadores.service';
import { TipoLicencia, EstadoOperador } from '../entities';

export class OperadoresController {
  public router: Router;

  constructor(private readonly operadoresService: OperadoresService) {
    this.router = Router();
    this.initializeRoutes();
  }

  private initializeRoutes(): void {
    // CRUD básico
    this.router.get('/', this.findAll.bind(this));
    this.router.get('/disponibles', this.getOperadoresDisponibles.bind(this));
    this.router.get('/licencia-por-vencer', this.getOperadoresLicenciaPorVencer.bind(this));
    this.router.get('/licencia-vencida', this.getOperadoresLicenciaVencida.bind(this));
    this.router.get('/:id', this.findOne.bind(this));
    this.router.get('/empleado/:numeroEmpleado', this.findByNumeroEmpleado.bind(this));
    this.router.get('/licencia/:numeroLicencia', this.findByLicencia.bind(this));
    this.router.post('/', this.create.bind(this));
    this.router.patch('/:id', this.update.bind(this));
    this.router.delete('/:id', this.delete.bind(this));

    // Operaciones específicas
    this.router.post('/:id/estado', this.cambiarEstado.bind(this));
  }

  private async findAll(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      if (!tenantId) {
        res.status(400).json({ error: 'Tenant ID is required' });
        return;
      }

      const { search, estado, estados, tipoLicencia, sucursalId, limit, offset } = req.query;

      const result = await this.operadoresService.findAll({
        tenantId,
        search: search as string,
        estado: estado as EstadoOperador,
        estados: estados ? (estados as string).split(',') as EstadoOperador[] : undefined,
        tipoLicencia: tipoLicencia as TipoLicencia,
        sucursalId: sucursalId as string,
        limit: limit ? parseInt(limit as string, 10) : undefined,
        offset: offset ? parseInt(offset as string, 10) : undefined,
      });

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

  private async findOne(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      if (!tenantId) {
        res.status(400).json({ error: 'Tenant ID is required' });
        return;
      }

      const { id } = req.params;
      const operador = await this.operadoresService.findOne(id, tenantId);

      if (!operador) {
        res.status(404).json({ error: 'Operador no encontrado' });
        return;
      }

      res.json({ data: operador });
    } catch (error) {
      next(error);
    }
  }

  private async findByNumeroEmpleado(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      if (!tenantId) {
        res.status(400).json({ error: 'Tenant ID is required' });
        return;
      }

      const { numeroEmpleado } = req.params;
      const operador = await this.operadoresService.findByNumeroEmpleado(numeroEmpleado, tenantId);

      if (!operador) {
        res.status(404).json({ error: 'Operador no encontrado' });
        return;
      }

      res.json({ data: operador });
    } catch (error) {
      next(error);
    }
  }

  private async findByLicencia(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      if (!tenantId) {
        res.status(400).json({ error: 'Tenant ID is required' });
        return;
      }

      const { numeroLicencia } = req.params;
      const operador = await this.operadoresService.findByLicencia(numeroLicencia, tenantId);

      if (!operador) {
        res.status(404).json({ error: 'Operador no encontrado' });
        return;
      }

      res.json({ data: operador });
    } catch (error) {
      next(error);
    }
  }

  private async create(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = req.headers['x-user-id'] as string;

      if (!tenantId) {
        res.status(400).json({ error: 'Tenant ID is required' });
        return;
      }

      const dto: CreateOperadorDto = req.body;
      const operador = await this.operadoresService.create(tenantId, dto, userId);
      res.status(201).json({ data: operador });
    } catch (error) {
      next(error);
    }
  }

  private async update(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = req.headers['x-user-id'] as string;

      if (!tenantId) {
        res.status(400).json({ error: 'Tenant ID is required' });
        return;
      }

      const { id } = req.params;
      const dto: UpdateOperadorDto = req.body;
      const operador = await this.operadoresService.update(id, tenantId, dto, userId);

      if (!operador) {
        res.status(404).json({ error: 'Operador no encontrado' });
        return;
      }

      res.json({ data: operador });
    } catch (error) {
      next(error);
    }
  }

  private async delete(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;

      if (!tenantId) {
        res.status(400).json({ error: 'Tenant ID is required' });
        return;
      }

      const { id } = req.params;
      const deleted = await this.operadoresService.delete(id, tenantId);

      if (!deleted) {
        res.status(404).json({ error: 'Operador no encontrado' });
        return;
      }

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

  private async cambiarEstado(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      const userId = req.headers['x-user-id'] as string;

      if (!tenantId) {
        res.status(400).json({ error: 'Tenant ID is required' });
        return;
      }

      const { id } = req.params;
      const { estado } = req.body;

      if (!estado) {
        res.status(400).json({ error: 'Estado es requerido' });
        return;
      }

      const operador = await this.operadoresService.cambiarEstado(id, tenantId, estado, userId);

      if (!operador) {
        res.status(404).json({ error: 'Operador no encontrado' });
        return;
      }

      res.json({ data: operador });
    } catch (error) {
      next(error);
    }
  }

  private async getOperadoresDisponibles(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      if (!tenantId) {
        res.status(400).json({ error: 'Tenant ID is required' });
        return;
      }

      const operadores = await this.operadoresService.getOperadoresDisponibles(tenantId);
      res.json({ data: operadores });
    } catch (error) {
      next(error);
    }
  }

  private async getOperadoresLicenciaPorVencer(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      if (!tenantId) {
        res.status(400).json({ error: 'Tenant ID is required' });
        return;
      }

      const { dias } = req.query;
      const diasAntelacion = dias ? parseInt(dias as string, 10) : 30;
      const operadores = await this.operadoresService.getOperadoresLicenciaPorVencer(tenantId, diasAntelacion);
      res.json({ data: operadores });
    } catch (error) {
      next(error);
    }
  }

  private async getOperadoresLicenciaVencida(req: Request, res: Response, next: NextFunction): Promise<void> {
    try {
      const tenantId = req.headers['x-tenant-id'] as string;
      if (!tenantId) {
        res.status(400).json({ error: 'Tenant ID is required' });
        return;
      }

      const operadores = await this.operadoresService.getOperadoresLicenciaVencida(tenantId);
      res.json({ data: operadores });
    } catch (error) {
      next(error);
    }
  }
}
