/**
 * Service de validation des prérequis de phases
 * Gère la validation des dépendances entre phases et leurs prérequis métier
 */

import type { PhaseChantier } from '../types/btp-extended';

export interface PhaseValidationResult {
    canStart: boolean;
    errors: ValidationError[];
    warnings: ValidationWarning[];
    blockedBy: string[];
    readyToStart: boolean;
}

export interface ValidationError {
    code: string;
    message: string;
    severity: 'error' | 'warning' | 'info';
    phaseId?: string;
    prerequisiteId?: string;
}

export interface ValidationWarning {
    code: string;
    message: string;
    recommendation?: string;
}

export interface PrerequisiteStatus {
    prerequisiteId: string;
    prerequisiteName: string;
    status: 'completed' | 'in_progress' | 'not_started' | 'not_found';
    completionDate?: Date;
    isBlocking: boolean;
}

class PhaseValidationService {
    /**
     * Valide si une phase peut être démarrée en fonction de ses prérequis
     */
    validatePhaseStart(
        phase: PhaseChantier, 
        allPhases: PhaseChantier[],
        options: { strictMode?: boolean } = {}
    ): PhaseValidationResult {
        const { strictMode = false } = options;
        const result: PhaseValidationResult = {
            canStart: true,
            errors: [],
            warnings: [],
            blockedBy: [],
            readyToStart: false
        };

        // Vérifier les prérequis de base
        this.validateBasicPrerequisites(phase, result);

        // Vérifier les dépendances entre phases
        this.validatePhaseDependencies(phase, allPhases, result, strictMode);

        // Vérifier les prérequis métier
        this.validateBusinessPrerequisites(phase, allPhases, result);

        // Vérifier les contraintes temporelles
        this.validateTemporalConstraints(phase, allPhases, result);

        // Déterminer si la phase est prête à démarrer
        result.readyToStart = result.canStart && result.errors.length === 0;

        return result;
    }

    /**
     * Valide les prérequis de base d'une phase
     */
    private validateBasicPrerequisites(phase: PhaseChantier, result: PhaseValidationResult): void {
        // Vérifier le statut de la phase
        if (phase.statut === 'TERMINEE') {
            result.errors.push({
                code: 'PHASE_ALREADY_COMPLETED',
                message: 'Cette phase est déjà terminée',
                severity: 'info'
            });
            result.canStart = false;
        }

        if (phase.statut === 'EN_COURS') {
            result.warnings.push({
                code: 'PHASE_ALREADY_STARTED',
                message: 'Cette phase est déjà en cours',
                recommendation: 'Vérifiez l\'avancement actuel'
            });
        }

        // Vérifier les dates
        const today = new Date();
        today.setHours(0, 0, 0, 0);

        if (phase.dateDebutPrevue) {
            const dateDebut = new Date(phase.dateDebutPrevue);
            dateDebut.setHours(0, 0, 0, 0);

            if (dateDebut > today) {
                result.warnings.push({
                    code: 'PHASE_FUTURE_START',
                    message: `Cette phase est prévue pour commencer le ${dateDebut.toLocaleDateString('fr-FR')}`,
                    recommendation: 'Vérifiez si un démarrage anticipé est possible'
                });
            }
        }

        if (phase.dateFinPrevue) {
            const dateFin = new Date(phase.dateFinPrevue);
            dateFin.setHours(0, 0, 0, 0);

            if (dateFin < today) {
                result.warnings.push({
                    code: 'PHASE_OVERDUE',
                    message: 'Cette phase aurait dû être terminée',
                    recommendation: 'Réviser la planification'
                });
            }
        }
    }

