/**
 * Wizard skeleton helper for Pro calculators.
 *
 * Expected HTML skeleton:
 * <div class="vareoncalc-wizard" data-wizard>
 *   <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>
 *   <div class="vareoncalc-wizard__track" data-wizard-track>
 *     <button type="button" data-wizard-track-step data-step-index="0">1</button>
 *   </div>
 *   <div class="vareoncalc-wizard__body">
 *     <div class="vareoncalc-wizard__step"
 *       data-wizard-step
 *       data-step-title="Step title"
 *       data-step-subtitle="Optional subtitle"
 *       data-step-optional="true">
 *       <!-- step fields -->
 *     </div>
 *   </div>
 *   <div class="vareoncalc-wizard__nav">
 *     <button type="button" data-wizard-back>Back</button>
 *     <button type="button" data-wizard-skip>Skip</button>
 *     <button type="button" data-wizard-next>Next</button>
 *     <button type="button" data-wizard-finish>See results</button>
 *   </div>
 *   <div class="vareoncalc-wizard__results" data-wizard-results aria-hidden="true">
 *     <!-- results -->
 *     <button type="button" data-wizard-restart>Start over</button>
 *   </div>
 * </div>
 *
 * Optional notes:
 * - data-wizard-step can carry an ID (ex: data-wizard-step="snapshot") for lookups.
 * - data-step-optional="true" enables Skip for that step.
 * - data-results-title / data-results-subtitle can populate the header on results.
 */

import { __, sprintf, ValidationHelpers } from '@vareoncalc/calculator-base';

const DEFAULT_SELECTORS = {
  root: '.vareoncalc-wizard',
  step: '[data-wizard-step]',
  results: '[data-wizard-results]',
  back: '[data-wizard-back]',
  next: '[data-wizard-next]',
  skip: '[data-wizard-skip]',
  finish: '[data-wizard-finish]',
  restart: '[data-wizard-restart]',
  indicator: '[data-wizard-indicator]',
  title: '[data-wizard-title]',
  subtitle: '[data-wizard-subtitle]',
  progress: '[data-wizard-progress]',
  trackStep: '[data-wizard-track-step]'
};

const DEFAULT_MESSAGES = {
  stepIndicator: __( 'Step %d of %d', 'vareon-calculator-suite-lite' ),
  resultsIndicator: __( 'Results', 'vareon-calculator-suite-lite' ),
  invalidStep: __( 'Please complete the required fields before continuing.', 'vareon-calculator-suite-lite' )
};

/**
 * Initialize wizard skeleton behavior for a container or root element.
 * @param {HTMLElement} container
 * @param {Object} [options]
 * @param {Object} [options.selectors]
 * @param {number} [options.initialStep]
 * @param {Function} [options.validateStep]
 * @returns {Object|Object[]|null}
 */
export function initWizardSkeleton(container, options = {}) {
  if (!container) {
    return null;
  }

  const selectors = { ...DEFAULT_SELECTORS, ...(options.selectors || {}) };
  const rootSelector = selectors.root || DEFAULT_SELECTORS.root;
  const roots = container.classList?.contains('vareoncalc-wizard')
    ? [container]
    : Array.from(container.querySelectorAll(rootSelector));

  if (roots.length === 0) {
    return null;
  }

  const instances = roots.map(root => initWizardSkeletonRoot(root, selectors, options));
  return instances.length === 1 ? instances[0] : instances;
}

