import { PRICES, PUMP_TRUCK_FEES, CONSTRAINTS, COVERAGE_AREAS } from "./constants" export interface CalculationInput { area: number // m² height: number // cm postalCode: string distance: number // km (round trip) } export interface CalculationDetails { // Input values area: number height: number postalCode: string distance: number // Calculated values insulationThickness: number // cm insulationVolume: number // m³ compoundWeight: number // kg // Component prices insulation: number floorHeating: number syntheticNet: number selfLevelingCompound: number pumpTruckFee: number startFee: number // Subtotals subtotal: number coveringFee: number wasteFee: number totalFees: number // Transport transport: number bridgeFee: number // Totals totalExclVat: number vat: number totalInclVat: number } export function calculateInsulation(area: number, height: number): { thickness: number volume: number price: number } { const thickness = Math.max(0, height - CONSTRAINTS.CONCRETE_THICKNESS) const volume = area * (thickness / 100) const price = thickness > 0 ? volume * PRICES.INSULATION_TOTAL : area * PRICES.SIMPLE_LABOR return { thickness, volume, price } } export function calculatePumpTruckFee(weight: number): number { const tier = PUMP_TRUCK_FEES.find((tier) => weight > tier.minWeight) return tier?.fee ?? PUMP_TRUCK_FEES[PUMP_TRUCK_FEES.length - 1].fee } export function getBridgeFee(postalCode: string): number { const postalNumber = parseInt(postalCode) for (const area of Object.values(COVERAGE_AREAS)) { if (postalNumber >= area.start && postalNumber <= area.end) { return area.bridgeFee } } return 0 } export function calculatePrice(input: CalculationInput): CalculationDetails { const { area, height, postalCode, distance } = input // Step 1: Calculate derived values const insulation = calculateInsulation(area, height) const compoundWeight = area * PRICES.COMPOUND_WEIGHT_PER_M2 // Step 2: Calculate components const floorHeating = area * PRICES.FLOOR_HEATING_TOTAL const syntheticNet = area * PRICES.SYNTHETIC_NET_TOTAL const selfLevelingCompound = area * PRICES.SELF_LEVELING_COMPOUND const pumpTruckFee = calculatePumpTruckFee(compoundWeight) const startFee = PRICES.START_FEE // Step 3: Calculate subtotal const subtotal = insulation.price + floorHeating + syntheticNet + selfLevelingCompound + pumpTruckFee + startFee // Step 4: Calculate percentage fees const coveringFee = subtotal * PRICES.COVERING_PERCENTAGE const wasteFee = subtotal * PRICES.WASTE_PERCENTAGE const totalFees = coveringFee + wasteFee // Step 5: Calculate transport const transport = distance * PRICES.TRANSPORT_PER_KM const bridgeFee = getBridgeFee(postalCode) // Step 6: Calculate totals const totalExclVat = subtotal + totalFees + transport + bridgeFee const vat = totalExclVat * PRICES.VAT const totalInclVat = totalExclVat * (1 + PRICES.VAT) return { // Input values area, height, postalCode, distance, // Calculated values insulationThickness: insulation.thickness, insulationVolume: insulation.volume, compoundWeight, // Component prices insulation: insulation.price, floorHeating, syntheticNet, selfLevelingCompound, pumpTruckFee, startFee, // Subtotals subtotal, coveringFee, wasteFee, totalFees, // Transport transport, bridgeFee, // Totals totalExclVat, vat, totalInclVat, } } export function formatPrice(price: number): string { return new Intl.NumberFormat("da-DK", { style: "currency", currency: "DKK", minimumFractionDigits: 0, maximumFractionDigits: 0, }).format(price) } export function formatEstimate(price: number): string { // Round to nearest 500 const rounded = Math.round(price / 500) * 500 return `Ca. ${formatPrice(rounded)}` }