/**
 * Service de matching intelligent pour MediFlash SOS+
 * Algorithmes d'optimisation pour assigner pharmacies et livreurs
 */

export interface MatchingCriteria {
  location: { lat: number; lng: number };
  urgency: 'low' | 'medium' | 'high' | 'critical';
  medicineRequirements: MedicineRequirement[];
  maxDistance: number; // km
  preferredDeliveryTime: number; // minutes
  clientProfile?: ClientProfile;
  orderValue?: number;
}

export interface MedicineRequirement {
  name: string;
  quantity: number;
  priority: 'essential' | 'preferred' | 'optional';
  substitutes?: string[]; // Médicaments de substitution acceptables
}

export interface ClientProfile {
  id: string;
  loyaltyTier: 'bronze' | 'silver' | 'gold' | 'platinum';
  previousOrders: number;
  averageRating: number;
  preferredPharmacies: string[];
  languagePreference?: string;
}

export interface PharmacyCandidate {
  id: string;
  name: string;
  location: { lat: number; lng: number };
  distance: number;
  availability: PharmacyAvailability;
  inventory: MedicineInventory[];
  performance: PharmacyPerformance;
  workingHours: WorkingHours;
  capacity: CapacityInfo;
  pricing: PricingInfo;
}

export interface CourierCandidate {
  id: string;
  name: string;
  currentLocation: { lat: number; lng: number };
  distance: number;
  availability: CourierAvailability;
  performance: CourierPerformance;
  vehicle: VehicleInfo;
  workingHours: WorkingHours;
  currentOrders: string[];
  capacity: CapacityInfo;
}

export interface MatchingResult {
  pharmacy: PharmacyMatch | null;
  courier: CourierMatch | null;
  estimatedDeliveryTime: number; // minutes
  totalCost: number;
  confidence: number; // 0-1
  alternatives: MatchingAlternative[];
  reasoning: MatchingReasoning;
}

export interface PharmacyMatch {
  candidate: PharmacyCandidate;
  score: number;
  reasons: string[];
  estimatedPreparationTime: number;
  availableMedicines: MedicineMatch[];
  missingMedicines: string[];
  totalPrice: number;
}

export interface CourierMatch {
  candidate: CourierCandidate;
  score: number;
  reasons: string[];
  estimatedPickupTime: number;
  estimatedDeliveryTime: number;
  route: RouteInfo;
  cost: number;
}

export interface MatchingAlternative {
  pharmacy: PharmacyCandidate;
  courier: CourierCandidate;
  score: number;
  estimatedTime: number;
  cost: number;
  pros: string[];
  cons: string[];
}

export interface MatchingReasoning {
  primaryFactors: string[];
  secondaryFactors: string[];
  tradeoffs: string[];
  recommendations: string[];
}

// Types auxiliaires
interface PharmacyAvailability {
  isOpen: boolean;
  currentCapacity: number;
  maxCapacity: number;
  averageProcessingTime: number;
  lastUpdate: Date;
}

interface MedicineInventory {
  name: string;
  quantity: number;
  unitPrice: number;
  expiryDate: Date;
  lastUpdated: Date;
}

interface PharmacyPerformance {
  rating: number;
  responseTime: number; // minutes moyenne pour accepter
  fulfillmentRate: number; // % commandes complétées avec succès
  accuracy: number; // % commandes sans erreur
  completedOrders: number;
}

interface CourierAvailability {
  isOnline: boolean;
  status: 'available' | 'busy' | 'offline';
  currentOrders: number;
  maxOrders: number;
  lastLocationUpdate: Date;
}

interface CourierPerformance {
  rating: number;
  onTimeRate: number; // % livraisons à temps
  completionRate: number; // % livraisons complétées
  averageDeliveryTime: number;
  totalDeliveries: number;
}

interface VehicleInfo {
  type: 'bicycle' | 'motorcycle' | 'car' | 'walking';
  speed: number; // km/h moyenne
  capacity: number; // nombre de commandes max
}

interface WorkingHours {
  monday: { open: string; close: string; };
  tuesday: { open: string; close: string; };
  wednesday: { open: string; close: string; };
  thursday: { open: string; close: string; };
  friday: { open: string; close: string; };
  saturday: { open: string; close: string; };
  sunday: { open: string; close: string; };
}