    /**
     * Valide les dépendances entre phases
     */
    private validatePhaseDependencies(
        phase: PhaseChantier, 
        allPhases: PhaseChantier[], 
        result: PhaseValidationResult,
        strictMode: boolean
    ): void {
        if (!phase.prerequis || phase.prerequis.length === 0) {
            return;
        }

        const prerequisiteStatuses = this.getPrerequisiteStatuses(phase, allPhases);

        prerequisiteStatuses.forEach(prereq => {
            switch (prereq.status) {
                case 'not_found':
                    result.errors.push({
                        code: 'PREREQUISITE_NOT_FOUND',
                        message: `Prérequis non trouvé: ${prereq.prerequisiteName}`,
                        severity: 'error',
                        prerequisiteId: prereq.prerequisiteId
                    });
                    result.canStart = false;
                    break;

                case 'not_started':
                    if (prereq.isBlocking || strictMode) {
                        result.errors.push({
                            code: 'PREREQUISITE_NOT_STARTED',
                            message: `Prérequis non démarré: ${prereq.prerequisiteName}`,
                            severity: 'error',
                            prerequisiteId: prereq.prerequisiteId
                        });
                        result.blockedBy.push(prereq.prerequisiteName);
                        result.canStart = false;
                    } else {
                        result.warnings.push({
                            code: 'PREREQUISITE_NOT_STARTED_WARNING',
                            message: `Prérequis non démarré: ${prereq.prerequisiteName}`,
                            recommendation: 'Considérez démarrer ce prérequis en parallèle'
                        });
                    }
                    break;

                case 'in_progress':
                    if (prereq.isBlocking || strictMode) {
                        result.warnings.push({
                            code: 'PREREQUISITE_IN_PROGRESS',
                            message: `Prérequis en cours: ${prereq.prerequisiteName}`,
                            recommendation: 'Attendez la fin de cette phase ou vérifiez si un démarrage parallèle est possible'
                        });
                    }
                    break;

                case 'completed':
                    // Tout va bien
                    break;
            }
        });
    }

    /**
     * Valide les prérequis métier spécifiques
     */
    private validateBusinessPrerequisites(
        phase: PhaseChantier, 
        allPhases: PhaseChantier[], 
        result: PhaseValidationResult
    ): void {
        // Règles métier spécifiques au BTP
        this.validateBTPBusinessRules(phase, allPhases, result);

        // Vérifier les compétences requises
        this.validateRequiredSkills(phase, result);

        // Vérifier les ressources disponibles
        this.validateResourceAvailability(phase, result);
    }

    /**
     * Valide les règles métier spécifiques au BTP
     */
    private validateBTPBusinessRules(
        phase: PhaseChantier, 
        allPhases: PhaseChantier[], 
        result: PhaseValidationResult
    ): void {
        const phaseName = phase.nom.toLowerCase();

        // Règles pour la maçonnerie
        if (phaseName.includes('maçonnerie') || phaseName.includes('béton')) {
            const fondations = allPhases.find(p => 
                p.nom.toLowerCase().includes('fondation') || 
                p.nom.toLowerCase().includes('excavation')
            );
            
            if (fondations && fondations.statut !== 'TERMINEE') {
                result.errors.push({
                    code: 'FOUNDATION_NOT_COMPLETED',
                    message: 'Les fondations doivent être terminées avant les travaux de maçonnerie',
                    severity: 'error',
                    phaseId: fondations.id
                });
                result.canStart = false;
                result.blockedBy.push('Fondations');
            }
        }

        // Règles pour l'électricité
        if (phaseName.includes('électric') || phaseName.includes('électro')) {
            const grosOeuvre = allPhases.find(p => 
                p.nom.toLowerCase().includes('gros œuvre') || 
                p.nom.toLowerCase().includes('gros oeuvre') ||
                p.nom.toLowerCase().includes('structure')
            );
            
            if (grosOeuvre && grosOeuvre.statut !== 'TERMINEE') {
                result.warnings.push({
                    code: 'STRUCTURE_NOT_COMPLETED',
                    message: 'Il est recommandé d\'attendre la fin du gros œuvre',
                    recommendation: 'Certains travaux électriques peuvent commencer en parallèle selon les zones'
                });
            }
        }

        // Règles pour la plomberie
        if (phaseName.includes('plomberie') || phaseName.includes('sanitaire')) {
            const cloisons = allPhases.find(p => 
                p.nom.toLowerCase().includes('cloison') || 
                p.nom.toLowerCase().includes('doublage')
            );
            
            if (cloisons && cloisons.statut === 'TERMINEE') {
                result.warnings.push({
                    code: 'PARTITIONS_ALREADY_DONE',
                    message: 'Les cloisons sont déjà terminées - travaux de plomberie plus complexes',
                    recommendation: 'Prévoir des saignées ou passages techniques'
                });
            }
        }

        // Règles pour les finitions
        if (phaseName.includes('peinture') || phaseName.includes('revêtement') || phaseName.includes('carrelage')) {
            const secondOeuvre = allPhases.filter(p => {
                const nom = p.nom.toLowerCase();
                return nom.includes('électric') || nom.includes('plomberie') || nom.includes('chauffage');
            });

            const unfinishedSecondOeuvre = secondOeuvre.filter(p => p.statut !== 'TERMINEE');
            
            if (unfinishedSecondOeuvre.length > 0) {
                result.warnings.push({
                    code: 'SECOND_WORK_NOT_COMPLETED',
                    message: 'Certains travaux de second œuvre ne sont pas terminés',
                    recommendation: 'Terminer électricité, plomberie et chauffage avant les finitions'
                });
            }
        }
    }

