/**
 * CorrectiveActionController - REST API for corrective actions (Acciones Correctivas CAPA)
 *
 * Endpoints para gestion de acciones correctivas y preventivas (CAPA).
 *
 * @module Quality (MAI-009)
 * @routes /api/acciones-correctivas
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import {
  CorrectiveActionService,
  CorrectiveActionFilters,
  CreateCorrectiveActionDto,
  UpdateCorrectiveActionDto,
  CompleteActionDto,
  VerifyActionDto,
} from '../services/corrective-action.service';
import { CorrectiveAction, ActionType, ActionStatus } from '../entities/corrective-action.entity';
import { NonConformity } from '../entities/non-conformity.entity';
import { AuthMiddleware } from '../../auth/middleware/auth.middleware';
import { AuthService } from '../../auth/services/auth.service';
import { User } from '../../core/entities/user.entity';
import { Tenant } from '../../core/entities/tenant.entity';
import { RefreshToken } from '../../auth/entities/refresh-token.entity';

interface ServiceContext {
  tenantId: string;
  userId?: string;
}

/**
 * Creates the CorrectiveAction controller with all REST endpoints
 * @param dataSource - TypeORM DataSource for database operations
 * @returns Express Router with all endpoints configured
 */
export function createCorrectiveActionController(dataSource: DataSource): Router {
  const router = Router();

  // Repositories
  const actionRepo = dataSource.getRepository(CorrectiveAction);
  const ncRepo = dataSource.getRepository(NonConformity);
  const userRepository = dataSource.getRepository(User);
  const tenantRepository = dataSource.getRepository(Tenant);
  const refreshTokenRepository = dataSource.getRepository(RefreshToken);

  // Services
  const service = new CorrectiveActionService(actionRepo, ncRepo);
  const authService = new AuthService(userRepository, tenantRepository, refreshTokenRepository as any);
  const authMiddleware = new AuthMiddleware(authService, dataSource);

  /**
   * Helper to extract service context from request
   */
  const getContext = (req: Request): ServiceContext => {
    if (!req.tenantId) {
      throw new Error('Tenant ID is required');
    }
    return {
      tenantId: req.tenantId,
      userId: req.user?.sub,
    };
  };

  /**
   * GET /api/acciones-correctivas
   * List corrective actions with filters and pagination
   *
   * Query params:
   * - nonConformityId: Filter by non-conformity
   * - responsibleId: Filter by responsible user
   * - actionType: Filter by type (corrective, preventive, improvement)
   * - status: Filter by status (pending, in_progress, completed, verified)
   * - effectivenessVerified: Filter by effectiveness verification
   * - dueDateFrom/To: Due date range filters
   * - search: Search in description
   * - page: Page number (default: 1)
   * - limit: Items per page (default: 20, max: 100)
   */
  router.get('/', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const filters: CorrectiveActionFilters = {};
      if (req.query.nonConformityId) filters.nonConformityId = req.query.nonConformityId as string;
      if (req.query.responsibleId) filters.responsibleId = req.query.responsibleId as string;
      if (req.query.actionType) filters.actionType = req.query.actionType as ActionType;
      if (req.query.status) filters.status = req.query.status as ActionStatus;
      if (req.query.effectivenessVerified !== undefined) {
        filters.effectivenessVerified = req.query.effectivenessVerified === 'true';
      }
      if (req.query.dueDateFrom) filters.dueDateFrom = new Date(req.query.dueDateFrom as string);
      if (req.query.dueDateTo) filters.dueDateTo = new Date(req.query.dueDateTo as string);
      if (req.query.search) filters.search = req.query.search as string;

      const page = parseInt(req.query.page as string) || 1;
      const limit = Math.min(parseInt(req.query.limit as string) || 20, 100);

      const result = await service.findWithFilters(getContext(req), filters, page, limit);

      res.status(200).json({
        success: true,
        data: result.data,
        pagination: {
          total: result.total,
          page: result.page,
          limit: result.limit,
          totalPages: Math.ceil(result.total / result.limit),
        },
      });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /api/acciones-correctivas/vencidas
   * Get overdue corrective actions
   */
  router.get('/vencidas', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const overdueActions = await service.getOverdueActions(getContext(req));

      res.status(200).json({
        success: true,
        data: overdueActions,
        count: overdueActions.length,
      });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /api/acciones-correctivas/por-responsable/:responsibleId
   * Get corrective action statistics by responsible user
   */
  router.get('/por-responsable/:responsibleId', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const stats = await service.getStatsByResponsible(getContext(req), req.params.responsibleId);

      res.status(200).json({
        success: true,
        data: stats,
      });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /api/acciones-correctivas/por-no-conformidad/:nonConformityId
   * Get corrective actions for a specific non-conformity
   */
  router.get('/por-no-conformidad/:nonConformityId', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const actions = await service.findByNonConformity(getContext(req), req.params.nonConformityId);

      res.status(200).json({
        success: true,
        data: actions,
        count: actions.length,
      });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /api/acciones-correctivas/:id
   * Get corrective action detail with relations
   */
  router.get('/:id', authMiddleware.authenticate, async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const action = await service.findWithDetails(getContext(req), req.params.id);
      if (!action) {
        res.status(404).json({ error: 'Not Found', message: 'Accion correctiva no encontrada' });
        return;
      }

      res.status(200).json({
        success: true,
        data: action,
      });
    } catch (error) {
      next(error);
    }
  });

  /**
   * POST /api/acciones-correctivas
   * Create new corrective action
   *
   * Body:
   * - nonConformityId: (required) UUID of the non-conformity
   * - actionType: (required) 'corrective' | 'preventive' | 'improvement'
   * - description: (required) Description text
   * - responsibleId: (required) UUID of responsible user
   * - dueDate: (required) Due date
   */
  router.post('/', authMiddleware.authenticate, authMiddleware.authorize('admin', 'quality', 'resident'), async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      // Validate required fields
      const { nonConformityId, actionType, description, responsibleId, dueDate } = req.body;
      if (!nonConformityId || !actionType || !description || !responsibleId || !dueDate) {
        res.status(400).json({
          error: 'Bad Request',
          message: 'nonConformityId, actionType, description, responsibleId y dueDate son requeridos',
        });
        return;
      }

      // Validate actionType enum
      const validTypes: ActionType[] = ['corrective', 'preventive', 'improvement'];
      if (!validTypes.includes(actionType)) {
        res.status(400).json({
          error: 'Bad Request',
          message: `Tipo de accion invalido. Valores validos: ${validTypes.join(', ')}`,
        });
        return;
      }

      const dto: CreateCorrectiveActionDto = {
        nonConformityId,
        actionType,
        description,
        responsibleId,
        dueDate: new Date(dueDate),
      };

      const action = await service.create(getContext(req), dto);

      res.status(201).json({
        success: true,
        data: action,
        message: 'Accion correctiva creada exitosamente',
      });
    } catch (error: any) {
      if (error.message?.includes('not found')) {
        res.status(404).json({ error: 'Not Found', message: error.message });
        return;
      }
      if (error.message?.includes('Cannot add')) {
        res.status(400).json({ error: 'Bad Request', message: error.message });
        return;
      }
      next(error);
    }
  });

  /**
   * PUT /api/acciones-correctivas/:id
   * Update corrective action
   */
  router.put('/:id', authMiddleware.authenticate, authMiddleware.authorize('admin', 'quality', 'resident'), async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const dto: UpdateCorrectiveActionDto = {};
      if (req.body.actionType !== undefined) dto.actionType = req.body.actionType;
      if (req.body.description !== undefined) dto.description = req.body.description;
      if (req.body.responsibleId !== undefined) dto.responsibleId = req.body.responsibleId;
      if (req.body.dueDate !== undefined) dto.dueDate = new Date(req.body.dueDate);

      const action = await service.update(getContext(req), req.params.id, dto);
      if (!action) {
        res.status(404).json({ error: 'Not Found', message: 'Accion correctiva no encontrada' });
        return;
      }

      res.status(200).json({
        success: true,
        data: action,
        message: 'Accion correctiva actualizada exitosamente',
      });
    } catch (error: any) {
      if (error.message?.includes('Cannot update')) {
        res.status(400).json({ error: 'Bad Request', message: error.message });
        return;
      }
      next(error);
    }
  });

  /**
   * POST /api/acciones-correctivas/:id/iniciar
   * Start work on corrective action
   */
  router.post('/:id/iniciar', authMiddleware.authenticate, authMiddleware.authorize('admin', 'quality', 'resident'), async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const action = await service.startWork(getContext(req), req.params.id);
      if (!action) {
        res.status(404).json({ error: 'Not Found', message: 'Accion correctiva no encontrada' });
        return;
      }

      res.status(200).json({
        success: true,
        data: action,
        message: 'Trabajo iniciado en accion correctiva',
      });
    } catch (error: any) {
      if (error.message?.includes('Can only start')) {
        res.status(400).json({ error: 'Bad Request', message: error.message });
        return;
      }
      next(error);
    }
  });

  /**
   * POST /api/acciones-correctivas/:id/completar
   * Mark corrective action as completed
   *
   * Body:
   * - completionNotes: (required) Notes about the completion
   */
  router.post('/:id/completar', authMiddleware.authenticate, authMiddleware.authorize('admin', 'quality', 'resident'), async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const { completionNotes } = req.body;
      if (!completionNotes) {
        res.status(400).json({ error: 'Bad Request', message: 'completionNotes es requerido' });
        return;
      }

      const dto: CompleteActionDto = { completionNotes };

      const action = await service.complete(getContext(req), req.params.id, dto);
      if (!action) {
        res.status(404).json({ error: 'Not Found', message: 'Accion correctiva no encontrada' });
        return;
      }

      res.status(200).json({
        success: true,
        data: action,
        message: 'Accion correctiva marcada como completada',
      });
    } catch (error: any) {
      if (error.message?.includes('Can only complete')) {
        res.status(400).json({ error: 'Bad Request', message: error.message });
        return;
      }
      next(error);
    }
  });

  /**
   * POST /api/acciones-correctivas/:id/verificar
   * Verify effectiveness of corrective action
   *
   * Body:
   * - effectivenessVerified: (required) boolean indicating if action was effective
   * - verificationNotes: (optional) Notes about verification
   */
  router.post('/:id/verificar', authMiddleware.authenticate, authMiddleware.authorize('admin', 'quality'), async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const { effectivenessVerified, verificationNotes } = req.body;
      if (effectivenessVerified === undefined) {
        res.status(400).json({ error: 'Bad Request', message: 'effectivenessVerified es requerido' });
        return;
      }

      const dto: VerifyActionDto = {
        effectivenessVerified: Boolean(effectivenessVerified),
        verificationNotes,
      };

      const action = await service.verify(getContext(req), req.params.id, dto);
      if (!action) {
        res.status(404).json({ error: 'Not Found', message: 'Accion correctiva no encontrada' });
        return;
      }

      res.status(200).json({
        success: true,
        data: action,
        message: action.effectivenessVerified
          ? 'Accion correctiva verificada como efectiva'
          : 'Accion correctiva verificada como no efectiva',
      });
    } catch (error: any) {
      if (error.message?.includes('Can only verify')) {
        res.status(400).json({ error: 'Bad Request', message: error.message });
        return;
      }
      next(error);
    }
  });

  /**
   * POST /api/acciones-correctivas/:id/reabrir
   * Reopen completed or verified corrective action
   *
   * Body:
   * - reason: (required) Reason for reopening
   */
  router.post('/:id/reabrir', authMiddleware.authenticate, authMiddleware.authorize('admin', 'quality'), async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const { reason } = req.body;
      if (!reason) {
        res.status(400).json({ error: 'Bad Request', message: 'reason es requerido' });
        return;
      }

      const action = await service.reopen(getContext(req), req.params.id, reason);
      if (!action) {
        res.status(404).json({ error: 'Not Found', message: 'Accion correctiva no encontrada' });
        return;
      }

      res.status(200).json({
        success: true,
        data: action,
        message: 'Accion correctiva reabierta exitosamente',
      });
    } catch (error: any) {
      if (error.message?.includes('Can only reopen')) {
        res.status(400).json({ error: 'Bad Request', message: error.message });
        return;
      }
      next(error);
    }
  });

  /**
   * DELETE /api/acciones-correctivas/:id
   * Delete pending corrective action
   */
  router.delete('/:id', authMiddleware.authenticate, authMiddleware.authorize('admin', 'quality'), async (req: Request, res: Response, next: NextFunction): Promise<void> => {
    try {
      const tenantId = req.tenantId;
      if (!tenantId) {
        res.status(400).json({ error: 'Bad Request', message: 'Tenant ID required' });
        return;
      }

      const deleted = await service.delete(getContext(req), req.params.id);
      if (!deleted) {
        res.status(404).json({ error: 'Not Found', message: 'Accion correctiva no encontrada' });
        return;
      }

      res.status(200).json({
        success: true,
        message: 'Accion correctiva eliminada exitosamente',
      });
    } catch (error: any) {
      if (error.message?.includes('Can only delete')) {
        res.status(400).json({ error: 'Bad Request', message: error.message });
        return;
      }
      next(error);
    }
  });

  return router;
}
