import ApiService from './ApiService';

/**
 * Service pour les calculs techniques ultra-détaillés BTP
 * Le plus ambitieux système de calculs BTP d'Afrique
 */

// =================== INTERFACES PARAMÈTRES ===================

export interface ParametresCalculBriques {
  surface: number;
  epaisseurMur: number;
  codeBrique: string;
  zoneClimatique: string;
  typeAppareillage: 'DROIT' | 'QUINCONCE' | 'FLAMAND' | 'ANGLAIS';
  jointHorizontal: number;
  jointVertical: number;
  ouvertures: Ouverture[];
}

export interface Ouverture {
  largeur: number;
  hauteur: number;
}

export interface ParametresCalculMortier {
  volumeMaconnerie: number;
  typeMortier: 'POSE_BRIQUES' | 'JOINTOIEMENT' | 'ENDUIT_BASE' | 'ENDUIT_FINITION' | 'STANDARD';
  zoneClimatique: string;
}

export interface ParametresCalculBetonArme {
  volume: number;
  classeBeton: 'C20/25' | 'C25/30' | 'C30/37' | 'C35/45';
  classeExposition: 'XC1' | 'XC3' | 'XC4' | 'XS1' | 'XS3';
  typeOuvrage: 'DALLE' | 'POUTRE' | 'POTEAU' | 'VOILE';
  epaisseur: number;
  zoneClimatique: string;
}

// =================== INTERFACES RÉSULTATS ===================

export interface ResultatCalculBriques {
  nombreBriques: number;
  nombrePalettes: number;
  briquesParM2: number;
  surfaceNette: number;
  mortier: ResultatCalculMortier;
  facteurPerte: number;
  facteurClimatique: number;
  nombreCouches: number;
  recommendationsZone: string[];
}

export interface ResultatCalculMortier {
  volumeTotal: number;
  cimentKg: number;
  sableLitres: number;
  eauLitres: number;
  sacs50kg: number;
}

export interface ResultatCalculBetonArme {
  volume: number;
  cimentKg: number;
  cimentSacs50kg: number;
  sableKg: number;
  sableM3: number;
  graviersKg: number;
  graviersM3: number;
  eauLitres: number;
  acierKgTotal: number;
  repartitionAcier: Record<number, number>; // diamètre -> poids en kg
  enrobage: number;
  dosageAdapte: DosageBeton;
  adaptationsClimatiques: string[];
}

export interface DosageBeton {
  ciment: number; // kg/m³
  eau: number;    // L/m³
  graviers: number; // kg/m³
  sable: number;   // kg/m³
}

export interface DosageBetonInfo {
  usage: string;
  ciment: string;
  resistance: string;
  exposition: string;
}

// =================== CLASSES DE SERVICE ===================

export class CalculsTechniquesService {
  private static readonly BASE_PATH = '/api/v1/calculs-techniques';

  // =================== CALCULS MAÇONNERIE ===================

  /**
   * Calcul ultra-précis quantité briques pour mur
   * Prend en compte dimensions exactes, joints, appareillage, pertes, zone climatique
   */
  static async calculerBriquesMur(params: ParametresCalculBriques): Promise<ResultatCalculBriques> {
    const response = await ApiService.post<ResultatCalculBriques>(
      `${this.BASE_PATH}/briques-mur`,
      params
    );

    return response;
  }

  /**
   * Calcul mortier pour maçonnerie traditionnelle
   */
  static async calculerMortierMaconnerie(params: ParametresCalculMortier): Promise<ResultatCalculMortier> {
    const response = await ApiService.post<ResultatCalculMortier>(
      `${this.BASE_PATH}/mortier-maconnerie`,
      params
    );

    return response;
  }