    /**
     * Valide les compétences requises
     */
    private validateRequiredSkills(phase: PhaseChantier, result: PhaseValidationResult): void {
        // Cette validation serait étoffée avec une vraie base de données des compétences
        const requiredSkills = this.getRequiredSkillsForPhase(phase);
        
        if (requiredSkills.length > 0) {
            result.warnings.push({
                code: 'SKILLS_REQUIRED',
                message: `Compétences requises: ${requiredSkills.join(', ')}`,
                recommendation: 'Vérifiez la disponibilité des artisans qualifiés'
            });
        }
    }

    /**
     * Valide la disponibilité des ressources
     */
    private validateResourceAvailability(phase: PhaseChantier, result: PhaseValidationResult): void {
        // Vérifications météorologiques pour certaines phases
        if (this.isWeatherSensitivePhase(phase)) {
            const season = this.getCurrentSeason();
            if (season === 'winter') {
                result.warnings.push({
                    code: 'WEATHER_SENSITIVE_WINTER',
                    message: 'Phase sensible aux conditions météorologiques - période hivernale',
                    recommendation: 'Prévoir des protections contre le gel et les intempéries'
                });
            }
        }

        // Vérification des matériaux
        result.warnings.push({
            code: 'MATERIALS_CHECK',
            message: 'Vérifiez la disponibilité des matériaux',
            recommendation: 'Confirmez les livraisons avant le démarrage'
        });
    }

    /**
     * Valide les contraintes temporelles
     */
    private validateTemporalConstraints(
        phase: PhaseChantier, 
        allPhases: PhaseChantier[], 
        result: PhaseValidationResult
    ): void {
        const today = new Date();

        // Vérifier les chevauchements problématiques
        const overlappingPhases = this.findOverlappingPhases(phase, allPhases);
        
        overlappingPhases.forEach(overlapping => {
            if (this.arePhasesMutuallyExclusive(phase, overlapping)) {
                result.errors.push({
                    code: 'PHASE_CONFLICT',
                    message: `Conflit avec la phase: ${overlapping.nom}`,
                    severity: 'error',
                    phaseId: overlapping.id
                });
                result.canStart = false;
            }
        });

        // Vérifier les délais critiques
        if (phase.critique && phase.dateFinPrevue) {
            const dateFin = new Date(phase.dateFinPrevue);
            const diffDays = Math.ceil((dateFin.getTime() - today.getTime()) / (1000 * 60 * 60 * 24));
            
            if (diffDays < 7) {
                result.warnings.push({
                    code: 'CRITICAL_PHASE_URGENT',
                    message: 'Phase critique avec délai serré',
                    recommendation: 'Mobiliser des ressources supplémentaires'
                });
            }
        }
    }

