`).join("");
}
function selectedServices(){
return [...document.querySelectorAll('#checks input[type="checkbox"]:checked')].map(x=>x.value);
}
function typeCoefficient(){
return {"Appartement":1,"Maison":1.08,"Local professionnel":1.25,"Immeuble entier":1.60}[val("type")]||1;
}
function surfaceCoefficient(){
const a=num("surface");
if(a<=50)return .92;if(a<=100)return 1;if(a<=150)return 1.12;if(a<=250)return 1.25;if(a<=500)return 1.42;return 1.65;
}
function accessCoefficient(){
return {"normal":1,"parking":1.04,"stairs":1.07,"occupied":1.10}[val("access")]||1;
}
function urgencyCoefficient(){
return {"standard":1,"fast":1.08,"urgent":1.15}[val("urgency")]||1;
}
function packRate(count){
if(count>=7)return .17;if(count>=5)return .13;if(count>=3)return .08;if(count>=2)return .04;return 0;
}
function formatDuration(minutes){
const m=Math.max(0,Math.round(minutes));
const h=Math.floor(m/60),r=m%60;
return h ? `${h} h ${String(r).padStart(2,"0")}` : `${r} min`;
}
function compute(){
const services=selectedServices(),vat=num("vat")||1.2;
let avgHT=0,lowHT=0,highHT=0,baseMinutes=0;
services.forEach(s=>{
avgHT+=MARKET[s].avg;lowHT+=MARKET[s].low;highHT+=MARKET[s].high;baseMinutes+=MARKET[s].time;
});
const propertyCoef=typeCoefficient()*surfaceCoefficient()*accessCoefficient()*urgencyCoefficient();
const adjustedHT=avgHT*propertyCoef;
const propertyAdjHT=adjustedHT-avgHT;
const distance=num("distance"),travelMin=num("travelTime");
const includedKm=num("includedKm"),includedMinutes=num("includedMinutes");
const excessRoundKm=Math.max(0,(distance-includedKm)*2);
const excessRoundMinutes=Math.max(0,(travelMin-includedMinutes)*2);
const kmCostTTC=excessRoundKm*(num("kmRate")||.65);
const timeCostTTC=(excessRoundMinutes/60)*(num("travelHourly")||42);
// Évite de facturer intégralement deux fois le même déplacement.
const travelTTC=Math.max(kmCostTTC,timeCostTTC);
const discountRate=packRate(services.length);
const discountHT=adjustedHT*discountRate;
const totalTTC=Math.max(0,(adjustedHT-discountHT)*vat+travelTTC);
const surfaceTimeCoef=Math.max(.85,Math.min(1.75,surfaceCoefficient()));
const typeTimeCoef=val("type")==="Immeuble entier"?1.35:val("type")==="Local professionnel"?1.18:1;
const siteMinutes=Math.round(baseMinutes*surfaceTimeCoef*typeTimeCoef*accessCoefficient());
const reportMinutes=Math.round(siteMinutes*.28);
const roundTravelMinutes=travelMin*2;
const totalMinutes=siteMinutes+reportMinutes+roundTravelMinutes;
const rangePct=(num("rangePercent")||7)/100;
const estimateLow=Math.round(totalTTC*(1-rangePct)/5)*5;
const estimateHigh=Math.round(totalTTC*(1+rangePct)/5)*5;
const marketLowTTC=lowHT*vat;
const marketHighTTC=highHT*vat;
const marketPosition=marketHighTTC>marketLowTTC
?Math.max(0,Math.min(100,((totalTTC-marketLowTTC)/(marketHighTTC-marketLowTTC))*100))
:50;
return {services,avgHT,lowHT,highHT,vat,propertyAdjHT,travelTTC,discountHT,totalTTC,
estimateLow,estimateHigh,siteMinutes,reportMinutes,roundTravelMinutes,totalMinutes,
marketLowTTC,marketHighTTC,marketPosition};
}
function showResult(){
const r=compute();
document.getElementById("diagnosticList").innerHTML=r.services.length
?r.services.map(s=>`
${LABELS[s]}${Math.round(MARKET[s].avg*r.vat)} € moy.`).join("")
:"
Aucun diagnostic sélectionné—";
document.getElementById("estimatedPrice").textContent=`${Math.round(r.totalTTC)} €`;
document.getElementById("estimatedRange").textContent=`Fourchette conseillée : ${r.estimateLow} à ${r.estimateHigh} € TTC`;
document.getElementById("siteTime").textContent=formatDuration(r.siteMinutes);
document.getElementById("roundTravel").textContent=formatDuration(r.roundTravelMinutes);
document.getElementById("totalTime").textContent=formatDuration(r.totalMinutes);
document.getElementById("basePrice").textContent=`${Math.round(r.avgHT*r.vat)} €`;
document.getElementById("propertyAdjustment").textContent=`${r.propertyAdjHT>=0?"+":""}${Math.round(r.propertyAdjHT*r.vat)} €`;
document.getElementById("travelAdjustment").textContent=`${r.travelTTC>0?"+":""}${Math.round(r.travelTTC)} €`;
document.getElementById("packDiscount").textContent=`-${Math.round(r.discountHT*r.vat)} €`;
document.getElementById("marketDot").style.left=`${r.marketPosition}%`;
let position="dans la moyenne du marché";
if(r.marketPosition<33)position="dans la partie basse du marché";
else if(r.marketPosition>67)position="dans la partie haute du marché";
document.getElementById("marketText").textContent=
`Pour cette combinaison de diagnostics, les repères étudiés se situent approximativement entre ${Math.round(r.marketLowTTC)} € et ${Math.round(r.marketHighTTC)} € TTC avant ajustements. L'estimation Facility Diagnostic se place ${position}.`;
buildMail(r);
goToStep(5);
}
function buildMail(r){
const body=`Bonjour,
Je souhaite recevoir un devis personnalisé Facility Diagnostic.
Projet : ${project()}
Type de bien : ${val("type")}
Surface : ${val("surface")} m²
Pièces : ${val("rooms")}
Code postal : ${val("cp")||"Non renseigné"}
Distance aller estimée depuis Vélizy : ${val("distance")} km
Temps de trajet aller : ${val("travelTime")} minutes
Diagnostics estimés :
${r.services.map(s=>"- "+LABELS[s]).join("\n")}
Estimation affichée : ${Math.round(r.totalTTC)} € TTC
Fourchette indicative : ${r.estimateLow} à ${r.estimateHigh} € TTC
Temps total estimé de mission : ${formatDuration(r.totalMinutes)}
Cette estimation est indicative et doit être confirmée après vérification du bien et des documents.
Merci de me recontacter.
Cordialement,`;
document.getElementById("requestButton").href=
`mailto:contact@facility-diagnostic.fr?subject=${encodeURIComponent("Demande de devis — "+project())}&body=${encodeURIComponent(body)}`;
}
function nextStep(){
if(currentStep===1 && num("surface")<=0){alert("Merci d’indiquer une surface valide.");return}
if(currentStep===4){showResult();return}
if(currentStep===3)renderChecks();
goToStep(currentStep+1);
}
function prevStep(){goToStep(currentStep-1)}
function goToStep(n){
currentStep=Math.max(1,Math.min(5,n));
document.querySelectorAll(".step").forEach(s=>s.classList.toggle("active",Number(s.dataset.step)===currentStep));
document.getElementById("progressBar").style.width=`${currentStep*20}%`;
document.getElementById("app").scrollIntoView({behavior:"smooth",block:"start"});
}
goToStep(1);