  /**
   * Estimation rapide briques pour surface donnée
   */
  static async estimationRapideBriques(surface: number, typeBrique: string = 'brique-rouge-15x10x5'): Promise<{
    estimationBasse: number;
    estimationHaute: number;
    estimationMoyenne: number;
    baseCalcul: string;
  }> {
    // Calcul côté client pour estimation rapide
    const briquesParM2Moyen = 67; // Moyenne pour brique 15x10x5cm
    const facteurPerteMoyen = 1.08; // 8% de perte moyenne
    
    const estimationMoyenne = Math.ceil(surface * briquesParM2Moyen * facteurPerteMoyen);
    const estimationBasse = Math.ceil(estimationMoyenne * 0.85);
    const estimationHaute = Math.ceil(estimationMoyenne * 1.25);

    return {
      estimationBasse,
      estimationHaute,
      estimationMoyenne,
      baseCalcul: `Surface: ${surface}m² × ${briquesParM2Moyen} briques/m² × ${facteurPerteMoyen} (pertes)`
    };
  }

  // =================== CALCULS BÉTON ARMÉ ===================

  /**
   * Calcul béton armé avec adaptation climatique africaine
   */
  static async calculerBetonArme(params: ParametresCalculBetonArme): Promise<ResultatCalculBetonArme> {
    const response = await ApiService.post<ResultatCalculBetonArme>(
      `${this.BASE_PATH}/beton-arme`,
      params
    );

    return response;
  }

  /**
   * Récupère les dosages béton standard avec adaptations climatiques
   */
  static async getDosagesBeton(): Promise<{
    dosages: Record<string, DosageBetonInfo>;
    notes: string[];
  }> {
    const response = await ApiService.get<{
      dosages: Record<string, DosageBetonInfo>;
      notes: string[];
    }>(`${this.BASE_PATH}/dosages-beton`);

    return response;
  }

  /**
   * Estimation rapide béton pour volume donné
   */
  static async estimationRapideBeton(volume: number, classeBeton: string = 'C25/30'): Promise<{
    cimentSacs: number;
    sableM3: number;
    graviersM3: number;
    eauLitres: number;
    coutEstime: number;
  }> {
    // Dosages moyens selon classe
    const dosages = {
      'C20/25': { ciment: 300, sable: 1100, graviers: 650, eau: 165 },
      'C25/30': { ciment: 350, sable: 1050, graviers: 600, eau: 175 },
      'C30/37': { ciment: 385, sable: 1000, graviers: 580, eau: 180 },
      'C35/45': { ciment: 420, sable: 950, graviers: 550, eau: 185 }
    };

    const dosage = dosages[classeBeton] || dosages['C25/30'];
    
    const cimentKg = volume * dosage.ciment;
    const cimentSacs = Math.ceil(cimentKg / 50);
    const sableKg = volume * dosage.sable;
    const sableM3 = sableKg / 1600; // densité sable
    const graviersKg = volume * dosage.graviers;
    const graviersM3 = graviersKg / 1500; // densité graviers
    const eauLitres = volume * dosage.eau;

    // Estimation coût (prix moyens Afrique de l'Ouest)
    const coutEstime = (cimentSacs * 8000) + // 8000 FCFA/sac
                      (sableM3 * 25000) +     // 25000 FCFA/m³
                      (graviersM3 * 30000) +  // 30000 FCFA/m³
                      (eauLitres * 2);        // 2 FCFA/L

    return {
      cimentSacs,
      sableM3: Math.ceil(sableM3 * 100) / 100, // 2 décimales
      graviersM3: Math.ceil(graviersM3 * 100) / 100,
      eauLitres,
      coutEstime
    };
  }

  // =================== CALCULS COMPLEXES ===================