interface CapacityInfo {
  current: number;
  maximum: number;
  utilizationRate: number;
}

interface PricingInfo {
  baseFee: number;
  deliveryFee: number;
  urgencyMultiplier: number;
}

interface MedicineMatch {
  requested: string;
  available: string;
  quantity: number;
  isExact: boolean;
  isSubstitute: boolean;
  unitPrice: number;
}

interface RouteInfo {
  distance: number;
  estimatedDuration: number;
  waypoints: { lat: number; lng: number }[];
  trafficFactor: number;
}

export class MatchingService {
  // Poids des critères pour le scoring
  private readonly PHARMACY_WEIGHTS = {
    distance: 0.25,
    availability: 0.20,
    inventory: 0.25,
    performance: 0.15,
    pricing: 0.10,
    urgency: 0.05
  };

  private readonly COURIER_WEIGHTS = {
    distance: 0.30,
    availability: 0.25,
    performance: 0.20,
    capacity: 0.15,
    vehicle: 0.10
  };

  constructor() {}

  /**
   * Trouve la meilleure combinaison pharmacie + livreur
   */
  async findOptimalMatch(criteria: MatchingCriteria): Promise<MatchingResult> {
    try {
      // 1. Trouver les pharmacies candidates
      const pharmacyCandidates = await this.findPharmacyCandidates(criteria);
      
      if (pharmacyCandidates.length === 0) {
        return {
          pharmacy: null,
          courier: null,
          estimatedDeliveryTime: 0,
          totalCost: 0,
          confidence: 0,
          alternatives: [],
          reasoning: {
            primaryFactors: ['Aucune pharmacie disponible dans la zone'],
            secondaryFactors: [],
            tradeoffs: [],
            recommendations: ['Élargir le rayon de recherche', 'Contacter les pharmacies manuellement']
          }
        };
      }

      // 2. Scorer et classer les pharmacies
      const rankedPharmacies = await this.rankPharmacies(pharmacyCandidates, criteria);
      const bestPharmacy = rankedPharmacies[0];

      // 3. Trouver les livreurs pour la meilleure pharmacie
      const courierCandidates = await this.findCourierCandidates({
        ...criteria,
        pickupLocation: bestPharmacy.candidate.location
      });

      // 4. Scorer et choisir le meilleur livreur
      const rankedCouriers = courierCandidates.length > 0 
        ? await this.rankCouriers(courierCandidates, criteria, bestPharmacy.candidate.location)
        : [];

      const bestCourier = rankedCouriers[0] || null;

      // 5. Calculer estimations et alternatives
      const estimatedDeliveryTime = this.calculateTotalDeliveryTime(bestPharmacy, bestCourier);
      const totalCost = this.calculateTotalCost(bestPharmacy, bestCourier, criteria);
      const alternatives = await this.generateAlternatives(rankedPharmacies, rankedCouriers, criteria);
      
      // 6. Générer les raisons du choix
      const reasoning = this.generateReasoning(bestPharmacy, bestCourier, criteria);
      
      // 7. Calculer la confiance dans la recommandation
      const confidence = this.calculateConfidence(bestPharmacy, bestCourier, pharmacyCandidates.length, courierCandidates.length);

      return {
        pharmacy: bestPharmacy,
        courier: bestCourier,
        estimatedDeliveryTime,
        totalCost,
        confidence,
        alternatives,
        reasoning
      };

    } catch (error) {
      console.error('Error in optimal matching:', error);
      throw new Error('Erreur lors de la recherche de correspondance optimale');
    }
  }

