/**
 * Solar Calculator Main Logic
 * Handles all ROI calculations, energy production, and financial modeling
 */
(() => {
    'use strict';

    // ========= DEBUG LOGGING FLAG =========
    // Set keiste_log = 1 to enable comprehensive calculation logging
    let keiste_log = 0;

    // ========= 1) CONSTANTS & DEFAULTS =========
    // Calendar
    const DAYS_IN_YR = 365.4;
    const MONTHS_IN_YR = 12.3;
    const HOURS_IN_DAY = 24;

    // Financial - will be set from PHP config
    const CORPORATION_TAX = 0.125;        // 12.5%
    let CURRENCY_SYMBOL = '$';  // Default, will be overridden by config
    // Grant settings are now building-type-specific, resolved dynamically
    const LOAN_APR_DEFAULT = 0.07;        // 7% APR
    const FEED_IN_TARIFF_DEFAULT = 0.21;  // $/kWh
    const COMPOUND_7_YRS = 1.07;          // coefficient @5% over 7years
    let ANNUAL_INCREASE = 0.05;           // 5% bill increase - will be set from config
    const SOLAR_PANEL_DEGRADATION = 0.005;// 0.5%/yr
    const LENGTH_OF_PAYBACK = 7;          // loan length, years (used when needed)

    // Energy
    const PANEL_POWER_W = 400;            // W per panel (kWp = panels*0.4)
    const YRS_OF_SYSTEM = 25;
    // CO2 coefficient: tonnes CO2 avoided per kWh generated.
    // Typical grid factor ~400 g CO2/kWh => 0.0004 tonnes/kWh
    const CO2_COEFFICIENT_TONNES = 0.0004;  // tonnes per kWh
    const DAY_POWER_AVG = 1.85;           // kWh/day per 400W panel on average in Ireland

    // UI defaults
    const DEFAULT_PANELS = 0;
    const DEFAULT_EXPORT_PERCENT = 0.10;   // 10% of production exported
    const DEFAULT_RETAIL_RATE = 0.17;     // $/kWh – sensible default if blank
    const DEFAULT_FEED_IN_TARIFF = FEED_IN_TARIFF_DEFAULT;
    const DEFAULT_APR = LOAN_APR_DEFAULT;

    // ========= 2) HELPERS =========
    const byId = id => document.getElementById(id);
    const num = v => {
        if (v === null || v === undefined) return 0;
        const n = typeof v === 'number' ? v : parseFloat(String(v).replace(/[^\d.\-]/g, ''));
        return Number.isFinite(n) ? n : 0;
    };
    const clamp = (x, lo, hi) => Math.min(Math.max(x, lo), hi);

    function fmtEuro(x) {
        try { return CURRENCY_SYMBOL + Math.round(x).toLocaleString('en-IE'); }
        catch { return `${CURRENCY_SYMBOL}${Math.round(x).toLocaleString('en-IE')}`; }
    }
    function fmtNum(x, digits = 2) {
        return Number(x || 0).toLocaleString('en-IE', { maximumFractionDigits: digits });
    }

    // parse solar panel configurations from the DOM tables and normalize fields
    const parsedSolarConfigs = [];
    const parseNumber = (s) => {
        if (s === null || s === undefined) return 0;
        const str = String(s).trim();
        if (!str) return 0;
        // Remove non-numeric except dot and minus, but also handle comma as thousands sep
        const cleaned = str.replace(/,/g, '').replace(/[^0-9.\-]/g, '');
        const n = parseFloat(cleaned);
        return Number.isFinite(n) ? n : 0;
    };

    Array.from(document.getElementsByClassName('table-striped')).forEach(table => {
        try {
            const cfg = { panelsCount: 0, yearlyEnergyDcKwh: 0 };
            const tbody = table.querySelector('tbody');
            if (!tbody) return;
            const rows = tbody.querySelectorAll('tr');
            rows.forEach(row => {
                const cells = row.querySelectorAll('td');
                if (cells.length < 2) return;
                const key = cells[0].innerText.trim().toLowerCase();
                const value = cells[1].innerText.trim();
                if (key.includes('panel')) {
                    cfg.panelsCount = parseInt(parseNumber(value)) || cfg.panelsCount;
                } else if (key.includes('energy') || key.includes('annual')) {
                    cfg.yearlyEnergyDcKwh = parseNumber(value) || cfg.yearlyEnergyDcKwh;
                } else if (key.includes('kwh')) {
                    cfg.yearlyEnergyDcKwh = parseNumber(value) || cfg.yearlyEnergyDcKwh;
                } else {
                    // store raw fallback for any other key
                    cfg[key] = value;
                }
            });
            // only push cfgs that have at least a panels count or energy estimate
            if ((cfg.panelsCount && cfg.panelsCount > 0) || (cfg.yearlyEnergyDcKwh && cfg.yearlyEnergyDcKwh > 0)) {
                parsedSolarConfigs.push(cfg);
            }
        } catch (e) {
            // ignore malformed tables
        }
    });

    // expose parsed configs for debugging / fallback
    window.__parsedSolarConfigs = parsedSolarConfigs;

    // ========= 3) COST MODEL =========
    /**
     * Estimate total installed cost for solar system in Ireland.
     * @param {number} panels - number of solar panels (each assumed 400 W)
     * @param {number} batteryKWh - optional battery size in kWh
     * @param {boolean} includeDiverter - whether to include a diverter ($550)
     * @returns {number} total cost ($)
     */
    function estimateSolarCost(panels, batteryKWh = 0, includeDiverter = true) {
        const panelWatt = 400;              // average panel size
        // Resolve cost per kWp from admin-configured values using building type
        const getCostPerKwP = () => {
            try {
                const cfg = window.KSRAD_CalcConfig || {};
                const costs = cfg.systemCosts || {};
                // Get building type from dropdown
                const btEl = document.getElementById('userBuildingType');
                const buildingType = (btEl && btEl.value) ? btEl.value.trim() : 'Residential';
                
                // Use the building type's cost directly
                if (typeof costs[buildingType] === 'number' && costs[buildingType] > 0) {
                    return Number(costs[buildingType]);
                }
                
                // Fallback: default cost
                return 1200;
            } catch (e) {
                return 1200;
            }
        };
        const costPerKwP = getCostPerKwP();
        const systemKwP = (panels * panelWatt) / 1000;
        const batteryCostPerKWh = 500;      // $/kWh installed
        const diverterCost = 550;           // one-off
        const panelCost = systemKwP * costPerKwP;
        const batteryCost = batteryKWh * batteryCostPerKWh;
        // Only include diverter cost when at least one panel is selected.
        // This prevents a default $550 cost appearing when panels = 0.
        const diverter = includeDiverter && panels > 0 ? diverterCost : 0;
        return panelCost + batteryCost + diverter;
    }

    // ========= 4) CORE CALCULATIONS =========
    function readInputs() {
        // sliders / checkboxes
        const inclGrant = !!(byId('inclGrant')?.checked);
        const inclACA = !!(byId('inclACA')?.checked);
        const inclLoan = !!(byId('inclLoan')?.checked);

        const panelCountEl = byId('panelCount');
        const panels = panelCountEl ? clamp(num(panelCountEl.value), 0, 10000) : DEFAULT_PANELS;

        // key text inputs
        const exportRate = (() => {
            // exportRate is the % of production exported (from admin settings or default 10%)
            const cfg = window.KSRAD_CalcConfig || {};
            const rate = cfg.defaultExportRate;
            if (typeof rate === 'number' && rate > 0) {
                return clamp(rate, 0, 1);
            }
            return DEFAULT_EXPORT_PERCENT; // 0.10 = 10% exported
        })();

        const electricityRate = (() => {
            const val = byId('electricityRate')?.value;
            const r = num(val);
            return r > 0 ? r : DEFAULT_RETAIL_RATE;
        })();

        const feedInTariff = FEED_IN_TARIFF_DEFAULT; // can be extended to be editable if needed
        // Allow user-specified loan APR if there's an input (id=loanApr), otherwise fall back to default
        const parsedLoanApr = (() => {
            const v = byId('loanApr')?.value;
            const n = Number.parseFloat(String(v || '').replace(/[^0-9.\-]/g, ''));
            return Number.isFinite(n) && n > 0 ? n : LOAN_APR_DEFAULT;
        })();
        // APR to use for loan calculations (0 if loan not selected)
        const APR = inclLoan ? parsedLoanApr : 0;

        // bill (required to run figs)
        const billMonthly = (() => {
            const val = byId('electricityBill')?.value;
            // Ensure we never treat a negative input as a negative bill - clamp to 0
            const r = Math.max(0, num(val));
            return r;
        })();
        
        // TOGGLED OFF: Download Report button disabled


        // add an energy production estimate based on panels and available solar configs
        let yearlyEnergy = 0;
        // prefer parsed DOM configs, then server-provided `solarConfigs` (may be a top-level const, not on window)
        const availableConfigs = (Array.isArray(window.__parsedSolarConfigs) && window.__parsedSolarConfigs.length > 0)
            ? window.__parsedSolarConfigs
            : (window.KSRAD_UtilityConfig && Array.isArray(window.KSRAD_UtilityConfig.solarConfigs) && window.KSRAD_UtilityConfig.solarConfigs.length > 0 
                ? window.KSRAD_UtilityConfig.solarConfigs 
                : (typeof solarConfigs !== 'undefined' && Array.isArray(solarConfigs) && solarConfigs.length > 0 ? solarConfigs : []));
        if (availableConfigs.length > 0) {
            // helper: try to extract a numeric kWh value from a config object safely
            const extractKwh = (cfg) => {
                if (!cfg) return 0;
                // try common keys first
                const candidates = [cfg['yearlyEnergyDcKwh'], cfg['yearlyEnergy'], cfg['Annual Energy Production'], cfg['Annual Energy Production (kWh)'], cfg['Annual Energy Production kWh'], cfg['Annual Energy Production:'], cfg['Annual Energy Production\u00A0']];
                for (const cand of candidates) {
                    if (cand && typeof cand === 'string') {
                        const n = parseFloat(cand.replace(/[^0-9.\-]/g, '').replace(/,/g, ''));
                        if (Number.isFinite(n) && n > 0) return n;
                    }
                    if (Number.isFinite(cand) && cand > 0) return Number(cand);
                }
                // fallback: inspect any string value on the config object and pick first number-like token
                for (const v of Object.values(cfg)) {
                    if (!v) continue;
                    const s = String(v);
                    const m = s.match(/([0-9\.,]+)\s*/);
                    if (m) {
                        const n = parseFloat(m[1].replace(/,/g, ''));
                        if (Number.isFinite(n) && n > 0) return n;
                    }
                }
                return 0;
            };

            // find config matching panel count
            for (let i = 0; i < availableConfigs.length; i++) {
                const config = availableConfigs[i];
                const configPanels = parseInt(config['panelsCount'] || config['panels'] || config['Number of Panels'] || config['Panels']) || 0;
                if (configPanels === panels) {
                    yearlyEnergy = extractKwh(config) || 0;
                    break;
                }
            }
            // if there isn't an exact matching panels, choose the closest lower one
            if (yearlyEnergy === 0) {
                let closestDiff = Infinity;
                for (let i = 0; i < availableConfigs.length; i++) {
                    const config = availableConfigs[i];
                    const configPanels = parseInt(config['panelsCount'] || config['panels'] || config['Number of Panels'] || config['Panels']) || 0;
                    const diff = panels - configPanels;
                    if (diff >= 0 && diff < closestDiff) {
                        closestDiff = diff;
                        yearlyEnergy = extractKwh(config) || 0;
                    }
                }
            }
        }

        return { inclGrant, inclACA, inclLoan, panels, exportRate, electricityRate, feedInTariff, APR, billMonthly, yearlyEnergy };
    }

    function keyFigures(state) {
        const { inclGrant, inclACA, inclLoan, panels, exportRate, electricityRate: RETAIL, feedInTariff: FIT, APR, billMonthly, yearlyEnergy } = state;
        // Derived system constants
        const kWp = (panels * PANEL_POWER_W) / 1000;
        const baseCost = Math.round(estimateSolarCost(state.panels)); // $

        // Resolve grant settings based on building type (Residential vs Non-Residential)
        const getGrantSettings = () => {
            try {
                const cfg = window.KSRAD_CalcConfig || {};
                const grants = cfg.grantSettings || {};
                const btEl = document.getElementById('userBuildingType');
                const selected = (btEl && btEl.value) ? btEl.value.trim() : 'Residential';
                // Map building types to grant categories
                const isResidential = (selected === 'Residential');
                const category = isResidential ? 'Residential' : 'Non-Residential';
                if (grants[category]) {
                    return { rate: grants[category].rate || 0, cap: grants[category].cap || 0 };
                }
                return { rate: 0, cap: 0 }; // fallback
            } catch (e) {
                return { rate: 0, cap: 0 };
            }
        };
        const grantSettings = getGrantSettings();
        const seaiGrant = state.inclGrant ? Math.min(Number(baseCost * grantSettings.rate), grantSettings.cap) : 0;
        const acaAllowance = state.inclACA ? Math.min(Number(baseCost - seaiGrant), Number(baseCost) * CORPORATION_TAX ) : 0;

        // interest multiplier used when including loan-related uplift (simple proxy)
        const interest = Math.min(Number(APR ? APR * LENGTH_OF_PAYBACK : 0) || 0, 0.5); // cap at 50%
        
        // Install costs
        // convert computed floats to rounded integers for display/consistency
        const install_cost = Math.round(Number(baseCost));

        // Production
        const yearlyEnergyKWhYr0 = yearlyEnergy; // year 0 nominal from config
        const yearlyEnergyKWh = yearlyEnergyKWhYr0; // displayed headline (yr0  value)

        // Loan modelling (monthly amortisation uses the loan term, not the 25-year system life)
        const m = 12, n = LENGTH_OF_PAYBACK * m;
        const principal = Math.max(0, baseCost - seaiGrant);
        const r = APR / m;
        const monthlyRepay = Math.round(inclLoan ? principal * (r / (1 - Math.pow(1 + r, -n))) : 0);
        const yearlyLoanCost = Math.round(inclLoan ? monthlyRepay * 12 : 0);

        // Net install cost: if loan, show total loan payments; otherwise show upfront cost after grant
        const net_install_cost = inclLoan ? Math.round(yearlyLoanCost * LENGTH_OF_PAYBACK) : Math.round(baseCost - seaiGrant);

        // Total 25-year savings (benefits - cost + ACA if included)
        // Must account for actual electricity usage—can't "self-consume" power if you have no bill
        const benefits25 = Array.from({ length: YRS_OF_SYSTEM }, (_, y) => {
            // Use actual yearly production (not formula) for consistency
            const baseProduction = yearlyEnergy > 0 ? yearlyEnergy : (panels * DAY_POWER_AVG * DAYS_IN_YR);
            const pvYear = baseProduction * Math.pow(1 - SOLAR_PANEL_DEGRADATION, y);
            
            // Determine actual self-consumption based on bill (same logic as savings_year0)
            const currentUsageKwh = (billMonthly * 12) / RETAIL;
            const maxSelfConsumptionKwh = pvYear * (1 - exportRate);
            const actualSelfConsumptionKwh = Math.min(maxSelfConsumptionKwh, currentUsageKwh);
            const exportKwh = pvYear - actualSelfConsumptionKwh;
            
            // Financial benefits with escalation
            const retailY = RETAIL * Math.pow(1 + ANNUAL_INCREASE, y);
            const fitY = FIT; // could escalate, left constant per provided spec
            return (actualSelfConsumptionKwh * retailY) + (exportKwh * fitY);
        }).reduce((a, b) => a + b, 0);

        // Total loan payments over the evaluation window: stop counting repayments after the loan term
        const loanYearsCount = Math.min(YRS_OF_SYSTEM, LENGTH_OF_PAYBACK);
        const loanCost25 = inclLoan ? (monthlyRepay * 12 * loanYearsCount) : principal; // total paid on loan within evaluation window
        const total_yr_savings = benefits25 - loanCost25 + (inclACA ? acaAllowance : 0);

        // First-year annual saving (calculate this BEFORE payback so we can use it)
        // ===== FIXED PRODUCTION & SAVINGS MODEL =====

        // Annual usage derived from bill
        const current_usage_kwh = (billMonthly * MONTHS_IN_YR) / RETAIL;

        // Total solar production
        const annual_solar_kwh =
            panels *
            PANEL_POWER_W / 1000 *
            DAY_POWER_AVG *
            DAYS_IN_YR;

        // Self-consumption is limited by actual usage
        const max_self_consumption_kwh = annual_solar_kwh * (1 - exportRate);
        const actual_self_consumption_kwh = Math.min(max_self_consumption_kwh, current_usage_kwh);

        // Export is what's left after self-consumption
        const export_kwh = annual_solar_kwh - actual_self_consumption_kwh;

        // --- FINANCIALS ---
        const bill_savings = actual_self_consumption_kwh * RETAIL;
        const export_income = export_kwh * FIT;

        // Total benefit (before loan / adjustments)
        const savings_year0 = bill_savings + export_income - yearlyLoanCost;

        // Monthly charge (Year 0) - based on actual savings
        // Only show meaningful net income when there's a bill to offset
        const monthly_charge = billMonthly > 0 ? (savings_year0 / 12) - billMonthly : 0;
	
        // Payback period (years) - uses actual net annual savings
        // Investment amount to pay back
        const investment = inclLoan ? loanCost25 : net_install_cost;
        // Payback = Investment / Annual Savings
        const payback_period = savings_year0 > 0 ? investment / savings_year0 : 0;

        // ROI over 25 years (%)
        const ROI_25Y = (() => {
            const cost = inclLoan ? (monthlyRepay * 12 * loanYearsCount) : principal;
            return cost > 0 ? ((benefits25 - cost) / cost) * 100 : 0;
        })();

        // CO2 reduction over life
        const co2_reduction = CO2_COEFFICIENT_TONNES *
        Array.from({ length: YRS_OF_SYSTEM }, (_, y) =>
                panels * DAY_POWER_AVG * Math.pow(1 - SOLAR_PANEL_DEGRADATION, y) * DAYS_IN_YR
            ).reduce((a, b) => a + b, 0);

        // ========= COMPREHENSIVE LOGGING (when keiste_log = 1) =========
        if (keiste_log === 1) {
            console.log('\n' + '='.repeat(80));
            console.log('KEISTE SOLAR CALCULATOR - COMPREHENSIVE CALCULATION LOG');
            console.log('='.repeat(80));
            
            // 1. CONSTANTS
            console.log('\n[1] CONSTANTS:');
            console.log('  DAYS_IN_YR: ' + DAYS_IN_YR);
            console.log('  MONTHS_IN_YR: ' + MONTHS_IN_YR);
            console.log('  HOURS_IN_DAY: ' + HOURS_IN_DAY);
            console.log('  CORPORATION_TAX: ' + (CORPORATION_TAX * 100) + '%');
            console.log('  LOAN_APR_DEFAULT: ' + (LOAN_APR_DEFAULT * 100) + '%');
            console.log('  FEED_IN_TARIFF_DEFAULT: ' + CURRENCY_SYMBOL + FEED_IN_TARIFF_DEFAULT + '/kWh');
            console.log('  ANNUAL_INCREASE: ' + (ANNUAL_INCREASE * 100) + '%');
            console.log('  SOLAR_PANEL_DEGRADATION: ' + (SOLAR_PANEL_DEGRADATION * 100) + '%/yr');
            console.log('  LENGTH_OF_PAYBACK: ' + LENGTH_OF_PAYBACK + ' years');
            console.log('  PANEL_POWER_W: ' + PANEL_POWER_W + 'W');
            console.log('  YRS_OF_SYSTEM: ' + YRS_OF_SYSTEM + ' years');
            console.log('  CO2_COEFFICIENT_TONNES: ' + CO2_COEFFICIENT_TONNES + ' tonnes/kWh');
            console.log('  DAY_POWER_AVG: ' + DAY_POWER_AVG + ' kWh/day per panel');
            console.log('  CURRENCY_SYMBOL: ' + CURRENCY_SYMBOL);
            
            // 2. INPUT VARIABLES
            console.log('\n[2] INPUT VARIABLES:');
            console.log('  panels: ' + panels);
            console.log('  billMonthly: ' + CURRENCY_SYMBOL + billMonthly);
            console.log('  electricityRate (RETAIL): ' + CURRENCY_SYMBOL + RETAIL + '/kWh');
            console.log('  feedInTariff (FIT): ' + CURRENCY_SYMBOL + FIT + '/kWh');
            console.log('  exportRate: ' + (exportRate * 100) + '%');
            console.log('  APR: ' + (APR * 100) + '%');
            console.log('  inclGrant: ' + inclGrant);
            console.log('  inclACA: ' + inclACA);
            console.log('  inclLoan: ' + inclLoan);
            console.log('  yearlyEnergy (from config): ' + yearlyEnergy + ' kWh');
            console.log('  grantSettings.rate: ' + (grantSettings.rate * 100) + '%');
            console.log('  grantSettings.cap: ' + CURRENCY_SYMBOL + grantSettings.cap);
            
            // 3. DERIVED SYSTEM VALUES
            console.log('\n[3] DERIVED SYSTEM VALUES:');
            console.log('  kWp = panels × PANEL_POWER_W ÷ 1000');
            console.log('      = ' + panels + ' × ' + PANEL_POWER_W + ' ÷ 1000');
            console.log('      = ' + kWp.toFixed(2) + ' kWp');
            
            // 4. COST CALCULATIONS
            console.log('\n[4] COST CALCULATIONS:');
            console.log('  baseCost = estimateSolarCost(panels)');
            console.log('           = ' + CURRENCY_SYMBOL + baseCost);
            console.log('  ');
            console.log('  seaiGrant = inclGrant ? min(baseCost × grantRate, grantCap) : 0');
            console.log('            = ' + inclGrant + ' ? min(' + CURRENCY_SYMBOL + baseCost + ' × ' + grantSettings.rate + ', ' + CURRENCY_SYMBOL + grantSettings.cap + ') : 0');
            console.log('            = ' + CURRENCY_SYMBOL + seaiGrant);
            console.log('  ');
            console.log('  acaAllowance = inclACA ? min(baseCost - seaiGrant, baseCost × CORPORATION_TAX) : 0');
            console.log('               = ' + inclACA + ' ? min(' + CURRENCY_SYMBOL + baseCost + ' - ' + CURRENCY_SYMBOL + seaiGrant + ', ' + CURRENCY_SYMBOL + baseCost + ' × ' + CORPORATION_TAX + ') : 0');
            console.log('               = ' + CURRENCY_SYMBOL + acaAllowance);
            console.log('  ');
            console.log('  install_cost = ' + CURRENCY_SYMBOL + install_cost);
            
            // 5. LOAN CALCULATIONS
            console.log('\n[5] LOAN CALCULATIONS:');
            console.log('  m (months/year) = ' + m);
            console.log('  n (total months) = LENGTH_OF_PAYBACK × m = ' + LENGTH_OF_PAYBACK + ' × ' + m + ' = ' + n);
            console.log('  principal = max(0, baseCost - seaiGrant)');
            console.log('            = max(0, ' + CURRENCY_SYMBOL + baseCost + ' - ' + CURRENCY_SYMBOL + seaiGrant + ')');
            console.log('            = ' + CURRENCY_SYMBOL + principal);
            console.log('  r (monthly rate) = APR ÷ m = ' + APR + ' ÷ ' + m + ' = ' + r.toFixed(6));
            console.log('  ');
            console.log('  monthlyRepay = inclLoan ? principal × (r ÷ (1 - (1 + r)^-n)) : 0');
            console.log('               = ' + inclLoan + ' ? ' + CURRENCY_SYMBOL + principal + ' × (' + r.toFixed(6) + ' ÷ (1 - (1 + ' + r.toFixed(6) + ')^-' + n + ')) : 0');
            console.log('               = ' + CURRENCY_SYMBOL + monthlyRepay);
            console.log('  ');
            console.log('  yearlyLoanCost = inclLoan ? monthlyRepay × 12 : 0');
            console.log('                 = ' + inclLoan + ' ? ' + CURRENCY_SYMBOL + monthlyRepay + ' × 12 : 0');
            console.log('                 = ' + CURRENCY_SYMBOL + yearlyLoanCost);
            console.log('  ');
            console.log('  net_install_cost = inclLoan ? yearlyLoanCost × LENGTH_OF_PAYBACK : baseCost - seaiGrant');
            console.log('                   = ' + inclLoan + ' ? ' + CURRENCY_SYMBOL + yearlyLoanCost + ' × ' + LENGTH_OF_PAYBACK + ' : ' + CURRENCY_SYMBOL + baseCost + ' - ' + CURRENCY_SYMBOL + seaiGrant);
            console.log('                   = ' + CURRENCY_SYMBOL + net_install_cost);
            
            // 6. ENERGY PRODUCTION CALCULATIONS
            console.log('\n[6] ENERGY PRODUCTION CALCULATIONS (Year 0):');
            console.log('  yearlyEnergyKWh (displayed) = ' + yearlyEnergyKWh + ' kWh');
            console.log('  ');
            console.log('  annual_solar_kwh = panels × (PANEL_POWER_W ÷ 1000) × DAY_POWER_AVG × DAYS_IN_YR');
            console.log('                   = ' + panels + ' × (' + PANEL_POWER_W + ' ÷ 1000) × ' + DAY_POWER_AVG + ' × ' + DAYS_IN_YR);
            console.log('                   = ' + annual_solar_kwh.toFixed(2) + ' kWh');
            console.log('  ');
            console.log('  current_usage_kwh = (billMonthly × MONTHS_IN_YR) ÷ RETAIL');
            console.log('                    = (' + CURRENCY_SYMBOL + billMonthly + ' × ' + MONTHS_IN_YR + ') ÷ ' + CURRENCY_SYMBOL + RETAIL);
            console.log('                    = ' + current_usage_kwh.toFixed(2) + ' kWh');
            
            // 7. SELF-CONSUMPTION & EXPORT
            console.log('\n[7] SELF-CONSUMPTION & EXPORT CALCULATIONS:');
            console.log('  max_self_consumption_kwh = annual_solar_kwh × (1 - exportRate)');
            console.log('                           = ' + annual_solar_kwh.toFixed(2) + ' × (1 - ' + exportRate + ')');
            console.log('                           = ' + max_self_consumption_kwh.toFixed(2) + ' kWh');
            console.log('  ');
            console.log('  actual_self_consumption_kwh = min(max_self_consumption_kwh, current_usage_kwh)');
            console.log('                              = min(' + max_self_consumption_kwh.toFixed(2) + ', ' + current_usage_kwh.toFixed(2) + ')');
            console.log('                              = ' + actual_self_consumption_kwh.toFixed(2) + ' kWh');
            console.log('  ');
            console.log('  export_kwh = annual_solar_kwh - actual_self_consumption_kwh');
            console.log('             = ' + annual_solar_kwh.toFixed(2) + ' - ' + actual_self_consumption_kwh.toFixed(2));
            console.log('             = ' + export_kwh.toFixed(2) + ' kWh');
            
            // 8. YEAR 0 FINANCIAL SAVINGS
            console.log('\n[8] YEAR 0 FINANCIAL SAVINGS:');
            console.log('  bill_savings = actual_self_consumption_kwh × RETAIL');
            console.log('               = ' + actual_self_consumption_kwh.toFixed(2) + ' × ' + CURRENCY_SYMBOL + RETAIL);
            console.log('               = ' + CURRENCY_SYMBOL + bill_savings.toFixed(2));
            console.log('  ');
            console.log('  export_income = export_kwh × FIT');
            console.log('                = ' + export_kwh.toFixed(2) + ' × ' + CURRENCY_SYMBOL + FIT);
            console.log('                = ' + CURRENCY_SYMBOL + export_income.toFixed(2));
            console.log('  ');
            console.log('  savings_year0 = bill_savings + export_income - yearlyLoanCost');
            console.log('                = ' + CURRENCY_SYMBOL + bill_savings.toFixed(2) + ' + ' + CURRENCY_SYMBOL + export_income.toFixed(2) + ' - ' + CURRENCY_SYMBOL + yearlyLoanCost);
            console.log('                = ' + CURRENCY_SYMBOL + savings_year0.toFixed(2));
            
            // 9. 25-YEAR PROJECTIONS
            console.log('\n[9] 25-YEAR PROJECTIONS:');
            console.log('  loanYearsCount = min(YRS_OF_SYSTEM, LENGTH_OF_PAYBACK)');
            console.log('                 = min(' + YRS_OF_SYSTEM + ', ' + LENGTH_OF_PAYBACK + ')');
            console.log('                 = ' + loanYearsCount);
            console.log('  ');
            console.log('  loanCost25 = inclLoan ? (monthlyRepay × 12 × loanYearsCount) : principal');
            console.log('             = ' + inclLoan + ' ? (' + CURRENCY_SYMBOL + monthlyRepay + ' × 12 × ' + loanYearsCount + ') : ' + CURRENCY_SYMBOL + principal);
            console.log('             = ' + CURRENCY_SYMBOL + loanCost25);
            console.log('  ');
            console.log('  benefits25 (sum of 25 years with degradation & escalation) = ' + CURRENCY_SYMBOL + benefits25.toFixed(2));
            console.log('  ');
            console.log('  total_yr_savings = benefits25 - loanCost25 + (inclACA ? acaAllowance : 0)');
            console.log('                   = ' + CURRENCY_SYMBOL + benefits25.toFixed(2) + ' - ' + CURRENCY_SYMBOL + loanCost25 + ' + (' + inclACA + ' ? ' + CURRENCY_SYMBOL + acaAllowance + ' : 0)');
            console.log('                   = ' + CURRENCY_SYMBOL + total_yr_savings.toFixed(2));
            
            // 10. KEY INTERFACE FIGURES
            console.log('\n[10] KEY INTERFACE FIGURES:');
            console.log('  monthly_charge = billMonthly > 0 ? (savings_year0 ÷ 12) - billMonthly : 0');
            console.log('                 = ' + billMonthly + ' > 0 ? (' + CURRENCY_SYMBOL + savings_year0.toFixed(2) + ' ÷ 12) - ' + CURRENCY_SYMBOL + billMonthly + ' : 0');
            console.log('                 = ' + CURRENCY_SYMBOL + monthly_charge.toFixed(2));
            console.log('  ');
            console.log('  investment = inclLoan ? loanCost25 : net_install_cost');
            console.log('             = ' + inclLoan + ' ? ' + CURRENCY_SYMBOL + loanCost25 + ' : ' + CURRENCY_SYMBOL + net_install_cost);
            console.log('             = ' + CURRENCY_SYMBOL + investment);
            console.log('  ');
            console.log('  payback_period = savings_year0 > 0 ? investment ÷ savings_year0 : 0');
            console.log('                 = ' + savings_year0.toFixed(2) + ' > 0 ? ' + CURRENCY_SYMBOL + investment + ' ÷ ' + CURRENCY_SYMBOL + savings_year0.toFixed(2) + ' : 0');
            console.log('                 = ' + payback_period.toFixed(2) + ' years');
            console.log('  ');
            const roi_cost = inclLoan ? (monthlyRepay * 12 * loanYearsCount) : principal;
            console.log('  ROI_25Y = cost > 0 ? ((benefits25 - cost) ÷ cost) × 100 : 0');
            console.log('          = ' + CURRENCY_SYMBOL + roi_cost + ' > 0 ? ((' + CURRENCY_SYMBOL + benefits25.toFixed(2) + ' - ' + CURRENCY_SYMBOL + roi_cost + ') ÷ ' + CURRENCY_SYMBOL + roi_cost + ') × 100 : 0');
            console.log('          = ' + ROI_25Y.toFixed(2) + '%');
            console.log('  ');
            const total_co2_energy = Array.from({ length: YRS_OF_SYSTEM }, (_, y) =>
                panels * DAY_POWER_AVG * Math.pow(1 - SOLAR_PANEL_DEGRADATION, y) * DAYS_IN_YR
            ).reduce((a, b) => a + b, 0);
            console.log('  co2_reduction = CO2_COEFFICIENT_TONNES × (sum of 25 years production)');
            console.log('                = ' + CO2_COEFFICIENT_TONNES + ' × ' + total_co2_energy.toFixed(2));
            console.log('                = ' + co2_reduction.toFixed(2) + ' tonnes');
            
            // 11. SUMMARY
            console.log('\n[11] CALCULATION SUMMARY:');
            console.log('  Installation Cost: ' + CURRENCY_SYMBOL + install_cost);
            console.log('  Grant: ' + CURRENCY_SYMBOL + seaiGrant);
            console.log('  ACA Allowance: ' + CURRENCY_SYMBOL + acaAllowance);
            console.log('  Net Install Cost: ' + CURRENCY_SYMBOL + net_install_cost);
            console.log('  Annual Energy (Year 0): ' + yearlyEnergyKWh + ' kWh');
            console.log('  Annual Savings (Year 0): ' + CURRENCY_SYMBOL + savings_year0.toFixed(2));
            console.log('  Monthly Net Income: ' + CURRENCY_SYMBOL + monthly_charge.toFixed(2));
            console.log('  Payback Period: ' + payback_period.toFixed(2) + ' years');
            console.log('  25-Year Total Savings: ' + CURRENCY_SYMBOL + total_yr_savings.toFixed(2));
            console.log('  25-Year ROI: ' + ROI_25Y.toFixed(2) + '%');
            console.log('  CO2 Reduction (25 years): ' + co2_reduction.toFixed(2) + ' tonnes');
            
            console.log('\n' + '='.repeat(80));
            console.log('END OF CALCULATION LOG');
            console.log('='.repeat(80) + '\n');
        }

        return {
            baseCost, seaiGrant, acaAllowance,
            install_cost, net_install_cost,
            yearlyEnergyKWh, monthly_charge, total_yr_savings,
            payback_period, ROI_25Y, savings_year0, co2_reduction
        };
    }

    // ========= 5) GUI UPDATES =========
    function updateGrantDescription() {
        // Update the grant description text based on current building type
        try {
            const cfg = window.KSRAD_CalcConfig || {};
            const grants = cfg.grantSettings || {};
            const btEl = document.getElementById('userBuildingType');
            const selected = (btEl && btEl.value) ? btEl.value.trim() : 'Residential';
            
            const isResidential = (selected === 'Residential');
            const category = isResidential ? 'Residential' : 'Non-Residential';
            
            const grantRate = grants[category] ? (grants[category].rate || 0) : 0;
            const grantCap = grants[category] ? (grants[category].cap || 0) : 0;
            
            // Find and update grant description elements
            const grantDescElements = document.querySelectorAll('.grant-description, [data-grant-description]');
            grantDescElements.forEach(el => {
                const percentDisplay = Math.round(grantRate * 100);
                const capDisplay = CURRENCY_SYMBOL + grantCap.toLocaleString('en-IE');
                el.textContent = `${percentDisplay}% Grant (max ${capDisplay})`;
            });
        } catch (e) {
        }
    }
    
    function updateResults(state, figs) {
        const setTxt = (id, txt) => {
            document.querySelectorAll('#' + id).forEach(el => {
                if (!el) return;
                // Do not overwrite form inputs (slider). Only update visible text elements.
                if (el.tagName && el.tagName.toUpperCase() === 'INPUT') return;
                el.textContent = txt;
            });
        };
        // #results
        setTxt('installationCost', fmtEuro(figs.install_cost));
        setTxt('grant', fmtEuro(figs.seaiGrant));
        
        // Update grant description text dynamically
        updateGrantDescription();
        
        setTxt('panelCount', fmtNum(state.panels, 0));
        // Annual energy production display: support both legacy `yearlyEnergy` and current `yearlyEnergyValue` IDs
        const yearlyKwhDisplay = fmtNum(figs.yearlyEnergyKWh || (state.panels * DAY_POWER_AVG * DAYS_IN_YR), 0) + ' kWh';
        setTxt('yearlyEnergy', yearlyKwhDisplay);
        setTxt('yearlyEnergyValue', yearlyKwhDisplay.replace(/\s*kWh$/,'')); // value-only for left-side summary
        // Keep hidden input `yearlyEnergy` in sync if present
        const yearlyHidden = byId('yearlyEnergy');
        if (yearlyHidden && yearlyHidden.tagName && yearlyHidden.tagName.toUpperCase() === 'INPUT') {
            yearlyHidden.value = String(figs.yearlyEnergyKWh || (state.panels * DAY_POWER_AVG * DAYS_IN_YR) || 0);
        }
        setTxt('monthlyBill', fmtEuro(state.billMonthly));
        setTxt('annualIncrease', (ANNUAL_INCREASE * 100).toFixed(1) + '%');
        // if the income is negative, show in red (format/sign is handled here)
        if (figs.monthly_charge < 0) {
            setTxt('netIncome', '-' + fmtEuro(Math.abs(figs.monthly_charge)));
            const el = byId('netIncome');
            if (el) el.style.color = 'red';
        } else {
            setTxt('netIncome', '+' +  fmtEuro(figs.monthly_charge));
            const el = byId('netIncome');
            if (el) el.style.color = 'black';
        }
        setTxt('exportRate', (state.exportRate * 100).toFixed(0) + '%');
        setTxt('electricityRate', fmtEuro(state.electricityRate));
    }

    function updateInstallationDetails(state, figs) {
        const setTxt = (id, txt) => {
            document.querySelectorAll('#' + id).forEach(el => {
                if (!el) return;
                if (el.tagName && el.tagName.toUpperCase() === 'INPUT') return;
                el.textContent = txt;
            });
        };
        
        // Only show meaningful figures when there's a bill
        if (!state.billMonthly || state.billMonthly === 0) {
            setTxt('netCost', CURRENCY_SYMBOL + '0');
            setTxt('totalSavings', CURRENCY_SYMBOL + '0');
            setTxt('roi', '0%');
            setTxt('co2Reduction', '0 t');
            setTxt('annualSavings', CURRENCY_SYMBOL + '0');
            setTxt('paybackPeriod', '0 years');
            return;
        }
        
        // #installation-details
        setTxt('netCost', fmtEuro(figs.net_install_cost));
        setTxt('totalSavings', fmtEuro(figs.total_yr_savings));
        setTxt('roi', fmtNum(figs.ROI_25Y, 1) + '%');
        setTxt('panelCount', fmtNum(state.panels, 0));

        // show one decimal for CO₂ reductions for readability
        setTxt('co2Reduction', fmtNum(figs.co2_reduction, 1) + ' t');
        setTxt('annualSavings', fmtEuro(figs.savings_year0));
        setTxt('paybackPeriod', fmtNum(figs.payback_period, 2) + ' years');
    }

    // Minimal canvas updates so the IDs react without external libs
    function updateBreakEvenChart(state, figs) {
        // Prefer updating Chart.js instance when available (keeps rendering consistent)
        if (window.breakEvenChart && window.breakEvenChart.data && typeof window.calculateBreakEvenDataSimple === 'function') {
            try {
                // On page load with no bill, show zero baseline
                if (!state.billMonthly || state.billMonthly === 0) {
                    window.breakEvenChart.data.datasets[0].data = Array(25).fill(0);
                    window.breakEvenChart.data.datasets[0].label = '0 Panels';
                    window.breakEvenChart.update('none');
                    return;
                }
                
                const cfg = { 
                    panelsCount: state.panels, 
                    yearlyEnergyDcKwh: figs.yearlyEnergyKWh || (state.panels * DAY_POWER_AVG * DAYS_IN_YR),
                    installCost: figs.baseCost
                };
                const be = window.calculateBreakEvenDataSimple(cfg);
                
                if (be && be.savings && window.breakEvenChart.data && window.breakEvenChart.data.datasets && window.breakEvenChart.data.datasets[0]) {
                    window.breakEvenChart.data.datasets[0].data = [...be.savings];
                    window.breakEvenChart.data.datasets[0].label = `${state.panels} Panels`;
                    // Force chart to recalculate scales and redraw
                    window.breakEvenChart.options.scales.y.min = undefined;
                    window.breakEvenChart.options.scales.y.max = undefined;
                    window.breakEvenChart.update('active');
                    return;
                }
            } catch (e) {
                // fall back to canvas drawing below
            }
        }

        const c = byId('breakEvenChart');
        if (!c || !c.getContext) return;
        const ctx = c.getContext('2d');
        const W = c.width, H = c.height;
        ctx.clearRect(0, 0, W, H);
        // Simple two-bar visual: Cost vs 25y Benefits
        const cost = Math.max(1, figs.net_install_cost);
        const benefit = Math.max(1, figs.total_yr_savings + figs.net_install_cost);
        const maxV = Math.max(cost, benefit);
        const barW = W * 0.3, gap = W * 0.1;
        const scale = (v) => (v / maxV) * (H * 0.8);
        ctx.fillRect(W * 0.15, H - scale(cost), barW, scale(cost));
        ctx.fillRect(W * 0.55, H - scale(benefit), barW, scale(benefit));
    }

    function updateEnergyChart(state, figs) {
        // If Chart.js instance exists, update its dataset instead of raw canvas drawing
        if (window.energyChart) {
            try {
                const years = YRS_OF_SYSTEM;
                const degradation = SOLAR_PANEL_DEGRADATION;
                const data = Array.from({ length: years }, (_, y) => {
                    return state.panels * DAY_POWER_AVG * DAYS_IN_YR * Math.pow(1 - degradation, y);
                });
                window.energyChart.data.datasets[0].data = data;
                window.energyChart.data.datasets[0].label = `${state.panels} panels — Annual Production (kWh)`;
                window.energyChart.update();
                return;
            } catch (e) {
                // fall back to canvas drawing
            }
        }

        const c = byId('energyChart');
        if (!c || !c.getContext) return;
        const ctx = c.getContext('2d');
        const W = c.width, H = c.height;
        ctx.clearRect(0, 0, W, H);
        // Plot annual production decline by degradation
        const years = YRS_OF_SYSTEM;
        const values = Array.from({ length: years }, (_, y) => state.panels * DAY_POWER_AVG * DAYS_IN_YR * Math.pow(1 - SOLAR_PANEL_DEGRADATION, y));
        const maxV = Math.max(...values);
        const xstep = W / (years + 1);
        ctx.beginPath();
        values.forEach((v, i) => {
            const x = xstep * (i + 1);
            const y = H - (v / maxV) * (H * 0.85);
            if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
        });
        ctx.stroke();
    }

    function updateSolarInvestmentAnalysis(state, figs) {
        const setTxt = (id, txt) => {
            document.querySelectorAll('#' + id).forEach(el => {
                if (!el) return;
                if (el.tagName && el.tagName.toUpperCase() === 'INPUT') return;
                el.textContent = txt;
            });
        };
        setTxt('panelCountValue', fmtNum(state.panels, 0));
        setTxt('installCost', fmtEuro(figs.baseCost));
    }

    // ========= 6) MASTER =========
    let modalPopupTimer = null;
    let modalShown = false; // Track if modal has been shown
    
    // Use window.formSubmittedSuccessfully so it can be updated by modal handler
    if (typeof window.formSubmittedSuccessfully === 'undefined') {
        window.formSubmittedSuccessfully = false;
    }
    
    // Track user interaction - set by event listeners only
    window.ksradUserInteracted = false;

    function calculateROI() {
        const state = readInputs();
        
        // Modal popup timer - only trigger ONCE after user interaction
        // Check window.ksradUserInteracted which is set by event listeners
        if (!window.formSubmittedSuccessfully && window.ksradUserInteracted && !modalShown) {
            // Clear any existing timer
            if (modalPopupTimer) {
                clearTimeout(modalPopupTimer);
            }
            
            // Schedule modal to appear after 3 seconds (only once)
            modalPopupTimer = setTimeout(() => {
                if (!window.formSubmittedSuccessfully && !modalShown && typeof window.showModal === 'function') {
                    window.showModal();
                    modalShown = true; // Prevent modal from showing again
                }
            }, 3000);
        }
        
        // Guard: require monthly bill to compute robustly
        if (!state.billMonthly) {
            // still update zero-ish defaults so UI doesn't look stale
            const zeroFigs = keyFigures({ ...state, billMonthly: 0 });
            updateResults(state, zeroFigs);
            updateInstallationDetails(state, zeroFigs);
            // Only update charts if they exist
            if (window.breakEvenChart) updateBreakEvenChart(state, zeroFigs);
            if (window.energyChart) updateEnergyChart(state, zeroFigs);
            updateSolarInvestmentAnalysis(state, zeroFigs);
            return;
        }
        const figs = keyFigures(state);
        updateResults(state, figs);
        updateInstallationDetails(state, figs);
        // Only update charts if they exist
        if (window.breakEvenChart) updateBreakEvenChart(state, figs);
        if (window.energyChart) updateEnergyChart(state, figs);
        updateSolarInvestmentAnalysis(state, figs);
    }

    // ========= 7) EVENT WIRING =========
    function wireEvents() {
        const onChangeRecalc = (id, ev = 'change') => {
            const el = byId(id);
            if (el) {
                el.addEventListener(ev, () => {
                    // Mark that user has interacted
                    window.ksradUserInteracted = true;
                    calculateROI();
                });
            }
        };
        onChangeRecalc('inclGrant', 'change');
        onChangeRecalc('inclACA', 'change');
        onChangeRecalc('inclLoan', 'change');
        onChangeRecalc('panelCount', 'input');

        // keyup handlers for text inputs
        onChangeRecalc('exportRate', 'keyup');
        onChangeRecalc('electricityRate', 'keyup');
        
        // Building type change triggers recalc (affects grant rates and cost tiers)
        onChangeRecalc('userBuildingType', 'change');

        const btn = byId('openRoiModalButton');
        if (btn) {
            btn.addEventListener('click', () => {
                window.ksradUserInteracted = true;
                calculateROI();
            });
        }

        // Also recalc on electricityBill keyup so users see instant feedback
        onChangeRecalc('electricityBill', 'keyup');
    }

    // ========= 8) INITIALISE =========
    function initialPopulate() {
        // Explicitly set all ROI values to zero on page load
        const setZero = (id, txt) => {
            const el = byId(id);
            if (el && el.tagName !== 'INPUT') el.textContent = txt;
        };
        setZero('netIncome', CURRENCY_SYMBOL + '0');
        setZero('netCost', CURRENCY_SYMBOL + '0');
        setZero('paybackPeriod', '0 yrs');
        setZero('annualSavings', CURRENCY_SYMBOL + '0');
        setZero('totalSavings', CURRENCY_SYMBOL + '0');
        setZero('roi', '0%');
        setZero('co2Reduction', '0');
        
        // Set installation details to zero
        setZero('installationCost', '0');
        setZero('installCost', '0');
        setZero('grant', '0');
        
        // Initialize charts with zero data if they exist and are fully initialized
        if (window.breakEvenChart && window.breakEvenChart.data && window.breakEvenChart.data.datasets && window.breakEvenChart.data.datasets[0]) {
            window.breakEvenChart.data.datasets[0].data = Array(25).fill(0);
            window.breakEvenChart.data.datasets[0].label = '0 Panels';
            window.breakEvenChart.update('none');
        }
    }

    // ========= 9) INITIALIZATION =========
    function init() {
        // Apply configuration from PHP if available (don't wait, just use defaults if not ready)
        if (window.KSRAD_CalcConfig) {
            CURRENCY_SYMBOL = window.KSRAD_CalcConfig.currencySymbol || CURRENCY_SYMBOL;
            window.CURRENCY_SYMBOL = CURRENCY_SYMBOL;
            // Set annual price increase from config (convert from percentage to decimal)
            ANNUAL_INCREASE = parseFloat(window.KSRAD_CalcConfig.annualPriceIncrease || 0) / 100;
        }
        
        wireEvents();
        initialPopulate();
        
        // Ensure values stay at zero after a short delay (to override any other initialization)
        setTimeout(() => {
            initialPopulate();
        }, 200);
        
        // Additional check after longer delay to handle cached page loads
        setTimeout(() => {
            initialPopulate();
        }, 500);
    }

    // Expose functions globally for external access (before initialization)
    window.calculateROI = calculateROI;
    window.KSRAD_initCalculator = init; // Expose init for AJAX re-initialization
    // Expose keiste_log flag for debugging (set window.keiste_log = 1 to enable logging)
    Object.defineProperty(window, 'keiste_log', {
        get: () => keiste_log,
        set: (val) => { keiste_log = val; calculateROI(); }
    });
    
    // Auto-initialize when DOM is ready
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        // DOM already loaded - initialize immediately
        init();
    }
    
    // Note: window.formSubmittedSuccessfully is already initialized at the top of the file
    // and used directly throughout, so no need to re-assign here
})();