  /**
   * Calcul complet d'un mur (briques + mortier + enduit)
   */
  static async calculerMurComplet(params: {
    surface: number;
    epaisseurMur: number;
    codeBrique: string;
    zoneClimatique: string;
    typeAppareillage: string;
    avecEnduit: boolean;
    typeEnduit?: 'CIMENT' | 'CHAUX' | 'PLATRE';
  }): Promise<{
    briques: ResultatCalculBriques;
    enduit?: {
      mortierM3: number;
      cimentKg: number;
      sableKg: number;
      eauLitres: number;
    };
    coutTotal: number;
    tempsTotal: number; // en heures
  }> {
    // Calcul briques
    const paramsB: ParametresCalculBriques = {
      surface: params.surface,
      epaisseurMur: params.epaisseurMur,
      codeBrique: params.codeBrique,
      zoneClimatique: params.zoneClimatique,
      typeAppareillage: params.typeAppareillage as any,
      jointHorizontal: 10, // défaut 10mm
      jointVertical: 10,   // défaut 10mm
      ouvertures: []
    };

    const briques = await this.calculerBriquesMur(paramsB);

    let enduit;
    if (params.avecEnduit) {
      // Calcul enduit (15mm d'épaisseur moyenne)
      const volumeEnduit = params.surface * 0.015; // 1.5cm
      const dosageEnduit = params.typeEnduit === 'CHAUX' ? 250 : 350; // kg/m³
      
      enduit = {
        mortierM3: volumeEnduit,
        cimentKg: volumeEnduit * dosageEnduit,
        sableKg: volumeEnduit * 800, // 800kg sable/m³ mortier
        eauLitres: volumeEnduit * 200 // 200L eau/m³ mortier
      };
    }

    // Estimation coûts et temps
    const coutBriques = briques.nombreBriques * 250; // 250 FCFA/brique
    const coutMortier = briques.mortier.cimentKg * 160; // 160 FCFA/kg ciment
    const coutEnduit = enduit ? enduit.cimentKg * 160 : 0;
    const coutTotal = coutBriques + coutMortier + coutEnduit;

    const tempsBriques = briques.nombreBriques * 3 / 60; // 3min/brique
    const tempsEnduit = params.avecEnduit ? params.surface * 45 / 60 : 0; // 45min/m²
    const tempsTotal = tempsBriques + tempsEnduit;

    return {
      briques,
      enduit,
      coutTotal,
      tempsTotal
    };
  }

  /**
   * Calcul dalle béton complète (béton + armatures + coffrages)
   */
  static async calculerDalleComplete(params: {
    surface: number;
    epaisseur: number;
    classeBeton: string;
    zoneClimatique: string;
    typeArmature: 'LEGERE' | 'NORMALE' | 'RENFORCEE';
    avecCoffrage: boolean;
  }): Promise<{
    beton: ResultatCalculBetonArme;
    coffrage?: {
      planchesM2: number;
      etaisNombre: number;
    };
    coutTotal: number;
    tempsTotal: number;
  }> {
    const volume = params.surface * (params.epaisseur / 100); // épaisseur en cm -> m

    const paramsBA: ParametresCalculBetonArme = {
      volume,
      classeBeton: params.classeBeton as any,
      classeExposition: 'XC3', // défaut intérieur humide
      typeOuvrage: 'DALLE',
      epaisseur: params.epaisseur,
      zoneClimatique: params.zoneClimatique
    };

    const beton = await this.calculerBetonArme(paramsBA);

    let coffrage;
    if (params.avecCoffrage) {
      // Surface coffrante = surface dalle + rives
      const perimetre = 2 * Math.sqrt(params.surface * 4); // approximation carré
      const surfaceCoffrante = params.surface + (perimetre * params.epaisseur / 100);
      
      coffrage = {
        planchesM2: surfaceCoffrante * 1.15, // 15% majoration
        etaisNombre: Math.ceil(params.surface / 2) // 1 étai par 2m²
      };
    }

    // Estimation coûts
    const coutBeton = (beton.cimentSacs50kg * 8000) + 
                     (beton.sableM3.valueOf() * 25000) + 
                     (beton.graviersM3.valueOf() * 30000);
    const coutAcier = beton.acierKgTotal * 1200; // 1200 FCFA/kg acier
    const coutCoffrage = coffrage ? (coffrage.planchesM2 * 5000) + (coffrage.etaisNombre * 15000) : 0;
    const coutTotal = coutBeton + coutAcier + coutCoffrage;

    // Estimation temps
    const tempsBeton = volume * 2; // 2h/m³
    const tempsArmature = beton.acierKgTotal * 0.5; // 30min/kg
    const tempsCoffrage = coffrage ? coffrage.planchesM2 * 0.25 : 0; // 15min/m²
    const tempsTotal = tempsBeton + tempsArmature + tempsCoffrage;

    return {
      beton,
      coffrage,
      coutTotal,
      tempsTotal
    };
  }

  // =================== OUTILS UTILITAIRES ===================

