"use strict";
/**
 * InspectionService - Servicio de inspecciones de calidad
 *
 * Gestión de inspecciones con checklists y resultados.
 *
 * @module Quality
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.InspectionService = void 0;
class InspectionService {
    inspectionRepository;
    resultRepository;
    nonConformityRepository;
    checklistRepository;
    constructor(inspectionRepository, resultRepository, nonConformityRepository, checklistRepository) {
        this.inspectionRepository = inspectionRepository;
        this.resultRepository = resultRepository;
        this.nonConformityRepository = nonConformityRepository;
        this.checklistRepository = checklistRepository;
    }
    generateInspectionNumber() {
        const now = new Date();
        const year = now.getFullYear().toString().slice(-2);
        const month = (now.getMonth() + 1).toString().padStart(2, '0');
        const random = Math.random().toString(36).substring(2, 8).toUpperCase();
        return `INS-${year}${month}-${random}`;
    }
    generateNCNumber() {
        const now = new Date();
        const year = now.getFullYear().toString().slice(-2);
        const month = (now.getMonth() + 1).toString().padStart(2, '0');
        const random = Math.random().toString(36).substring(2, 6).toUpperCase();
        return `NC-${year}${month}-${random}`;
    }
    async findWithFilters(ctx, filters = {}, page = 1, limit = 20) {
        const skip = (page - 1) * limit;
        const queryBuilder = this.inspectionRepository
            .createQueryBuilder('insp')
            .leftJoinAndSelect('insp.checklist', 'checklist')
            .leftJoinAndSelect('insp.inspector', 'inspector')
            .where('insp.tenant_id = :tenantId', { tenantId: ctx.tenantId });
        if (filters.checklistId) {
            queryBuilder.andWhere('insp.checklist_id = :checklistId', { checklistId: filters.checklistId });
        }
        if (filters.loteId) {
            queryBuilder.andWhere('insp.lote_id = :loteId', { loteId: filters.loteId });
        }
        if (filters.inspectorId) {
            queryBuilder.andWhere('insp.inspector_id = :inspectorId', { inspectorId: filters.inspectorId });
        }
        if (filters.status) {
            queryBuilder.andWhere('insp.status = :status', { status: filters.status });
        }
        if (filters.dateFrom) {
            queryBuilder.andWhere('insp.inspection_date >= :dateFrom', { dateFrom: filters.dateFrom });
        }
        if (filters.dateTo) {
            queryBuilder.andWhere('insp.inspection_date <= :dateTo', { dateTo: filters.dateTo });
        }
        queryBuilder
            .orderBy('insp.inspection_date', 'DESC')
            .skip(skip)
            .take(limit);
        const [data, total] = await queryBuilder.getManyAndCount();
        return {
            data,
            meta: {
                total,
                page,
                limit,
                totalPages: Math.ceil(total / limit),
            },
        };
    }
    async findById(ctx, id) {
        return this.inspectionRepository.findOne({
            where: {
                id,
                tenantId: ctx.tenantId,
            },
        });
    }
    async findWithDetails(ctx, id) {
        return this.inspectionRepository.findOne({
            where: {
                id,
                tenantId: ctx.tenantId,
            },
            relations: ['checklist', 'checklist.items', 'inspector', 'results', 'results.checklistItem', 'nonConformities'],
        });
    }
    async create(ctx, dto) {
        // Validate checklist exists
        const checklist = await this.checklistRepository.findOne({
            where: {
                id: dto.checklistId,
                tenantId: ctx.tenantId,
                isActive: true,
                deletedAt: null,
            },
            relations: ['items'],
        });
        if (!checklist) {
            throw new Error('Checklist not found or inactive');
        }
        const inspection = this.inspectionRepository.create({
            tenantId: ctx.tenantId,
            createdById: ctx.userId,
            checklistId: dto.checklistId,
            loteId: dto.loteId,
            inspectionNumber: this.generateInspectionNumber(),
            inspectionDate: dto.inspectionDate,
            inspectorId: dto.inspectorId,
            notes: dto.notes,
            status: 'pending',
            totalItems: checklist.items?.filter(i => i.isActive).length || 0,
        });
        return this.inspectionRepository.save(inspection);
    }
    async startInspection(ctx, id) {
        const inspection = await this.findById(ctx, id);
        if (!inspection) {
            return null;
        }
        if (inspection.status !== 'pending') {
            throw new Error('Can only start pending inspections');
        }
        inspection.status = 'in_progress';
        inspection.updatedById = ctx.userId || '';
        return this.inspectionRepository.save(inspection);
    }
    async recordResult(ctx, inspectionId, dto) {
        const inspection = await this.findById(ctx, inspectionId);
        if (!inspection) {
            throw new Error('Inspection not found');
        }
        if (inspection.status !== 'in_progress') {
            throw new Error('Can only record results for in-progress inspections');
        }
        // Check if result already exists
        let result = await this.resultRepository.findOne({
            where: {
                inspectionId,
                checklistItemId: dto.checklistItemId,
                tenantId: ctx.tenantId,
            },
        });
        if (result) {
            // Update existing
            result.result = dto.result;
            result.observations = dto.observations || result.observations;
            result.photoUrl = dto.photoUrl || result.photoUrl;
            result.inspectedAt = new Date();
        }
        else {
            // Create new
            result = this.resultRepository.create({
                tenantId: ctx.tenantId,
                inspectionId,
                checklistItemId: dto.checklistItemId,
                result: dto.result,
                observations: dto.observations,
                photoUrl: dto.photoUrl,
                inspectedAt: new Date(),
            });
        }
        const savedResult = await this.resultRepository.save(result);
        // If failed, create non-conformity automatically
        if (dto.result === 'failed') {
            const nc = this.nonConformityRepository.create({
                tenantId: ctx.tenantId,
                createdById: ctx.userId,
                inspectionId,
                loteId: inspection.loteId,
                ncNumber: this.generateNCNumber(),
                detectionDate: new Date(),
                category: 'Inspection Finding',
                severity: 'minor',
                description: dto.observations || 'Failed inspection item',
                photoUrl: dto.photoUrl,
                status: 'open',
            });
            await this.nonConformityRepository.save(nc);
        }
        return savedResult;
    }
    async completeInspection(ctx, id) {
        const inspection = await this.findWithDetails(ctx, id);
        if (!inspection) {
            return null;
        }
        if (inspection.status !== 'in_progress') {
            throw new Error('Can only complete in-progress inspections');
        }
        // Calculate pass/fail counts
        const results = inspection.results || [];
        const passed = results.filter(r => r.result === 'passed').length;
        const failed = results.filter(r => r.result === 'failed').length;
        const total = results.filter(r => r.result !== 'not_applicable').length;
        inspection.passedItems = passed;
        inspection.failedItems = failed;
        inspection.passRate = total > 0 ? (passed / total) * 100 : 0;
        inspection.status = 'completed';
        inspection.completedAt = new Date();
        inspection.updatedById = ctx.userId || '';
        return this.inspectionRepository.save(inspection);
    }
    async approveInspection(ctx, id) {
        const inspection = await this.findWithDetails(ctx, id);
        if (!inspection) {
            return null;
        }
        if (inspection.status !== 'completed') {
            throw new Error('Can only approve completed inspections');
        }
        // Check for open critical non-conformities
        const criticalNCs = inspection.nonConformities?.filter(nc => nc.severity === 'critical' && nc.status !== 'verified');
        if (criticalNCs && criticalNCs.length > 0) {
            throw new Error('Cannot approve inspection with open critical non-conformities');
        }
        inspection.status = 'approved';
        inspection.approvedById = ctx.userId || '';
        inspection.approvedAt = new Date();
        inspection.updatedById = ctx.userId || '';
        return this.inspectionRepository.save(inspection);
    }
    async rejectInspection(ctx, id, reason) {
        const inspection = await this.findById(ctx, id);
        if (!inspection) {
            return null;
        }
        if (inspection.status !== 'completed') {
            throw new Error('Can only reject completed inspections');
        }
        inspection.status = 'rejected';
        inspection.rejectionReason = reason;
        inspection.updatedById = ctx.userId || '';
        return this.inspectionRepository.save(inspection);
    }
}
exports.InspectionService = InspectionService;
//# sourceMappingURL=inspection.service.js.map