    /**
     * Obtient le statut des prérequis d'une phase
     */
    private getPrerequisiteStatuses(phase: PhaseChantier, allPhases: PhaseChantier[]): PrerequisiteStatus[] {
        if (!phase.prerequis) return [];

        // prerequis is a string, parse it as JSON array or split by comma
        let prerequisIds: string[] = [];
        try {
            prerequisIds = JSON.parse(phase.prerequis);
        } catch {
            prerequisIds = phase.prerequis.split(',').map(id => id.trim()).filter(id => id);
        }

        return prerequisIds.map(prerequisiteId => {
            const prerequisitePhase = allPhases.find(p => p.id === prerequisiteId);

            return {
                prerequisiteId,
                prerequisiteName: prerequisitePhase?.nom || prerequisiteId,
                status: prerequisitePhase ?
                    (prerequisitePhase.statut === 'TERMINEE' ? 'completed' :
                     prerequisitePhase.statut === 'EN_COURS' ? 'in_progress' : 'not_started') :
                    'not_found',
                completionDate: prerequisitePhase?.dateFinReelle ? new Date(prerequisitePhase.dateFinReelle) : undefined,
                isBlocking: this.isBlockingPrerequisite(prerequisiteId, phase)
            };
        });
    }

    /**
     * Détermine si un prérequis est bloquant
     */
    private isBlockingPrerequisite(prerequisiteId: string, phase: PhaseChantier): boolean {
        // Logique pour déterminer si un prérequis est critique/bloquant
        // Basée sur le type de phase et les règles métier
        const criticalPrerequisites = [
            'fondations', 'excavation', 'gros-oeuvre', 'structure'
        ];
        
        return criticalPrerequisites.some(critical => 
            prerequisiteId.toLowerCase().includes(critical)
        );
    }

    /**
     * Obtient les compétences requises pour une phase
     */
    private getRequiredSkillsForPhase(phase: PhaseChantier): string[] {
        const phaseName = phase.nom.toLowerCase();
        const skills: string[] = [];

        if (phaseName.includes('maçonnerie')) skills.push('Maçon');
        if (phaseName.includes('électric')) skills.push('Électricien');
        if (phaseName.includes('plomberie')) skills.push('Plombier');
        if (phaseName.includes('charpente')) skills.push('Charpentier');
        if (phaseName.includes('couverture')) skills.push('Couvreur');
        if (phaseName.includes('peinture')) skills.push('Peintre');
        if (phaseName.includes('carrelage')) skills.push('Carreleur');

        return skills;
    }

    /**
     * Détermine si une phase est sensible aux conditions météorologiques
     */
    private isWeatherSensitivePhase(phase: PhaseChantier): boolean {
        const weatherSensitive = [
            'couverture', 'étanchéité', 'façade', 'maçonnerie extérieure', 
            'terrassement', 'fondations', 'béton'
        ];
        
        return weatherSensitive.some(sensitive => 
            phase.nom.toLowerCase().includes(sensitive)
        );
    }

    /**
     * Obtient la saison actuelle
     */
    private getCurrentSeason(): 'spring' | 'summer' | 'fall' | 'winter' {
        const month = new Date().getMonth() + 1;
        if (month >= 3 && month <= 5) return 'spring';
        if (month >= 6 && month <= 8) return 'summer';
        if (month >= 9 && month <= 11) return 'fall';
        return 'winter';
    }

    /**
     * Trouve les phases qui se chevauchent temporellement
     */
    private findOverlappingPhases(phase: PhaseChantier, allPhases: PhaseChantier[]): PhaseChantier[] {
        if (!phase.dateDebutPrevue || !phase.dateFinPrevue) return [];

        const phaseStart = new Date(phase.dateDebutPrevue);
        const phaseEnd = new Date(phase.dateFinPrevue);

        return allPhases.filter(otherPhase => {
            if (otherPhase.id === phase.id) return false;
            if (!otherPhase.dateDebutPrevue || !otherPhase.dateFinPrevue) return false;

            const otherStart = new Date(otherPhase.dateDebutPrevue);
            const otherEnd = new Date(otherPhase.dateFinPrevue);

            return (phaseStart <= otherEnd && phaseEnd >= otherStart);
        });
    }