  /**
   * Trouve les pharmacies candidates dans un rayon donné
   */
  private async findPharmacyCandidates(criteria: MatchingCriteria): Promise<PharmacyCandidate[]> {
    // En production, interroger la base de données
    // Pour la démonstration, simulation avec données exemple
    
    const mockPharmacies: PharmacyCandidate[] = [
      {
        id: 'pharm_001',
        name: 'Pharmacie Central',
        location: { lat: criteria.location.lat + 0.01, lng: criteria.location.lng + 0.01 },
        distance: 1.2,
        availability: {
          isOpen: true,
          currentCapacity: 3,
          maxCapacity: 10,
          averageProcessingTime: 15,
          lastUpdate: new Date()
        },
        inventory: criteria.medicineRequirements.map(req => ({
          name: req.name,
          quantity: req.quantity + 5,
          unitPrice: 2500,
          expiryDate: new Date(Date.now() + 365 * 24 * 60 * 60 * 1000),
          lastUpdated: new Date()
        })),
        performance: {
          rating: 4.5,
          responseTime: 3,
          fulfillmentRate: 0.95,
          accuracy: 0.98,
          completedOrders: 1250
        },
        workingHours: {
          monday: { open: '08:00', close: '20:00' },
          tuesday: { open: '08:00', close: '20:00' },
          wednesday: { open: '08:00', close: '20:00' },
          thursday: { open: '08:00', close: '20:00' },
          friday: { open: '08:00', close: '20:00' },
          saturday: { open: '08:00', close: '18:00' },
          sunday: { open: '09:00', close: '17:00' }
        },
        capacity: {
          current: 3,
          maximum: 10,
          utilizationRate: 0.3
        },
        pricing: {
          baseFee: 500,
          deliveryFee: 1000,
          urgencyMultiplier: criteria.urgency === 'critical' ? 1.5 : 1.0
        }
      }
    ];

    // Filtrer par distance et disponibilité
    return mockPharmacies.filter(pharmacy => 
      pharmacy.distance <= criteria.maxDistance &&
      pharmacy.availability.isOpen
    );
  }

  /**
   * Classe les pharmacies par score d'adéquation
   */
  private async rankPharmacies(candidates: PharmacyCandidate[], criteria: MatchingCriteria): Promise<PharmacyMatch[]> {
    const matches: PharmacyMatch[] = [];

    for (const candidate of candidates) {
      const score = this.calculatePharmacyScore(candidate, criteria);
      const availableMedicines = this.matchMedicines(candidate.inventory, criteria.medicineRequirements);
      const missingMedicines = this.findMissingMedicines(availableMedicines, criteria.medicineRequirements);
      const totalPrice = this.calculatePharmacyPrice(availableMedicines, candidate.pricing);
      
      const reasons = this.generatePharmacyReasons(candidate, score, criteria);

      matches.push({
        candidate,
        score,
        reasons,
        estimatedPreparationTime: candidate.availability.averageProcessingTime,
        availableMedicines,
        missingMedicines,
        totalPrice
      });
    }

    // Trier par score décroissant
    return matches.sort((a, b) => b.score - a.score);
  }

  /**
   * Calcule le score d'une pharmacie
   */
  private calculatePharmacyScore(pharmacy: PharmacyCandidate, criteria: MatchingCriteria): number {
    let score = 0;

    // Score de distance (inverse de la distance)
    const distanceScore = Math.max(0, 1 - (pharmacy.distance / criteria.maxDistance));
    score += distanceScore * this.PHARMACY_WEIGHTS.distance;

    // Score de disponibilité
    const capacityScore = 1 - pharmacy.capacity.utilizationRate;
    const availabilityScore = pharmacy.availability.isOpen ? capacityScore : 0;
    score += availabilityScore * this.PHARMACY_WEIGHTS.availability;

    // Score d'inventaire
    const inventoryScore = this.calculateInventoryScore(pharmacy.inventory, criteria.medicineRequirements);
    score += inventoryScore * this.PHARMACY_WEIGHTS.inventory;

    // Score de performance
    const performanceScore = (
      pharmacy.performance.rating / 5 +
      pharmacy.performance.fulfillmentRate +
      pharmacy.performance.accuracy +
      Math.min(1, (5 - pharmacy.performance.responseTime) / 5)
    ) / 4;
    score += performanceScore * this.PHARMACY_WEIGHTS.performance;

    // Score de prix (inverse du prix)
    const pricingScore = Math.max(0, 1 - (pharmacy.pricing.baseFee / 5000));
    score += pricingScore * this.PHARMACY_WEIGHTS.pricing;

    // Bonus urgence
    if (criteria.urgency === 'critical' && pharmacy.performance.responseTime < 2) {
      score += 0.1;
    }

    return Math.min(1, Math.max(0, score));
  }