function initWizardSkeletonRoot(root, selectors, options) {
  const stepElements = Array.from(root.querySelectorAll(selectors.step));
  const resultsPanel = root.querySelector(selectors.results);
  const indicatorEl = root.querySelector(selectors.indicator);
  const titleEl = root.querySelector(selectors.title);
  const subtitleEl = root.querySelector(selectors.subtitle);
  const progressEls = Array.from(root.querySelectorAll(selectors.progress));
  const trackButtons = Array.from(root.querySelectorAll(selectors.trackStep));
  const backButtons = root.querySelectorAll(selectors.back);
  const nextButtons = root.querySelectorAll(selectors.next);
  const skipButtons = root.querySelectorAll(selectors.skip);
  const finishButtons = root.querySelectorAll(selectors.finish);
  const restartButtons = root.querySelectorAll(selectors.restart);

  const steps = stepElements.map((stepEl, index) => {
    if (!stepEl.dataset.stepIndex) {
      stepEl.dataset.stepIndex = String(index);
    }
    return {
      index,
      id: getStepId(stepEl, index),
      title: stepEl.dataset.stepTitle || '',
      subtitle: stepEl.dataset.stepSubtitle || '',
      optional: isOptionalStep(stepEl),
      element: stepEl
    };
  });
  const totalSteps = steps.length;
  const stepIndexById = new Map();
  steps.forEach(step => {
    if (step.id) {
      stepIndexById.set(step.id, step.index);
    }
  });

  const trackItems = trackButtons.map((button, fallbackIndex) => {
    const resolvedIndex = resolveTrackIndex(button, stepIndexById, fallbackIndex);
    if (Number.isFinite(resolvedIndex)) {
      button.dataset.stepIndex = String(resolvedIndex);
    }
    return {
      button,
      index: Number.isFinite(resolvedIndex) ? resolvedIndex : fallbackIndex
    };
  });

  const state = {
    stepIndex: normalizeStepIndex(options.initialStep, totalSteps),
    isResults: false
  };

  const listeners = [];

  function addListener(element, type, handler) {
    element.addEventListener(type, handler);
    listeners.push({ element, type, handler });
  }

  function setInertState(element, isInert) {
    if (!element) {
      return;
    }
    if ('inert' in element) {
      element.inert = isInert;
      return;
    }
    if (isInert) {
      element.setAttribute('inert', '');
    } else {
      element.removeAttribute('inert');
    }
  }

  function updateHeader() {
    if (indicatorEl) {
      indicatorEl.textContent = state.isResults
        ? DEFAULT_MESSAGES.resultsIndicator
        : sprintf(DEFAULT_MESSAGES.stepIndicator, state.stepIndex + 1, totalSteps);
    }

    if (titleEl) {
      if (state.isResults) {
        titleEl.textContent = resultsPanel?.dataset.resultsTitle || '';
      } else {
        titleEl.textContent = steps[state.stepIndex]?.title || '';
      }
    }

    if (subtitleEl) {
      if (state.isResults) {
        subtitleEl.textContent = resultsPanel?.dataset.resultsSubtitle || '';
      } else {
        subtitleEl.textContent = steps[state.stepIndex]?.subtitle || '';
      }
    }
  }

  function updateProgress() {
    if (progressEls.length === 0) {
      return;
    }

    let percent = 0;
    if (totalSteps > 0) {
      percent = state.isResults ? 100 : Math.round(((state.stepIndex + 1) / totalSteps) * 100);
    }

    progressEls.forEach(el => {
      el.style.width = `${percent}%`;
    });
  }

  function updateTrack() {
    if (trackItems.length === 0) {
      return;
    }

    const currentIndex = state.isResults ? totalSteps : state.stepIndex;
    trackItems.forEach(item => {
      const targetIndex = clamp(item.index, 0, Math.max(totalSteps - 1, 0));
      const isActive = !state.isResults && targetIndex === state.stepIndex;
      const isComplete = targetIndex < currentIndex;
      const isDisabled = targetIndex > currentIndex;

      item.button.classList.toggle('is-active', isActive);
      item.button.classList.toggle('is-complete', isComplete);
      item.button.toggleAttribute('disabled', isDisabled);
      item.button.setAttribute('aria-disabled', isDisabled ? 'true' : 'false');
      if (isActive) {
        item.button.setAttribute('aria-current', 'step');
      } else {
        item.button.removeAttribute('aria-current');
      }
    });
  }

  function updateNav() {
    const isFirst = state.stepIndex <= 0;
    const isLast = state.stepIndex >= totalSteps - 1;
    const currentStep = steps[state.stepIndex];
    const isOptional = currentStep?.optional;
    const showNav = !state.isResults;

    backButtons.forEach(btn => setButtonVisibility(btn, showNav && !isFirst));
    nextButtons.forEach(btn => setButtonVisibility(btn, showNav && !isLast));
    finishButtons.forEach(btn => setButtonVisibility(btn, showNav && isLast));
    skipButtons.forEach(btn => setButtonVisibility(btn, showNav && isOptional));
  }

  function updateStepsVisibility() {
    steps.forEach(step => {
      const isActive = !state.isResults && step.index === state.stepIndex;
      step.element.classList.toggle('vareoncalc-wizard__step--active', isActive);
      step.element.setAttribute('aria-hidden', isActive ? 'false' : 'true');
      setInertState(step.element, !isActive);
    });

    if (resultsPanel) {
      const isActive = state.isResults;
      resultsPanel.classList.toggle('vareoncalc-wizard__results--active', isActive);
      resultsPanel.setAttribute('aria-hidden', isActive ? 'false' : 'true');
      setInertState(resultsPanel, !isActive);
    }
  }

  function updateRootState() {
    root.dataset.wizardState = state.isResults ? 'results' : 'steps';
    root.dataset.wizardStepIndex = String(state.stepIndex);
    root.dataset.wizardSteps = String(totalSteps);
  }

  function updateUI() {
    updateStepsVisibility();
    updateHeader();
    updateProgress();
    updateTrack();
    updateNav();
    updateRootState();
  }

  function validateCurrentStep() {
    if (typeof options.validateStep !== 'function' || totalSteps === 0) {
      return true;
    }

    const currentStep = steps[state.stepIndex];
    const result = options.validateStep({
      stepIndex: state.stepIndex,
      stepId: currentStep?.id || '',
      stepElement: currentStep?.element || null,
      isLastStep: state.stepIndex === totalSteps - 1,
      isOptional: currentStep?.optional || false
    });

    if (result === true || typeof result === 'undefined') {
      return true;
    }

    if (result === false) {
      ValidationHelpers.showToast(root, DEFAULT_MESSAGES.invalidStep);
      return false;
    }

    if (typeof result === 'string') {
      ValidationHelpers.showToast(root, result);
      return false;
    }

    if (typeof result === 'object') {
      if (result.valid === true) {
        return true;
      }
      ValidationHelpers.showToast(root, result.message || DEFAULT_MESSAGES.invalidStep);
      return false;
    }

    return true;
  }

  function setStep(nextIndex) {
    state.stepIndex = normalizeStepIndex(nextIndex, totalSteps);
    state.isResults = false;
    ValidationHelpers.hideToast(root);
    updateUI();
  }

  function showResults() {
    if (!resultsPanel) {
      return;
    }
    state.isResults = true;
    ValidationHelpers.hideToast(root);
    updateUI();
  }

  function restart() {
    state.stepIndex = 0;
    state.isResults = false;
    ValidationHelpers.hideToast(root);
    updateUI();
  }

  const handleBack = (event) => {
    event.preventDefault();
    if (state.isResults) {
      setStep(totalSteps - 1);
      return;
    }
    setStep(state.stepIndex - 1);
  };

  const handleNext = (event) => {
    event.preventDefault();
    if (!validateCurrentStep()) {
      return;
    }
    if (state.stepIndex >= totalSteps - 1) {
      showResults();
      return;
    }
    setStep(state.stepIndex + 1);
  };

  const handleSkip = (event) => {
    event.preventDefault();
    const currentStep = steps[state.stepIndex];
    if (!currentStep?.optional) {
      return;
    }
    if (state.stepIndex >= totalSteps - 1) {
      showResults();
      return;
    }
    setStep(state.stepIndex + 1);
  };

  const handleFinish = (event) => {
    event.preventDefault();
    if (!validateCurrentStep()) {
      return;
    }
    showResults();
  };

  const handleRestart = (event) => {
    event.preventDefault();
    restart();
  };

  const handleTrackClick = (event) => {
    event.preventDefault();
    const target = event.currentTarget;
    const rawIndex = target.dataset.stepIndex;
    const targetIndex = Number.parseInt(rawIndex, 10);
    if (!Number.isFinite(targetIndex)) {
      return;
    }
    const currentIndex = state.isResults ? totalSteps : state.stepIndex;
    if (targetIndex < currentIndex) {
      setStep(targetIndex);
    }
  };

  backButtons.forEach(btn => addListener(btn, 'click', handleBack));
  nextButtons.forEach(btn => addListener(btn, 'click', handleNext));
  skipButtons.forEach(btn => addListener(btn, 'click', handleSkip));
  finishButtons.forEach(btn => addListener(btn, 'click', handleFinish));
  restartButtons.forEach(btn => addListener(btn, 'click', handleRestart));
  trackItems.forEach(item => addListener(item.button, 'click', handleTrackClick));

  updateUI();

  return {
    root,
    setStep,
    showResults,
    restart,
    getState: () => ({ ...state, totalSteps }),
    destroy: () => {
      listeners.forEach(({ element, type, handler }) => {
        element.removeEventListener(type, handler);
      });
    }
  };
}