  /**
   * Conversion d'unités de mesure BTP
   */
  static convertirUnites(valeur: number, uniteSource: string, uniteDestination: string): number {
    const conversions: Record<string, Record<string, number>> = {
      'm': { 'cm': 100, 'mm': 1000, 'km': 0.001 },
      'm²': { 'cm²': 10000, 'mm²': 1000000, 'ha': 0.0001 },
      'm³': { 'l': 1000, 'cm³': 1000000, 'mm³': 1000000000 },
      'kg': { 'g': 1000, 't': 0.001, 'quintal': 0.01 },
      'MPa': { 'kPa': 1000, 'Pa': 1000000, 'bar': 10 }
    };

    if (conversions[uniteSource]?.[uniteDestination]) {
      return valeur * conversions[uniteSource][uniteDestination];
    }

    throw new Error(`Conversion non supportée: ${uniteSource} vers ${uniteDestination}`);
  }

  /**
   * Validation des paramètres de calcul
   */
  static validerParametres(type: 'BRIQUES' | 'MORTIER' | 'BETON', params: any): {
    valide: boolean;
    erreurs: string[];
    avertissements: string[];
  } {
    const erreurs: string[] = [];
    const avertissements: string[] = [];

    switch (type) {
      case 'BRIQUES':
        if (!params.surface || params.surface <= 0) erreurs.push('Surface requise et > 0');
        if (!params.epaisseurMur || params.epaisseurMur <= 0) erreurs.push('Épaisseur mur requise et > 0');
        if (!params.codeBrique) erreurs.push('Code brique requis');
        if (!params.zoneClimatique) erreurs.push('Zone climatique requise');
        
        if (params.surface > 1000) avertissements.push('Surface très importante (>1000m²)');
        if (params.epaisseurMur > 30) avertissements.push('Mur très épais (>30cm)');
        break;

      case 'BETON':
        if (!params.volume || params.volume <= 0) erreurs.push('Volume requis et > 0');
        if (!params.classeBeton) erreurs.push('Classe béton requise');
        if (!params.typeOuvrage) erreurs.push('Type ouvrage requis');
        
        if (params.volume > 500) avertissements.push('Volume très important (>500m³)');
        if (params.epaisseur && params.epaisseur < 10) avertissements.push('Épaisseur faible (<10cm)');
        break;
    }

    return {
      valide: erreurs.length === 0,
      erreurs,
      avertissements
    };
  }

  /**
   * Génération de devis détaillé
   */
  static async genererDevis(calculs: {
    briques?: ResultatCalculBriques;
    mortier?: ResultatCalculMortier;
    beton?: ResultatCalculBetonArme;
  }, options?: {
    margeEntreprise?: number; // %
    tva?: number; // %
    delaiExecution?: number; // jours
  }): Promise<{
    lignesDevis: Array<{
      designation: string;
      quantite: number;
      unite: string;
      prixUnitaire: number;
      montantHT: number;
    }>;
    totalHT: number;
    totalTTC: number;
    delaiExecution: number;
  }> {
    const lignesDevis: Array<{
      designation: string;
      quantite: number;
      unite: string;
      prixUnitaire: number;
      montantHT: number;
    }> = [];

    // Ajout lignes selon calculs
    if (calculs.briques) {
      lignesDevis.push({
        designation: 'Briques terre cuite',
        quantite: calculs.briques.nombreBriques,
        unite: 'unité',
        prixUnitaire: 250,
        montantHT: calculs.briques.nombreBriques * 250
      });
    }

    if (calculs.beton) {
      lignesDevis.push({
        designation: 'Ciment Portland CEM I',
        quantite: calculs.beton.cimentSacs50kg,
        unite: 'sac 50kg',
        prixUnitaire: 8000,
        montantHT: calculs.beton.cimentSacs50kg * 8000
      });
    }

    const totalHT = lignesDevis.reduce((sum, ligne) => sum + ligne.montantHT, 0);
    const marge = (options?.margeEntreprise || 20) / 100;
    const tva = (options?.tva || 18) / 100;
    
    const totalAvecMarge = totalHT * (1 + marge);
    const totalTTC = totalAvecMarge * (1 + tva);

    return {
      lignesDevis,
      totalHT: totalAvecMarge,
      totalTTC,
      delaiExecution: options?.delaiExecution || 15
    };
  }
}