  /**
   * Trouve les livreurs candidates
   */
  private async findCourierCandidates(criteria: MatchingCriteria & { pickupLocation?: { lat: number; lng: number } }): Promise<CourierCandidate[]> {
    // Simulation avec données exemple
    const mockCouriers: CourierCandidate[] = [
      {
        id: 'courier_001',
        name: 'Ahmed Diallo',
        currentLocation: { 
          lat: criteria.pickupLocation?.lat || criteria.location.lat + 0.005, 
          lng: criteria.pickupLocation?.lng || criteria.location.lng + 0.005 
        },
        distance: 0.8,
        availability: {
          isOnline: true,
          status: 'available',
          currentOrders: 1,
          maxOrders: 3,
          lastLocationUpdate: new Date()
        },
        performance: {
          rating: 4.7,
          onTimeRate: 0.94,
          completionRate: 0.98,
          averageDeliveryTime: 25,
          totalDeliveries: 340
        },
        vehicle: {
          type: 'motorcycle',
          speed: 35,
          capacity: 3
        },
        workingHours: {
          monday: { open: '07:00', close: '22:00' },
          tuesday: { open: '07:00', close: '22:00' },
          wednesday: { open: '07:00', close: '22:00' },
          thursday: { open: '07:00', close: '22:00' },
          friday: { open: '07:00', close: '22:00' },
          saturday: { open: '08:00', close: '20:00' },
          sunday: { open: '09:00', close: '19:00' }
        },
        currentOrders: ['order_123'],
        capacity: {
          current: 1,
          maximum: 3,
          utilizationRate: 0.33
        }
      }
    ];

    return mockCouriers.filter(courier => 
      courier.availability.status === 'available' &&
      courier.capacity.current < courier.capacity.maximum
    );
  }

  /**
   * Classe les livreurs par score
   */
  private async rankCouriers(
    candidates: CourierCandidate[], 
    criteria: MatchingCriteria, 
    pickupLocation: { lat: number; lng: number }
  ): Promise<CourierMatch[]> {
    const matches: CourierMatch[] = [];

    for (const candidate of candidates) {
      const score = this.calculateCourierScore(candidate, criteria, pickupLocation);
      const route = this.calculateRoute(candidate.currentLocation, pickupLocation, criteria.location);
      const estimatedPickupTime = this.calculatePickupTime(candidate, pickupLocation);
      const estimatedDeliveryTime = this.calculateDeliveryTime(route, candidate.vehicle);
      const cost = this.calculateDeliveryCost(route.distance, criteria.urgency);
      const reasons = this.generateCourierReasons(candidate, score, criteria);

      matches.push({
        candidate,
        score,
        reasons,
        estimatedPickupTime,
        estimatedDeliveryTime,
        route,
        cost
      });
    }

    return matches.sort((a, b) => b.score - a.score);
  }

  /**
   * Méthodes utilitaires
   */

  private calculateInventoryScore(inventory: MedicineInventory[], requirements: MedicineRequirement[]): number {
    let totalScore = 0;
    let totalWeight = 0;

    for (const req of requirements) {
      const weight = req.priority === 'essential' ? 3 : req.priority === 'preferred' ? 2 : 1;
      const available = inventory.find(item => item.name === req.name);
      
      if (available && available.quantity >= req.quantity) {
        totalScore += weight;
      }
      totalWeight += weight;
    }

    return totalWeight > 0 ? totalScore / totalWeight : 0;
  }

  private matchMedicines(inventory: MedicineInventory[], requirements: MedicineRequirement[]): MedicineMatch[] {
    return requirements.map(req => {
      const available = inventory.find(item => item.name === req.name);
      
      return {
        requested: req.name,
        available: available?.name || req.name,
        quantity: Math.min(req.quantity, available?.quantity || 0),
        isExact: !!available && available.quantity >= req.quantity,
        isSubstitute: false,
        unitPrice: available?.unitPrice || 0
      };
    });
  }

  private findMissingMedicines(available: MedicineMatch[], requirements: MedicineRequirement[]): string[] {
    return requirements
      .filter(req => !available.find(a => a.requested === req.name && a.isExact))
      .map(req => req.name);
  }

  private calculatePharmacyPrice(medicines: MedicineMatch[], pricing: PricingInfo): number {
    const medicineTotal = medicines.reduce((sum, med) => sum + (med.unitPrice * med.quantity), 0);
    return medicineTotal + pricing.baseFee;
  }

