import { ValidationHelpers, InputAdornment, HelpTooltip, __, sprintf } from '@vareoncalc/calculator-base';
import { formatCurrencyHtml, formatCompactCurrency, getFormattingConfig, escapeHtml } from '../utils/formatting.js';
import { mapHoverClientXToScalar, findNearestPoint, positionChartTooltip } from '../utils/chart-helpers.js';
import { initWizardSkeleton } from '../utils/wizard-skeleton.js';

/**
 * Savings & Compound Growth Calculator
 * Wizard-driven layout: The Capital -> The Engine -> Fine Tuning -> Advanced Options -> Results
 */

export function mapHoverClientXToYear(clientX, overlayRect, maxYear) {
  return mapHoverClientXToScalar(clientX, overlayRect, maxYear);
}

export function mount(container) {
  const textDomain = 'vareon-calculator-suite-lite';
  const formatting = getFormattingConfig();
  const currencySymbol = escapeHtml(formatting.currencySymbol || '$');
  const percentSuffix = '%';
  const yearSuffix = escapeHtml(__('yr', textDomain));

  // Build the wizard layout
  container.innerHTML = `
    <div class="vareoncalc-shell vareoncalc-shell--wizard">
      <div class="vareoncalc-shell__body">
        <div class="vareoncalc-wizard" data-wizard>

          <!-- Wizard Header -->
          <div class="vareoncalc-wizard__header">
            <div class="vareoncalc-wizard__indicator" data-wizard-indicator></div>
            <div class="vareoncalc-wizard__title" data-wizard-title></div>
            <div class="vareoncalc-wizard__subtitle" data-wizard-subtitle></div>
            <div class="vareoncalc-wizard__progress">
              <div class="vareoncalc-wizard__progress-fill" data-wizard-progress></div>
            </div>
          </div>

          <!-- Wizard Body (Steps) -->
          <div class="vareoncalc-wizard__body">

            <!-- Step 1: The Capital -->
            <div class="vareoncalc-wizard__step"
                 data-wizard-step="capital"
                 data-step-title="${__('The Capital', textDomain)}"
                 data-step-subtitle="${__('Initial deposit and monthly contributions', textDomain)}">
              <div class="savings-wizard__step-fields">
                <div class="vareoncalc-section savings-section savings-section--initial">
                  <div class="vareoncalc-section__header">
                    <div class="vareoncalc-section__title">${__('Initial Capital', textDomain)}</div>
                  </div>
                  <div class="vareoncalc-field">
                    <label for="initial-deposit">${__('Initial Deposit', textDomain)}</label>
          <input type="number" id="initial-deposit" data-suffix="${currencySymbol}" data-suffix-family="currency" placeholder="10000" min="0" step="100">
                  </div>
                </div>
                <div class="vareoncalc-section savings-section savings-section--monthly">
                  <div class="vareoncalc-section__header">
                    <div class="vareoncalc-section__title">${__('Recurring Contributions', textDomain)}</div>
                  </div>
                  <div class="vareoncalc-field">
                    <label for="monthly-contribution">${__('Monthly Contribution', textDomain)}</label>
          <input type="number" id="monthly-contribution" data-suffix="${currencySymbol}" data-suffix-family="currency" placeholder="300" min="0" step="100">
                  </div>
                </div>
              </div>
            </div>

            <!-- Step 2: The Engine -->
            <div class="vareoncalc-wizard__step"
                 data-wizard-step="engine"
                 data-step-title="${__('The Engine', textDomain)}"
                 data-step-subtitle="${__('Annual interest rate, horizon, and APY conversion', textDomain)}">
              <div class="savings-wizard__step-fields">
                <div class="vareoncalc-section savings-section savings-section--engine">
                  <div class="vareoncalc-section__header">
                    <div class="vareoncalc-section__title">${__('Growth Settings', textDomain)}</div>
                  </div>
                  <div class="vareoncalc-field-row">
                    <div class="vareoncalc-field">
                      <div class="savings-wizard__label-row">
                        <label for="interest-rate" class="savings-wizard__inline-label">
                          <span class="vareoncalc-tooltip" data-tooltip-trigger="text" data-tooltip="${__('APR (nominal rate)', textDomain)}" tabindex="0">${__('Annual Rate', textDomain)}</span>
                        </label>
                        <button type="button" class="savings-wizard__apy-toggle" id="apy-toggle" aria-expanded="false" aria-controls="apy-converter-panel">
                          ${__('APY', textDomain)}
                        </button>
                      </div>
                      <input type="number" id="interest-rate" data-suffix="${percentSuffix}" placeholder="6" min="0" max="25" step="0.1">
                    </div>
                    <div class="vareoncalc-field">
                      <label for="time-period">${__('Time Period', textDomain)}</label>
                      <input type="number" id="time-period" data-suffix="${yearSuffix}" placeholder="10" min="1" max="50" step="1">
                    </div>
                  </div>
                </div>
                <div class="vareoncalc-section savings-section savings-section--apy" id="apy-converter-panel" hidden>
                  <div class="vareoncalc-section__header">
                    <div class="vareoncalc-section__title">${__('APY Converter', textDomain)}</div>
                  </div>
                  <div class="vareoncalc-field savings-wizard__apy-field">
                    <label for="apy-input" class="savings-wizard__apy-label">
                      <span class="vareoncalc-tooltip" data-tooltip-trigger="text" data-tooltip="${__('Enter APY and convert it into the nominal annual rate using the selected compound frequency.', textDomain)}" tabindex="0">${__('APY Converter', textDomain)}</span>
                    </label>
                    <div class="savings-wizard__apy-row">
                      <input type="number" id="apy-input" class="vareoncalc-input" data-suffix="${percentSuffix}" placeholder="${__('APY %', textDomain)}" min="0" step="0.1">
                      <button type="button" class="vareoncalc-apy-converter__btn" id="apy-apply">${__('Apply', textDomain)}</button>
                    </div>
                  </div>
                </div>
              </div>
            </div>

            <!-- Step 3: Fine Tuning -->
            <div class="vareoncalc-wizard__step"
                 data-wizard-step="tuning"
                 data-step-title="${__('Fine Tuning', textDomain)}"
                 data-step-subtitle="${__('Compound frequency and contribution timing', textDomain)}">
              <div class="savings-wizard__step-fields">
                <div class="vareoncalc-section savings-section savings-section--compound-frequency">
                  <div class="vareoncalc-section__header">
                    <div class="vareoncalc-section__title">${__('Compounding', textDomain)}</div>
                  </div>
                  <div class="vareoncalc-field">
                    <label for="compound-frequency">${__('Compound Frequency', textDomain)}</label>
                    <select id="compound-frequency" class="vareoncalc-input">
                      <option value="12" selected>${__('Monthly', textDomain)}</option>
                      <option value="4">${__('Quarterly', textDomain)}</option>
                      <option value="2">${__('Semi-Annually', textDomain)}</option>
                      <option value="1">${__('Annually', textDomain)}</option>
                    </select>
                  </div>
                </div>
                <div class="vareoncalc-section savings-section savings-section--contribution-timing">
                  <div class="vareoncalc-section__header">
                    <div class="vareoncalc-section__title">${__('Contribution Timing', textDomain)}</div>
                  </div>
                  <div class="vareoncalc-field">
                    <label for="contribution-timing">${__('Contribute at', textDomain)}</label>
                    <select id="contribution-timing" class="vareoncalc-input">
                      <option value="beginning" selected>${__('Start of month', textDomain)}</option>
                      <option value="end">${__('End of month', textDomain)}</option>
                    </select>
                  </div>
                </div>
              </div>
            </div>

            <!-- Step 4: Advanced Options (optional) -->
            <div class="vareoncalc-wizard__step"
                 data-wizard-step="advanced"
                 data-step-title="${__('Advanced Options', textDomain)}"
                 data-step-subtitle="${__('Inflation, tax rate, and annual contribution increases', textDomain)}"
                 data-step-optional="true">
              <div class="savings-wizard__step-fields">
                <div class="vareoncalc-section savings-section savings-section--advanced-rates">
                  <div class="vareoncalc-section__header">
                    <div class="vareoncalc-section__title">${__('Rates & Assumptions', textDomain)}</div>
                  </div>
                  <div class="vareoncalc-field-row">
                    <div class="vareoncalc-field">
                      <label for="inflation-rate">${__('Inflation Rate', textDomain)}</label>
                      <input type="number" id="inflation-rate" data-suffix="${percentSuffix}" placeholder="2.5" min="0" max="100" step="0.1">
                    </div>
                    <div class="vareoncalc-field">
                      <label for="tax-rate">${__('Tax Rate', textDomain)}</label>
                      <input type="number" id="tax-rate" data-suffix="${percentSuffix}" placeholder="0" min="0" max="100" step="0.1">
                    </div>
                  </div>
                </div>
                <div class="vareoncalc-section savings-section savings-section--contribution-growth">
                  <div class="vareoncalc-section__header">
                    <div class="vareoncalc-section__title">${__('Contribution Growth', textDomain)}</div>
                  </div>
                  <div class="vareoncalc-field">
                    <label for="contribution-increase">${__('Annual Contribution Increase', textDomain)}</label>
                    <input type="number" id="contribution-increase" data-suffix="${percentSuffix}" placeholder="0" min="0" max="100" step="0.1">
                  </div>
                </div>
              </div>
            </div>

          </div>

          <!-- Wizard Navigation -->
          <div class="vareoncalc-wizard__nav">
            <button type="button" class="vareoncalc-btn vareoncalc-btn--outline" data-wizard-back>${__('Back', textDomain)}</button>
            <button type="button" class="vareoncalc-btn vareoncalc-btn--outline" data-wizard-skip>${__('Skip', textDomain)}</button>
            <button type="button" class="vareoncalc-btn" data-wizard-next>${__('Next', textDomain)}</button>
            <button type="button" class="vareoncalc-btn" data-wizard-finish>${__('Calculate Growth', textDomain)}</button>
          </div>

          <!-- Results Panel -->
          <div class="vareoncalc-wizard__results" data-wizard-results
               data-results-title="${__('The Snowball Effect', textDomain)}"
               data-results-subtitle="${__('Your projected wealth over time', textDomain)}"
               aria-hidden="true">
            <div class="vareoncalc-savings-results" id="result">
              <div class="vareoncalc-savings-hero">
                <div class="vareoncalc-savings-total" id="total-balance">$0.00</div>
                <div class="vareoncalc-savings-subtitle" id="result-subtitle">${__('Your projected balance', textDomain)}</div>
                <div class="vareoncalc-savings-real" id="purchasing-power" style="display: none;"></div>
              </div>

              <div class="vareoncalc-savings-breakdown">
                <div class="vareoncalc-composition-bar" aria-hidden="true">
                  <div class="vareoncalc-composition-bar__fill--principal" id="comp-bar-principal" style="width:100%"></div>
                  <div class="vareoncalc-composition-bar__fill--interest" id="comp-bar-interest" style="width:0%"></div>
                </div>
                <div class="vareoncalc-breakdown-metrics">
                  <div class="vareoncalc-breakdown-metric">
                    <span class="vareoncalc-breakdown-dot vareoncalc-breakdown-dot--principal"></span>
                    <div class="vareoncalc-breakdown-text">
                      <span class="vareoncalc-breakdown-label">${__('Total Deposited', textDomain)}</span>
                      <span class="vareoncalc-breakdown-value" id="stat-principal">$0</span>
                    </div>
                  </div>
                  <div class="vareoncalc-breakdown-metric vareoncalc-breakdown-metric--interest">
                    <span class="vareoncalc-breakdown-dot vareoncalc-breakdown-dot--interest"></span>
                    <div class="vareoncalc-breakdown-text">
                      <span class="vareoncalc-breakdown-label">${__('Interest Earned', textDomain)}</span>
                      <span class="vareoncalc-breakdown-value" id="stat-interest">+$0</span>
                    </div>
                  </div>
                </div>
                <div class="vareoncalc-growth-pill">
                  <span class="vareoncalc-growth-pill__arrow">&#8593;</span>
                  <span id="stat-growth">+0%</span>
                  <span class="vareoncalc-growth-pill__label">${__('total growth', textDomain)}</span>
                </div>
              </div>

              <div class="vareoncalc-savings-chart-section">
                <div class="vareoncalc-chart-header">
                  <span class="vareoncalc-chart-title">${__('Growth Over Time', textDomain)}</span>
                  <div class="vareoncalc-chart-legend">
                    <span class="vareoncalc-legend-item vareoncalc-legend-principal">
                      <span class="vareoncalc-legend-dot"></span>
                      ${__('Your Money', textDomain)}
                    </span>
                    <span class="vareoncalc-legend-item vareoncalc-legend-interest">
                      <span class="vareoncalc-legend-dot"></span>
                      ${__('Interest Earned', textDomain)}
                    </span>
                  </div>
                </div>
                <div class="vareoncalc-savings-chart" id="growth-chart"></div>
              </div>
            </div>
            <button type="button" class="vareoncalc-btn vareoncalc-btn--outline savings-wizard__restart" data-wizard-restart>${__('Start Over', textDomain)}</button>
          </div>

        </div>
      </div>
    </div>
  `;
  InputAdornment.apply(container);
  HelpTooltip.apply(container);

  // Collect input references
  const result = container.querySelector('#result');
  const apyInput = container.querySelector('#apy-input');
  const apyApply = container.querySelector('#apy-apply');
  const apyToggle = container.querySelector('#apy-toggle');
  const apyPanel = container.querySelector('#apy-converter-panel');
  const rateInput = container.querySelector('#interest-rate');
  const timingSelect = container.querySelector('#contribution-timing');
  const initialInput = container.querySelector('#initial-deposit');
  const monthlyInput = container.querySelector('#monthly-contribution');
  const yearsInput = container.querySelector('#time-period');
  const freqSelect = container.querySelector('#compound-frequency');
  const inflationInput = container.querySelector('#inflation-rate');
  const taxInput = container.querySelector('#tax-rate');
  const contributionIncreaseInput = container.querySelector('#contribution-increase');
  const purchasingPowerEl = container.querySelector('#purchasing-power');
  let cleanupGrowthChartHover = null;
  [initialInput, monthlyInput, rateInput, yearsInput, apyInput, inflationInput, taxInput, contributionIncreaseInput].forEach((input) => {
    input?.closest('.vareoncalc-input-adorned')?.classList.add('vareoncalc-input-adorned--suffix-rail');
  });

  // APY panel toggle (inline with Annual Rate label)
  const setApyPanelOpen = (open) => {
    if (!apyToggle || !apyPanel) {
      return;
    }
    apyToggle.setAttribute('aria-expanded', open ? 'true' : 'false');
    apyToggle.classList.toggle('is-active', open);
    apyPanel.hidden = !open;
  };

  if (apyToggle && apyPanel) {
    setApyPanelOpen(false);
    apyToggle.addEventListener('click', () => {
      setApyPanelOpen(apyPanel.hidden);
    });
  }

  // APY converter
  const applyApy = () => {
    if (!apyInput) {
      return;
    }
    const compoundFreq = parseInt(freqSelect.value);
    const apy = parseFloat(apyInput.value);
    if (!Number.isFinite(apy) || apy < 0) {
      ValidationHelpers.showError(apyInput, __('Please enter a valid APY percentage.', textDomain));
      return;
    }
    ValidationHelpers.clearAllErrors(container);
    const apyDecimal = apy / 100;
    const nominalRate = compoundFreq * (Math.pow(1 + apyDecimal, 1 / compoundFreq) - 1);
    const nominalPercent = nominalRate * 100;
    rateInput.value = nominalPercent.toFixed(6);
    apyInput.value = '';
    ValidationHelpers.showToast(container, __('APR updated from APY.', textDomain), { type: 'warning' });
    rateInput.dispatchEvent(new Event('input', { bubbles: true }));
  };

  if (apyApply) {
    apyApply.addEventListener('click', applyApy);
  }

  if (apyInput) {
    apyInput.addEventListener('keydown', (e) => {
      if (e.key === 'Enter') {
        e.preventDefault();
        applyApy();
      }
    });
  }

  // Helpers
  const formatNumber = (value, fractionDigits = 2) => {
    return (Math.round(value * Math.pow(10, fractionDigits)) / Math.pow(10, fractionDigits)).toLocaleString(undefined, {
      minimumFractionDigits: fractionDigits,
      maximumFractionDigits: fractionDigits
    });
  };

  const isValidOptionalPercent = (input) => {
    if (!input) {
      return true;
    }
    const raw = input.value;
    if (raw === '' || raw === null || raw === undefined) {
      return true;
    }
    const value = parseFloat(raw);
    return Number.isFinite(value) && value >= 0 && value <= 100;
  };

  const hasFundingInput = () => {
    const initialValue = parseFloat(initialInput?.value);
    const monthlyValue = parseFloat(monthlyInput?.value);
    return (Number.isFinite(initialValue) && initialValue > 0)
      || (Number.isFinite(monthlyValue) && monthlyValue > 0);
  };

  const markFundingInputsInvalid = () => {
    const validator = () => hasFundingInput();
    ValidationHelpers.markInvalid(initialInput, {
      allowEmpty: true,
      validator,
    });
    ValidationHelpers.markInvalid(monthlyInput, {
      allowEmpty: true,
      validator,
    });
  };

  // Chart layout constants (shared by generator + hover)
  const CRT = { w: 360, h: 210, pad: { top: 12, right: 12, bottom: 38, left: 50 } };
  CRT.cw = CRT.w - CRT.pad.left - CRT.pad.right;
  CRT.ch = CRT.h - CRT.pad.top - CRT.pad.bottom;

  // SVG chart generator
  const generateGrowthChart = (dataPoints) => {
    if (!dataPoints || dataPoints.length === 0) return '';

    const { w, h, pad, cw, ch } = CRT;
    const maxTotal = Math.max(...dataPoints.map(d => d.total));
    const maxYear = dataPoints[dataPoints.length - 1].year;
    if (maxTotal === 0 || maxYear === 0) return '';

    const sx = (year) => pad.left + (year / maxYear) * cw;
    const sy = (value) => pad.top + ch - (value / maxTotal) * ch;

    const gridLines = [];
    const yAxisLabels = [];
    for (let i = 1; i <= 3; i++) {
      const yVal = (maxTotal / 4) * i;
      const y = sy(yVal);
      gridLines.push(`<line x1="${pad.left}" y1="${y}" x2="${w - pad.right}" y2="${y}" class="vareoncalc-chart-gridline" />`);
      yAxisLabels.push(`<text x="${pad.left - 6}" y="${y + 3}" class="vareoncalc-chart-ylabel">${formatCompactCurrency(yVal)}</text>`);
    }

    let principalPath = `M ${sx(0)} ${sy(0)}`;
    dataPoints.forEach(d => { principalPath += ` L ${sx(d.year)} ${sy(d.principal)}`; });
    principalPath += ` L ${sx(maxYear)} ${sy(0)} Z`;

    let totalPath = `M ${sx(0)} ${sy(0)}`;
    dataPoints.forEach(d => { totalPath += ` L ${sx(d.year)} ${sy(d.total)}`; });
    totalPath += ` L ${sx(maxYear)} ${sy(0)} Z`;

    let interestLine = `M ${sx(dataPoints[0].year)} ${sy(dataPoints[0].total)}`;
    dataPoints.slice(1).forEach(d => { interestLine += ` L ${sx(d.year)} ${sy(d.total)}`; });

    let principalLine = `M ${sx(dataPoints[0].year)} ${sy(dataPoints[0].principal)}`;
    dataPoints.slice(1).forEach(d => { principalLine += ` L ${sx(d.year)} ${sy(d.principal)}`; });

    const yearLabels = [];
    const labelInterval = maxYear <= 5 ? 1 : maxYear <= 15 ? 2 : maxYear <= 30 ? 5 : 10;
    const yearLabelY = pad.top + ch + 15;
    for (let y = 0; y <= maxYear; y += labelInterval) {
      yearLabels.push(`<text x="${sx(y)}" y="${yearLabelY}" class="vareoncalc-chart-label">${y}</text>`);
    }
    if (maxYear % labelInterval !== 0) {
      yearLabels.push(`<text x="${sx(maxYear)}" y="${yearLabelY}" class="vareoncalc-chart-label">${maxYear}</text>`);
    }

    const gradientSuffix = Math.random().toString(36).slice(2, 9);
    const principalGradientId = `principalGradient-${gradientSuffix}`;
    const interestGradientId = `interestGradient-${gradientSuffix}`;

    return `
      <svg viewBox="0 0 ${w} ${h}" class="vareoncalc-growth-svg" preserveAspectRatio="xMidYMid meet" role="img" aria-label="${__('Savings growth over time', textDomain)}">
        <defs>
          <linearGradient id="${principalGradientId}" x1="0%" y1="0%" x2="0%" y2="100%">
            <stop offset="0%" style="stop-color: var(--vareoncalc-chart-principal, #3b82f6); stop-opacity: 0.6" />
            <stop offset="100%" style="stop-color: var(--vareoncalc-chart-principal, #3b82f6); stop-opacity: 0.15" />
          </linearGradient>
          <linearGradient id="${interestGradientId}" x1="0%" y1="0%" x2="0%" y2="100%">
            <stop offset="0%" style="stop-color: var(--vareoncalc-chart-interest, #10b981); stop-opacity: 0.7" />
            <stop offset="100%" style="stop-color: var(--vareoncalc-chart-interest, #10b981); stop-opacity: 0.2" />
          </linearGradient>
        </defs>

        ${gridLines.join('\n        ')}
        ${yAxisLabels.join('\n        ')}

        <path d="${totalPath}" fill="url(#${interestGradientId})" class="vareoncalc-area-interest" />
        <path d="${principalPath}" fill="url(#${principalGradientId})" class="vareoncalc-area-principal" />
        <path d="${interestLine}" fill="none" stroke="var(--vareoncalc-chart-interest, #10b981)" stroke-width="2" class="vareoncalc-line-interest" />
        <path d="${principalLine}" fill="none" stroke="var(--vareoncalc-chart-principal, #3b82f6)" stroke-width="2" class="vareoncalc-line-principal" />

        ${yearLabels.join('\n        ')}
        <text x="${(pad.left + w - pad.right) / 2}" y="${h - 4}" class="vareoncalc-chart-axis-label">${__('Years', textDomain)}</text>

        <line class="vareoncalc-chart-crosshair" x1="0" y1="${pad.top}" x2="0" y2="${pad.top + ch}" style="display:none" />
        <circle class="vareoncalc-chart-dot vareoncalc-chart-dot--principal" r="4.5" cx="0" cy="0" style="display:none" />
        <circle class="vareoncalc-chart-dot vareoncalc-chart-dot--total" r="4.5" cx="0" cy="0" style="display:none" />
        <rect class="vareoncalc-chart-overlay" x="${pad.left}" y="0" width="${cw}" height="${h}" fill="transparent" />
      </svg>
    `;
  };

  // Chart hover interaction
  const attachChartHover = (chartEl, dataPoints) => {
    const svg = chartEl.querySelector('.vareoncalc-growth-svg');
    if (!svg || !dataPoints || dataPoints.length < 2) return;

    const { w, pad, cw, ch } = CRT;
    const maxTotal = Math.max(...dataPoints.map(d => d.total));
    const maxYear = dataPoints[dataPoints.length - 1].year;
    if (maxTotal === 0 || maxYear === 0) return;

    const sx = (year) => pad.left + (year / maxYear) * cw;
    const sy = (value) => pad.top + ch - (value / maxTotal) * ch;

    const overlay = svg.querySelector('.vareoncalc-chart-overlay');
    const crosshair = svg.querySelector('.vareoncalc-chart-crosshair');
    const dotPrincipal = svg.querySelector('.vareoncalc-chart-dot--principal');
    const dotTotal = svg.querySelector('.vareoncalc-chart-dot--total');
    if (!overlay) return;

    let tooltip = chartEl.querySelector('.vareoncalc-chart-tooltip');
    if (!tooltip) {
      tooltip = document.createElement('div');
      tooltip.className = 'vareoncalc-chart-tooltip';
      chartEl.appendChild(tooltip);
    }

    const hideHover = () => {
      if (crosshair) crosshair.style.display = 'none';
      if (dotPrincipal) dotPrincipal.style.display = 'none';
      if (dotTotal) dotTotal.style.display = 'none';
      tooltip.style.display = 'none';
    };

    const handleMouseMove = (e) => {
      const overlayRect = overlay.getBoundingClientRect();
      const containerRect = chartEl.getBoundingClientRect();
      const yearApprox = mapHoverClientXToYear(e.clientX, overlayRect, maxYear);

      const nearest = findNearestPoint(dataPoints, yearApprox, (point) => point.year);
      if (!nearest) {
        hideHover();
        return;
      }

      const x = sx(nearest.year);
      const yP = sy(nearest.principal);
      const yT = sy(nearest.total);

      if (crosshair) {
        crosshair.setAttribute('x1', x);
        crosshair.setAttribute('x2', x);
        crosshair.style.display = '';
      }
      if (dotPrincipal) {
        dotPrincipal.setAttribute('cx', x);
        dotPrincipal.setAttribute('cy', yP);
        dotPrincipal.style.display = '';
      }
      if (dotTotal) {
        dotTotal.setAttribute('cx', x);
        dotTotal.setAttribute('cy', yT);
        dotTotal.style.display = '';
      }

      const yearText = nearest.year % 1 === 0
        ? __('Year', textDomain) + ' ' + Math.round(nearest.year)
        : __('Year', textDomain) + ' ' + nearest.year.toFixed(1);

      tooltip.innerHTML = `
        <div class="vareoncalc-chart-tooltip__year">${yearText}</div>
        <div class="vareoncalc-chart-tooltip__row">
          <span class="vareoncalc-chart-tooltip__dot vareoncalc-chart-tooltip__dot--principal"></span>
          <span class="vareoncalc-chart-tooltip__label">${__('Your Money', textDomain)}</span>
          <span class="vareoncalc-chart-tooltip__value">${formatCurrencyHtml(nearest.principal)}</span>
        </div>
        <div class="vareoncalc-chart-tooltip__row">
          <span class="vareoncalc-chart-tooltip__dot vareoncalc-chart-tooltip__dot--interest"></span>
          <span class="vareoncalc-chart-tooltip__label">${__('Balance', textDomain)}</span>
          <span class="vareoncalc-chart-tooltip__value">${formatCurrencyHtml(nearest.total)}</span>
        </div>
      `;

      positionChartTooltip(tooltip, e.clientX, e.clientY, containerRect);
      tooltip.style.display = 'block';
    };

    overlay.addEventListener('mousemove', handleMouseMove);
    overlay.addEventListener('mouseleave', hideHover);

    return () => {
      overlay.removeEventListener('mousemove', handleMouseMove);
      overlay.removeEventListener('mouseleave', hideHover);
      if (tooltip && tooltip.parentNode === chartEl) {
        chartEl.removeChild(tooltip);
      }
    };
  };

  // Main calculation function
  const calculate = () => {
    ValidationHelpers.clearAllErrors(container);

    const initialDeposit = parseFloat(initialInput.value) || 0;
    const monthlyContribution = parseFloat(monthlyInput.value) || 0;
    const annualRate = parseFloat(rateInput.value);
    const years = parseFloat(yearsInput.value);
    const compoundFreq = parseInt(freqSelect.value);
    const contributionTiming = timingSelect?.value === 'end' ? 'end' : 'beginning';

    if (!hasFundingInput()) {
      markFundingInputsInvalid();
      ValidationHelpers.showResultError(
        result,
        __('Please enter an initial deposit or monthly contribution.', textDomain)
      );
      return;
    }

    if (isNaN(annualRate) || annualRate < 0 || annualRate > 100) {
      ValidationHelpers.markInvalid(rateInput, {
        validator: () => {
          const value = parseFloat(rateInput.value);
          return Number.isFinite(value) && value >= 0 && value <= 100;
        },
      });
      ValidationHelpers.showResultError(result, __('Please enter a valid interest rate (0-100%).', textDomain));
      return;
    }

    if (isNaN(years) || years <= 0 || years > 50) {
      ValidationHelpers.markInvalid(yearsInput, {
        validator: () => {
          const value = parseFloat(yearsInput.value);
          return Number.isFinite(value) && value > 0 && value <= 50;
        },
      });
      ValidationHelpers.showResultError(result, __('Please enter a valid time period (1-50 years).', textDomain));
      return;
    }

    const inflationRaw = inflationInput?.value ?? '';
    const taxRaw = taxInput?.value ?? '';
    const increaseRaw = contributionIncreaseInput?.value ?? '';

    const inflationRate = inflationRaw === '' ? 0 : parseFloat(inflationRaw);
    if (!Number.isFinite(inflationRate) || inflationRate < 0 || inflationRate > 100) {
      ValidationHelpers.markInvalid(inflationInput, {
        allowEmpty: true,
        validator: () => {
          const raw = inflationInput?.value ?? '';
          if (raw === '') {
            return true;
          }
          const value = parseFloat(raw);
          return Number.isFinite(value) && value >= 0 && value <= 100;
        },
      });
      ValidationHelpers.showResultError(result, __('Please enter a valid inflation rate (0-100%).', textDomain));
      return;
    }

    const taxRate = taxRaw === '' ? 0 : parseFloat(taxRaw);
    if (!Number.isFinite(taxRate) || taxRate < 0 || taxRate > 100) {
      ValidationHelpers.markInvalid(taxInput, {
        allowEmpty: true,
        validator: () => {
          const raw = taxInput?.value ?? '';
          if (raw === '') {
            return true;
          }
          const value = parseFloat(raw);
          return Number.isFinite(value) && value >= 0 && value <= 100;
        },
      });
      ValidationHelpers.showResultError(result, __('Please enter a valid tax rate (0-100%).', textDomain));
      return;
    }

    const contributionIncrease = increaseRaw === '' ? 0 : parseFloat(increaseRaw);
    if (!Number.isFinite(contributionIncrease) || contributionIncrease < 0 || contributionIncrease > 100) {
      ValidationHelpers.markInvalid(contributionIncreaseInput, {
        allowEmpty: true,
        validator: () => {
          const raw = contributionIncreaseInput?.value ?? '';
          if (raw === '') {
            return true;
          }
          const value = parseFloat(raw);
          return Number.isFinite(value) && value >= 0 && value <= 100;
        },
      });
      ValidationHelpers.showResultError(result, __('Please enter a valid contribution increase (0-100%).', textDomain));
      return;
    }

    const effectiveNominalRate = (annualRate * (1 - (taxRate / 100))) / 100;
    const compoundsPerYear = compoundFreq;
    const months = Math.max(1, Math.round(years * 12));

    const ratePerPeriod = compoundsPerYear > 0 ? effectiveNominalRate / compoundsPerYear : 0;
    const monthlyRate = compoundsPerYear > 0
      ? Math.pow(1 + ratePerPeriod, compoundsPerYear / 12) - 1
      : 0;

    let currentBalance = initialDeposit;
    let totalPrincipal = initialDeposit;
    let currentMonthlyContribution = monthlyContribution;

    const dataPoints = [{
      year: 0,
      principal: totalPrincipal,
      interest: 0,
      total: currentBalance
    }];

    for (let month = 1; month <= months; month++) {
      if (contributionIncrease > 0 && month > 1 && (month - 1) % 12 === 0) {
        currentMonthlyContribution *= (1 + (contributionIncrease / 100));
      }

      const monthlyContrib = currentMonthlyContribution;

      if (contributionTiming === 'beginning') {
        currentBalance += monthlyContrib;
        totalPrincipal += monthlyContrib;
      }

      currentBalance *= (1 + monthlyRate);

      if (contributionTiming === 'end') {
        currentBalance += monthlyContrib;
        totalPrincipal += monthlyContrib;
      }

      if (month % 12 === 0) {
        dataPoints.push({
          year: month / 12,
          principal: totalPrincipal,
          interest: currentBalance - totalPrincipal,
          total: currentBalance
        });
      }
    }

    if (months % 12 !== 0) {
      dataPoints.push({
        year: months / 12,
        principal: totalPrincipal,
        interest: currentBalance - totalPrincipal,
        total: currentBalance
      });
    }

    const totalInterest = currentBalance - totalPrincipal;
    const interestPercent = totalPrincipal > 0 ? (totalInterest / totalPrincipal) * 100 : 0;
    const inflationFactor = inflationRate > 0
      ? Math.pow(1 + (inflationRate / 100), months / 12)
      : 1;
    const purchasingPower = inflationFactor > 0 ? currentBalance / inflationFactor : currentBalance;

    container.querySelector('#total-balance').innerHTML = formatCurrencyHtml(currentBalance);
    container.querySelector('#result-subtitle').textContent = sprintf(
      __('Nominal balance in %d years', textDomain),
      Math.round(years)
    );

    if (purchasingPowerEl) {
      if (inflationRate > 0) {
        purchasingPowerEl.style.display = 'inline-flex';
        purchasingPowerEl.innerHTML = `
          <span class="vareoncalc-savings-real__label">${__('Real purchasing power:', textDomain)}</span>
          <span class="vareoncalc-savings-real__value">${formatCurrencyHtml(purchasingPower)}</span>
        `;
      } else {
        purchasingPowerEl.style.display = 'none';
        purchasingPowerEl.textContent = '';
      }
    }

    const principalPct = currentBalance > 0 ? (totalPrincipal / currentBalance) * 100 : 100;
    const interestPct = currentBalance > 0 ? (totalInterest / currentBalance) * 100 : 0;
    container.querySelector('#comp-bar-principal').style.width = principalPct.toFixed(1) + '%';
    container.querySelector('#comp-bar-interest').style.width = interestPct.toFixed(1) + '%';

    const chartEl = container.querySelector('#growth-chart');
    if (typeof cleanupGrowthChartHover === 'function') {
      cleanupGrowthChartHover();
      cleanupGrowthChartHover = null;
    }
    chartEl.innerHTML = generateGrowthChart(dataPoints);
    cleanupGrowthChartHover = attachChartHover(chartEl, dataPoints);

    container.querySelector('#stat-principal').innerHTML = formatCurrencyHtml(totalPrincipal);
    container.querySelector('#stat-interest').innerHTML = '+' + formatCurrencyHtml(totalInterest);
    container.querySelector('#stat-growth').textContent = '+' + formatNumber(interestPercent, 1) + '%';

    result.style.display = 'flex';
  };

  // Step-level validation for the wizard
  const validateStep = ({ stepId }) => {
    if (stepId === 'capital' || stepId === '0') {
      if (!hasFundingInput()) {
        markFundingInputsInvalid();
        return __('Please enter an initial deposit or monthly contribution.', textDomain);
      }
      return true;
    }

    if (stepId === 'engine' || stepId === '1') {
      let message = '';
      const annualRate = parseFloat(rateInput.value);
      if (isNaN(annualRate) || annualRate < 0 || annualRate > 100) {
        ValidationHelpers.markInvalid(rateInput);
        message = message || __('Please enter a valid interest rate (0-100%).', textDomain);
      }

      const years = parseFloat(yearsInput.value);
      if (isNaN(years) || years <= 0 || years > 50) {
        ValidationHelpers.markInvalid(yearsInput);
        message = message || __('Please enter a valid time period (1-50 years).', textDomain);
      }

      return message ? message : true;
    }

    if (stepId === 'advanced' || stepId === '3') {
      let message = '';
      if (!isValidOptionalPercent(inflationInput)) {
        ValidationHelpers.markInvalid(inflationInput, {
          allowEmpty: true,
          validator: () => isValidOptionalPercent(inflationInput),
        });
        message = message || __('Please enter a valid inflation rate (0-100%).', textDomain);
      }
      if (!isValidOptionalPercent(taxInput)) {
        ValidationHelpers.markInvalid(taxInput, {
          allowEmpty: true,
          validator: () => isValidOptionalPercent(taxInput),
        });
        message = message || __('Please enter a valid tax rate (0-100%).', textDomain);
      }
      if (!isValidOptionalPercent(contributionIncreaseInput)) {
        ValidationHelpers.markInvalid(contributionIncreaseInput, {
          allowEmpty: true,
          validator: () => isValidOptionalPercent(contributionIncreaseInput),
        });
        message = message || __('Please enter a valid contribution increase (0-100%).', textDomain);
      }
      return message ? message : true;
    }

    return true;
  };

  // Initialize wizard skeleton
  const wizardRoot = container.querySelector('.vareoncalc-wizard');

  const wizard = initWizardSkeleton(wizardRoot, {
    initialStep: 0,
    validateStep,
  });

  // Hook: run calculate() whenever the wizard enters the results state
  if (wizard && wizardRoot) {
    const observer = new MutationObserver((mutations) => {
      for (const mutation of mutations) {
        if (mutation.type === 'attributes' && mutation.attributeName === 'data-wizard-state') {
          if (wizardRoot.dataset.wizardState === 'results') {
            calculate();
          }
        }
      }
    });
    observer.observe(wizardRoot, { attributes: true, attributeFilter: ['data-wizard-state'] });

    // Reset the results when restarting
    const restartBtn = container.querySelector('[data-wizard-restart]');
    if (restartBtn) {
      restartBtn.addEventListener('click', () => {
        if (typeof cleanupGrowthChartHover === 'function') {
          cleanupGrowthChartHover();
          cleanupGrowthChartHover = null;
        }
        result.style.display = 'none';
        container.querySelector('#total-balance').textContent = '$0.00';
        container.querySelector('#result-subtitle').textContent = __('Your projected balance', textDomain);
        container.querySelector('#growth-chart').innerHTML = '';
        container.querySelector('#stat-principal').textContent = '$0';
        container.querySelector('#stat-interest').textContent = '+$0';
        container.querySelector('#stat-growth').textContent = '+0%';
        container.querySelector('#comp-bar-principal').style.width = '100%';
        container.querySelector('#comp-bar-interest').style.width = '0%';
        if (purchasingPowerEl) {
          purchasingPowerEl.style.display = 'none';
          purchasingPowerEl.textContent = '';
        }
      });
    }
  }
}