function getStepId(stepEl, index) {
  const rawId = stepEl.getAttribute('data-wizard-step');
  if (rawId && rawId.trim()) {
    return rawId.trim();
  }
  if (stepEl.dataset.stepId) {
    return stepEl.dataset.stepId;
  }
  if (stepEl.id) {
    return stepEl.id;
  }
  return String(index);
}

function isOptionalStep(stepEl) {
  const flag = stepEl.dataset.stepOptional;
  return flag === '' || flag === 'true' || flag === '1';
}

function resolveTrackIndex(button, stepIndexById, fallbackIndex) {
  const rawIndex = button.dataset.stepIndex;
  if (rawIndex !== undefined && rawIndex !== '') {
    const parsed = Number.parseInt(rawIndex, 10);
    if (Number.isFinite(parsed)) {
      return parsed;
    }
  }

  const stepId = button.dataset.stepId || button.dataset.wizardStep;
  if (stepId && stepIndexById.has(stepId)) {
    return stepIndexById.get(stepId);
  }

  return fallbackIndex;
}

function normalizeStepIndex(value, totalSteps) {
  if (!Number.isFinite(totalSteps) || totalSteps <= 0) {
    return 0;
  }
  const parsed = Number.isFinite(value) ? value : Number.parseInt(value, 10);
  if (!Number.isFinite(parsed)) {
    return 0;
  }
  return clamp(parsed, 0, totalSteps - 1);
}

function clamp(value, min, max) {
  return Math.min(Math.max(value, min), max);
}

function setButtonVisibility(button, isVisible) {
  if (!button) {
    return;
  }
  button.style.display = isVisible ? '' : 'none';
  button.toggleAttribute('disabled', !isVisible);
}