  private calculateCourierScore(courier: CourierCandidate, criteria: MatchingCriteria, pickupLocation: { lat: number; lng: number }): number {
    let score = 0;

    // Score de distance
    const pickupDistance = this.calculateDistance(courier.currentLocation, pickupLocation);
    const distanceScore = Math.max(0, 1 - (pickupDistance / 10)); // 10km max
    score += distanceScore * this.COURIER_WEIGHTS.distance;

    // Score de disponibilité
    const availabilityScore = 1 - courier.capacity.utilizationRate;
    score += availabilityScore * this.COURIER_WEIGHTS.availability;

    // Score de performance
    const performanceScore = (
      courier.performance.rating / 5 +
      courier.performance.onTimeRate +
      courier.performance.completionRate
    ) / 3;
    score += performanceScore * this.COURIER_WEIGHTS.performance;

    // Score de capacité
    const capacityScore = (courier.capacity.maximum - courier.capacity.current) / courier.capacity.maximum;
    score += capacityScore * this.COURIER_WEIGHTS.capacity;

    // Score de véhicule
    const vehicleScore = this.getVehicleScore(courier.vehicle.type, criteria.urgency);
    score += vehicleScore * this.COURIER_WEIGHTS.vehicle;

    return Math.min(1, Math.max(0, score));
  }

  private calculateDistance(point1: { lat: number; lng: number }, point2: { lat: number; lng: number }): number {
    const R = 6371; // Rayon de la Terre en km
    const dLat = (point2.lat - point1.lat) * Math.PI / 180;
    const dLon = (point2.lng - point1.lng) * Math.PI / 180;
    const a = Math.sin(dLat/2) * Math.sin(dLat/2) +
              Math.cos(point1.lat * Math.PI / 180) * Math.cos(point2.lat * Math.PI / 180) *
              Math.sin(dLon/2) * Math.sin(dLon/2);
    return R * 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
  }

  private calculateRoute(from: { lat: number; lng: number }, pickup: { lat: number; lng: number }, delivery: { lat: number; lng: number }): RouteInfo {
    const pickupDistance = this.calculateDistance(from, pickup);
    const deliveryDistance = this.calculateDistance(pickup, delivery);
    const totalDistance = pickupDistance + deliveryDistance;
    
    return {
      distance: totalDistance,
      estimatedDuration: (totalDistance / 30) * 60, // 30 km/h moyenne
      waypoints: [from, pickup, delivery],
      trafficFactor: this.getTrafficFactor()
    };
  }

  private getTrafficFactor(): number {
    const hour = new Date().getHours();
    if (hour >= 7 && hour <= 9) return 1.4; // Rush hour matin
    if (hour >= 17 && hour <= 19) return 1.5; // Rush hour soir
    return 1.1; // Normal
  }

  private getVehicleScore(vehicleType: string, urgency: string): number {
    const scores = {
      motorcycle: { critical: 1.0, high: 0.9, medium: 0.8, low: 0.7 },
      bicycle: { critical: 0.6, high: 0.7, medium: 0.8, low: 0.9 },
      car: { critical: 0.8, high: 0.8, medium: 0.7, low: 0.6 },
      walking: { critical: 0.2, high: 0.3, medium: 0.4, low: 0.5 }
    };

    return scores[vehicleType as keyof typeof scores]?.[urgency as keyof typeof scores['motorcycle']] || 0.5;
  }

  private calculateTotalDeliveryTime(pharmacy: PharmacyMatch, courier: CourierMatch | null): number {
    const preparationTime = pharmacy.estimatedPreparationTime;
    const deliveryTime = courier?.estimatedDeliveryTime || 60; // 60 min par défaut si pas de livreur
    return preparationTime + deliveryTime;
  }

  private calculateTotalCost(pharmacy: PharmacyMatch, courier: CourierMatch | null, criteria: MatchingCriteria): number {
    const pharmacyCost = pharmacy.totalPrice;
    const deliveryCost = courier?.cost || 2000; // 2000 FCFA par défaut
    return pharmacyCost + deliveryCost;
  }

  private calculatePickupTime(courier: CourierCandidate, pickupLocation: { lat: number; lng: number }): number {
    const distance = this.calculateDistance(courier.currentLocation, pickupLocation);
    return (distance / courier.vehicle.speed) * 60; // en minutes
  }

  private calculateDeliveryTime(route: RouteInfo, vehicle: VehicleInfo): number {
    return (route.distance / vehicle.speed) * 60 * route.trafficFactor;
  }