    /**
     * Détermine si deux phases sont mutuellement exclusives
     */
    private arePhasesMutuallyExclusive(phase1: PhaseChantier, phase2: PhaseChantier): boolean {
        const exclusiveGroups = [
            ['maçonnerie', 'béton'],
            ['peinture', 'électricité'],
            ['carrelage', 'plomberie']
        ];

        return exclusiveGroups.some(group => {
            const phase1InGroup = group.some(term => phase1.nom.toLowerCase().includes(term));
            const phase2InGroup = group.some(term => phase2.nom.toLowerCase().includes(term));
            return phase1InGroup && phase2InGroup;
        });
    }

    /**
     * Valide l'ensemble d'un planning de phases
     */
    validateProjectSchedule(phases: PhaseChantier[]): {
        isValid: boolean;
        globalErrors: ValidationError[];
        phaseValidations: Map<string, PhaseValidationResult>;
    } {
        const phaseValidations = new Map<string, PhaseValidationResult>();
        const globalErrors: ValidationError[] = [];

        // Valider chaque phase individuellement
        phases.forEach(phase => {
            const validation = this.validatePhaseStart(phase, phases);
            phaseValidations.set(phase.id!, validation);
        });

        // Validations globales
        this.validateGlobalScheduleConstraints(phases, globalErrors);

        const isValid = globalErrors.length === 0 && 
            Array.from(phaseValidations.values()).every(v => v.readyToStart || v.errors.length === 0);

        return {
            isValid,
            globalErrors,
            phaseValidations
        };
    }

    /**
     * Valide les contraintes globales du planning
     */
    private validateGlobalScheduleConstraints(phases: PhaseChantier[], globalErrors: ValidationError[]): void {
        // Vérifier l'ordre logique des phases
        const orderedPhases = phases
            .filter(p => p.ordreExecution !== undefined)
            .sort((a, b) => (a.ordreExecution || 0) - (b.ordreExecution || 0));

        for (let i = 1; i < orderedPhases.length; i++) {
            const currentPhase = orderedPhases[i];
            const previousPhase = orderedPhases[i - 1];

            if (currentPhase.dateDebutPrevue && previousPhase.dateFinPrevue) {
                const currentStart = new Date(currentPhase.dateDebutPrevue);
                const previousEnd = new Date(previousPhase.dateFinPrevue);

                if (currentStart < previousEnd) {
                    globalErrors.push({
                        code: 'SCHEDULE_ORDER_VIOLATION',
                        message: `La phase "${currentPhase.nom}" commence avant la fin de "${previousPhase.nom}"`,
                        severity: 'warning',
                        phaseId: currentPhase.id
                    });
                }
            }
        }

        // Vérifier la durée totale du projet
        if (phases.length > 0) {
            const startDates = phases
                .filter(p => p.dateDebutPrevue)
                .map(p => new Date(p.dateDebutPrevue!));
            const endDates = phases
                .filter(p => p.dateFinPrevue)
                .map(p => new Date(p.dateFinPrevue!));

            if (startDates.length > 0 && endDates.length > 0) {
                const projectStart = new Date(Math.min(...startDates.map(d => d.getTime())));
                const projectEnd = new Date(Math.max(...endDates.map(d => d.getTime())));
                const projectDuration = Math.ceil((projectEnd.getTime() - projectStart.getTime()) / (1000 * 60 * 60 * 24));

                if (projectDuration > 730) { // 2 ans
                    globalErrors.push({
                        code: 'PROJECT_TOO_LONG',
                        message: `Durée du projet très longue: ${projectDuration} jours`,
                        severity: 'warning'
                    });
                }
            }
        }
    }
}

export default new PhaseValidationService();