/**
 * InspectionController - REST API for quality inspections
 *
 * Endpoints para gestión de inspecciones de calidad.
 *
 * @module Quality
 * @routes /api/inspections
 */

import { Router, Request, Response, NextFunction } from 'express';
import { DataSource } from 'typeorm';
import { InspectionService, InspectionFilters } from '../services/inspection.service';
import { Inspection } from '../entities/inspection.entity';
import { InspectionResult } from '../entities/inspection-result.entity';
import { NonConformity } from '../entities/non-conformity.entity';
import { Checklist } from '../entities/checklist.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;
}

export function createInspectionController(dataSource: DataSource): Router {
  const router = Router();

  // Repositories
  const inspectionRepo = dataSource.getRepository(Inspection);
  const resultRepo = dataSource.getRepository(InspectionResult);
  const ncRepo = dataSource.getRepository(NonConformity);
  const checklistRepo = dataSource.getRepository(Checklist);
  const userRepository = dataSource.getRepository(User);
  const tenantRepository = dataSource.getRepository(Tenant);
  const refreshTokenRepository = dataSource.getRepository(RefreshToken);

  // Services
  const service = new InspectionService(inspectionRepo, resultRepo, ncRepo, checklistRepo);
  const authService = new AuthService(userRepository, tenantRepository, refreshTokenRepository as any);
  const authMiddleware = new AuthMiddleware(authService, dataSource);

  // Helper for service context
  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/inspections
   * List inspections with filters
   */
  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: InspectionFilters = {};
      if (req.query.checklistId) filters.checklistId = req.query.checklistId as string;
      if (req.query.loteId) filters.loteId = req.query.loteId as string;
      if (req.query.inspectorId) filters.inspectorId = req.query.inspectorId as string;
      if (req.query.status) filters.status = req.query.status as InspectionFilters['status'];
      if (req.query.dateFrom) filters.dateFrom = new Date(req.query.dateFrom as string);
      if (req.query.dateTo) filters.dateTo = new Date(req.query.dateTo 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 } });
    } catch (error) {
      next(error);
    }
  });

  /**
   * GET /api/inspections/:id
   * Get inspection with details
   */
  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 inspection = await service.findWithDetails(getContext(req), req.params.id);
      if (!inspection) {
        res.status(404).json({ error: 'Not Found', message: 'Inspection not found' });
        return;
      }

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

  /**
   * POST /api/inspections
   * Create new inspection
   */
  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;
      }

      const inspection = await service.create(getContext(req), {
        checklistId: req.body.checklistId,
        loteId: req.body.loteId,
        inspectionDate: new Date(req.body.inspectionDate),
        inspectorId: req.body.inspectorId,
        notes: req.body.notes,
      });

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

  /**
   * POST /api/inspections/:id/start
   * Start inspection
   */
  router.post('/:id/start', 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 inspection = await service.startInspection(getContext(req), req.params.id);
      if (!inspection) {
        res.status(404).json({ error: 'Not Found', message: 'Inspection not found' });
        return;
      }

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

  /**
   * POST /api/inspections/:id/results
   * Record inspection result
   */
  router.post('/:id/results', 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 result = await service.recordResult(getContext(req), req.params.id, {
        checklistItemId: req.body.checklistItemId,
        result: req.body.result,
        observations: req.body.observations,
        photoUrl: req.body.photoUrl,
      });

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

  /**
   * POST /api/inspections/:id/complete
   * Complete inspection
   */
  router.post('/:id/complete', 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 inspection = await service.completeInspection(getContext(req), req.params.id);
      if (!inspection) {
        res.status(404).json({ error: 'Not Found', message: 'Inspection not found' });
        return;
      }

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

  /**
   * POST /api/inspections/:id/approve
   * Approve inspection
   */
  router.post('/:id/approve', 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 inspection = await service.approveInspection(getContext(req), req.params.id);
      if (!inspection) {
        res.status(404).json({ error: 'Not Found', message: 'Inspection not found' });
        return;
      }

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

  /**
   * POST /api/inspections/:id/reject
   * Reject inspection
   */
  router.post('/:id/reject', 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 inspection = await service.rejectInspection(getContext(req), req.params.id, req.body.reason);
      if (!inspection) {
        res.status(404).json({ error: 'Not Found', message: 'Inspection not found' });
        return;
      }

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

  /**
   * GET /api/inspections/:id/checklist
   * Get checklist associated with inspection
   */
  router.get('/:id/checklist', 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 inspection = await service.findWithDetails(getContext(req), req.params.id);
      if (!inspection) {
        res.status(404).json({ error: 'Not Found', message: 'Inspection not found' });
        return;
      }

      res.status(200).json({
        success: true,
        data: {
          checklist: inspection.checklist,
          results: inspection.results,
          totalItems: inspection.totalItems,
          passedItems: inspection.passedItems,
          failedItems: inspection.failedItems,
          passRate: inspection.passRate,
        },
      });
    } catch (error) {
      next(error);
    }
  });

  /**
   * PUT /api/inspections/:id
   * Update inspection
   */
  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 inspection = await service.findById(getContext(req), req.params.id);
      if (!inspection) {
        res.status(404).json({ error: 'Not Found', message: 'Inspection not found' });
        return;
      }

      if (inspection.status !== 'pending') {
        res.status(400).json({ error: 'Bad Request', message: 'Can only update pending inspections' });
        return;
      }

      // Update allowed fields
      if (req.body.inspectionDate) {
        inspection.inspectionDate = new Date(req.body.inspectionDate);
      }
      if (req.body.inspectorId) {
        inspection.inspectorId = req.body.inspectorId;
      }
      if (req.body.notes !== undefined) {
        inspection.notes = req.body.notes;
      }
      inspection.updatedById = req.user?.sub || '';

      const updated = await inspectionRepo.save(inspection);
      res.status(200).json({ success: true, data: updated });
    } catch (error) {
      next(error);
    }
  });

  return router;
}