  private calculateDeliveryCost(distance: number, urgency: string): number {
    const baseCost = 1000; // 1000 FCFA de base
    const distanceCost = distance * 200; // 200 FCFA par km
    const urgencyMultiplier = urgency === 'critical' ? 1.5 : urgency === 'high' ? 1.2 : 1.0;
    
    return (baseCost + distanceCost) * urgencyMultiplier;
  }

  private generatePharmacyReasons(pharmacy: PharmacyCandidate, score: number, criteria: MatchingCriteria): string[] {
    const reasons: string[] = [];
    
    if (pharmacy.distance < 2) reasons.push('Très proche de votre position');
    if (pharmacy.performance.rating > 4.5) reasons.push('Excellente réputation');
    if (pharmacy.performance.responseTime < 3) reasons.push('Réponse très rapide');
    if (pharmacy.capacity.utilizationRate < 0.5) reasons.push('Disponible immédiatement');
    
    return reasons;
  }

  private generateCourierReasons(courier: CourierCandidate, score: number, criteria: MatchingCriteria): string[] {
    const reasons: string[] = [];
    
    if (courier.distance < 1) reasons.push('Très proche pour la récupération');
    if (courier.performance.rating > 4.5) reasons.push('Livreur très bien noté');
    if (courier.performance.onTimeRate > 0.9) reasons.push('Toujours ponctuel');
    if (courier.vehicle.type === 'motorcycle') reasons.push('Véhicule rapide');
    
    return reasons;
  }

  private async generateAlternatives(
    pharmacies: PharmacyMatch[], 
    couriers: CourierMatch[], 
    criteria: MatchingCriteria
  ): Promise<MatchingAlternative[]> {
    const alternatives: MatchingAlternative[] = [];
    
    // Générer jusqu'à 3 alternatives
    for (let i = 1; i < Math.min(pharmacies.length, 4); i++) {
      const altPharmacy = pharmacies[i];
      const altCourier = couriers[Math.min(i, couriers.length - 1)];
      
      if (altPharmacy && altCourier) {
        alternatives.push({
          pharmacy: altPharmacy.candidate,
          courier: altCourier.candidate,
          score: (altPharmacy.score + altCourier.score) / 2,
          estimatedTime: altPharmacy.estimatedPreparationTime + altCourier.estimatedDeliveryTime,
          cost: altPharmacy.totalPrice + altCourier.cost,
          pros: [...altPharmacy.reasons.slice(0, 2), ...altCourier.reasons.slice(0, 2)],
          cons: altPharmacy.candidate.distance > 3 ? ['Plus éloigné'] : []
        });
      }
    }
    
    return alternatives;
  }

  private generateReasoning(pharmacy: PharmacyMatch | null, courier: CourierMatch | null, criteria: MatchingCriteria): MatchingReasoning {
    const reasoning: MatchingReasoning = {
      primaryFactors: [],
      secondaryFactors: [],
      tradeoffs: [],
      recommendations: []
    };

    if (pharmacy) {
      reasoning.primaryFactors.push(...pharmacy.reasons.slice(0, 2));
      if (pharmacy.missingMedicines.length > 0) {
        reasoning.tradeoffs.push(`Médicaments manquants: ${pharmacy.missingMedicines.join(', ')}`);
      }
    }

    if (courier) {
      reasoning.primaryFactors.push(...courier.reasons.slice(0, 2));
    }

    reasoning.recommendations.push('Confirmez rapidement pour garantir la disponibilité');
    if (criteria.urgency === 'critical') {
      reasoning.recommendations.push('Contactez directement la pharmacie pour accélérer');
    }

    return reasoning;
  }

  private calculateConfidence(
    pharmacy: PharmacyMatch | null, 
    courier: CourierMatch | null, 
    pharmacyCount: number, 
    courierCount: number
  ): number {
    let confidence = 0;

    // Score de base selon la disponibilité
    if (pharmacy && courier) {
      confidence = (pharmacy.score + courier.score) / 2;
    } else if (pharmacy) {
      confidence = pharmacy.score * 0.7; // Réduit car pas de livreur
    } else {
      confidence = 0.1; // Très faible si rien trouvé
    }

    // Bonus selon le nombre d'options
    const optionsBonus = Math.min(0.2, (pharmacyCount + courierCount) * 0.02);
    confidence += optionsBonus;

    return Math.min(1, Math.max(0, confidence));
  }
}

export const matchingService = new MatchingService();