/**
 * Compact two-step layout helper for Pro calculators.
 *
 * Expected HTML skeleton:
 * <div class="vareoncalc-two-step" data-two-step>
 *   <div class="vareoncalc-two-step__step vareoncalc-two-step__step--inputs" data-two-step-step="inputs">
 *     <div class="vareoncalc-two-step__inputs-body">
 *       <!-- inputs -->
 *     </div>
 *     <button type="button" data-two-step-next>See results</button>
 *     <button type="button" data-two-step-toggle>Edit inputs</button>
 *   </div>
 *   <div class="vareoncalc-two-step__step vareoncalc-two-step__step--results" data-two-step-step="results" aria-hidden="true">
 *     <div class="vareoncalc-two-step__results">
 *       <!-- results -->
 *     </div>
 *   </div>
 * </div>
 *
 * Optional controls:
 * - data-two-step-back: return to inputs step
 * - data-two-step-close: close drawer while in results step
 *
 * Notes:
 * - Inputs remain in a single DOM location to preserve values.
 * - Blind mode slides inputs over results; drawer mode uses CSS when
 *   .vareoncalc-two-step--drawer-open is set.
 */

const DEFAULT_SELECTORS = {
  root: '.vareoncalc-two-step',
  step: '.vareoncalc-two-step__step',
  inputsStep: '[data-two-step-step="inputs"]',
  resultsStep: '[data-two-step-step="results"]',
  next: '[data-two-step-next]',
  back: '[data-two-step-back]',
  toggle: '[data-two-step-toggle]',
  close: '[data-two-step-close]'
};

const DEFAULT_MODE = 'blind';

/**
 * Initialize compact two-step behavior for a container or root element.
 * @param {HTMLElement} container
 * @param {Object} [options]
 * @param {Object} [options.selectors]
 * @param {'inputs'|'results'} [options.initialStep]
 * @param {boolean} [options.initialDrawerOpen]
 * @param {Function|boolean} [options.canProceed]
 * @returns {Object|Object[]|null}
 */
export function initCompactTwoStep(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-two-step')
    ? [container]
    : Array.from(container.querySelectorAll(rootSelector));

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

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

function initCompactTwoStepRoot(root, selectors, options) {
  const inputsStep = root.querySelector(selectors.inputsStep) || root.querySelector('.vareoncalc-two-step__step--inputs');
  const resultsStep = root.querySelector(selectors.resultsStep) || root.querySelector('.vareoncalc-two-step__step--results');
  const inputsBody = inputsStep ? inputsStep.querySelector('.vareoncalc-two-step__inputs-body') : null;
  const resultsBody = resultsStep ? resultsStep.querySelector('.vareoncalc-two-step__results') : null;
  const nextButtons = root.querySelectorAll(selectors.next);
  const backButtons = root.querySelectorAll(selectors.back);
  const toggleButtons = root.querySelectorAll(selectors.toggle);
  const closeButtons = root.querySelectorAll(selectors.close);

  const mode = normalizeMode(options.mode || root.dataset.twoStepMode || DEFAULT_MODE);
  const isBlindMode = mode === 'blind';
  root.dataset.twoStepMode = mode;
  const canProceed = options.canProceed;

  const initialStep = normalizeStep(options.initialStep || root.dataset.step || 'inputs');
  const initialDrawerOpen = !isBlindMode && typeof options.initialDrawerOpen === 'boolean'
    ? options.initialDrawerOpen
    : root.dataset.drawerOpen === 'true';

  const state = {
    step: initialStep,
    drawerOpen: initialStep === 'results' ? initialDrawerOpen : false
  };

  const listeners = [];
  const widthState = {
    lockedWidth: 0,
    hostWidth: 0,
    resizeTimer: null,
    resizeObserver: null,
    hostObserver: null,
    rafId: null
  };
  const animationState = {
    timer: null
  };
  const layoutSyncState = {
    rafIds: [],
    settleTimer: null
  };
  const layoutHeightState = {
    contentResizeObserver: null,
    visualViewportHandler: null,
    queuedRefreshRaf: null
  };

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

  function ensureInputsId() {
    if (!inputsStep) {
      return null;
    }

    if (!inputsStep.id) {
      const uid = Math.random().toString(36).slice(2, 9);
      inputsStep.id = `vareoncalc-two-step-inputs-${uid}`;
    }

    return inputsStep.id;
  }

  function syncToggleAria() {
    const inputsId = ensureInputsId();
    const isExpanded = isBlindMode ? state.step === 'inputs' : state.drawerOpen;
    toggleButtons.forEach((btn) => {
      if (inputsId && !btn.hasAttribute('aria-controls')) {
        btn.setAttribute('aria-controls', inputsId);
      }
      btn.setAttribute('aria-expanded', isExpanded ? 'true' : 'false');
    });
  }

  function updateAria() {
    const showInputs = isBlindMode
      ? state.step === 'inputs'
      : state.step === 'inputs' || (state.step === 'results' && state.drawerOpen);
    const showResults = state.step === 'results';

    if (inputsStep) {
      if (isBlindMode) {
        inputsStep.setAttribute('aria-hidden', 'false');
      } else {
        inputsStep.setAttribute('aria-hidden', showInputs ? 'false' : 'true');
      }
    }

    if (inputsBody && isBlindMode) {
      inputsBody.setAttribute('aria-hidden', showInputs ? 'false' : 'true');
      if ('inert' in inputsBody) {
        inputsBody.inert = !showInputs;
      } else if (showInputs) {
        inputsBody.removeAttribute('inert');
      } else {
        inputsBody.setAttribute('inert', '');
      }
    }
    if (resultsStep) {
      const resultsVisible = isBlindMode ? showResults : showResults && !state.drawerOpen;
      resultsStep.setAttribute('aria-hidden', resultsVisible ? 'false' : 'true');
    }
  }

  function updateClasses() {
    const showInputs = isBlindMode
      ? state.step === 'inputs'
      : state.step === 'inputs' || (state.step === 'results' && state.drawerOpen);
    const showResults = state.step === 'results';

    if (inputsStep) {
      inputsStep.classList.toggle('vareoncalc-two-step__step--active', showInputs);
    }
    if (resultsStep) {
      resultsStep.classList.toggle('vareoncalc-two-step__step--active', showResults);
    }

    root.classList.toggle('vareoncalc-two-step--drawer-open', !isBlindMode && state.step === 'results' && state.drawerOpen);
    root.classList.toggle('vareoncalc-two-step--blind', isBlindMode);
    root.dataset.step = state.step;
    root.dataset.drawerOpen = state.drawerOpen ? 'true' : 'false';
  }

  function applyLayoutHeight() {
    if (!root.classList.contains('is-animating')) {
      root.style.minHeight = '';
      return;
    }
    const inputsHeight = inputsBody ? inputsBody.scrollHeight : 0;
    const resultsHeight = resultsBody ? resultsBody.scrollHeight : 0;
    const handleHeight = toggleButtons.length > 0 ? toggleButtons[0].getBoundingClientRect().height : 0;
    const nextHeight = state.step === 'results'
      ? Math.max(resultsHeight, handleHeight)
      : inputsHeight;
    if (nextHeight > 0) {
      root.style.minHeight = `${Math.ceil(nextHeight)}px`;
    }
  }

  function clearPendingLayoutSync() {
    if (typeof window === 'undefined') {
      return;
    }
    while (layoutSyncState.rafIds.length > 0) {
      window.cancelAnimationFrame(layoutSyncState.rafIds.pop());
    }
    if (layoutSyncState.settleTimer) {
      window.clearTimeout(layoutSyncState.settleTimer);
      layoutSyncState.settleTimer = null;
    }
  }

  function scheduleDeferredLayoutSync() {
    if (typeof window === 'undefined' || typeof window.requestAnimationFrame !== 'function') {
      applyLayoutHeight();
      return;
    }

    clearPendingLayoutSync();

    const firstRafId = window.requestAnimationFrame(() => {
      layoutSyncState.rafIds = layoutSyncState.rafIds.filter(id => id !== firstRafId);
      applyLayoutHeight();

      const secondRafId = window.requestAnimationFrame(() => {
        layoutSyncState.rafIds = layoutSyncState.rafIds.filter(id => id !== secondRafId);
        applyLayoutHeight();
      });
      layoutSyncState.rafIds.push(secondRafId);
    });
    layoutSyncState.rafIds.push(firstRafId);

    layoutSyncState.settleTimer = window.setTimeout(() => {
      layoutSyncState.settleTimer = null;
      applyLayoutHeight();
    }, 220);
  }

  function refreshLayout() {
    if (!isBlindMode) {
      return;
    }
    applyLayoutHeight();
    scheduleDeferredLayoutSync();
  }

  function queueLayoutHeightRefresh() {
    if (!isBlindMode || typeof window === 'undefined') {
      return;
    }
    if (layoutHeightState.queuedRefreshRaf) {
      return;
    }
    layoutHeightState.queuedRefreshRaf = window.requestAnimationFrame(() => {
      layoutHeightState.queuedRefreshRaf = null;
      refreshLayout();
    });
  }

  function getWidthHost() {
    if (root.parentElement) {
      return root.parentElement;
    }
    return root.closest('.vareoncalc-root') || root;
  }

  function getAvailableWidth() {
    const host = getWidthHost();
    return host ? host.getBoundingClientRect().width : 0;
  }

  function updateLockedWidth(nextWidth) {
    if (!Number.isFinite(nextWidth) || nextWidth <= 0) {
      return;
    }
    const available = getAvailableWidth();
    const clamped = available > 0 ? Math.min(nextWidth, available) : nextWidth;
    const rounded = Math.ceil(clamped);
    const nextMinWidth = `${rounded}px`;
    if (rounded === widthState.lockedWidth && root.style.minWidth === nextMinWidth) {
      return;
    }
    widthState.lockedWidth = rounded;
    root.style.minWidth = nextMinWidth;
  }

  function lockCurrentWidth() {
    if (!root.isConnected) {
      return;
    }
    const available = getAvailableWidth();
    if (available > 0) {
      updateLockedWidth(available);
    }
  }

  function scheduleWidthLock() {
    if (typeof window === 'undefined' || typeof window.requestAnimationFrame !== 'function') {
      lockCurrentWidth();
      return;
    }
    if (widthState.rafId) {
      window.cancelAnimationFrame(widthState.rafId);
    }
    widthState.rafId = window.requestAnimationFrame(() => {
      widthState.rafId = null;
      lockCurrentWidth();
    });
  }

  function resetLockedWidth() {
    widthState.lockedWidth = 0;
    root.style.minWidth = '';
    scheduleWidthLock();
  }

  function syncHostWidth(nextWidth) {
    if (!Number.isFinite(nextWidth) || nextWidth <= 0) {
      return;
    }

    const rounded = Math.ceil(nextWidth);
    if (rounded === widthState.hostWidth) {
      return;
    }

    widthState.hostWidth = rounded;
    updateLockedWidth(nextWidth);
    refreshLayout();
  }

  const handleWindowResize = () => {
    if (typeof window === 'undefined') {
      return;
    }
    queueLayoutHeightRefresh();
    if (widthState.resizeTimer) {
      window.clearTimeout(widthState.resizeTimer);
    }
    widthState.resizeTimer = window.setTimeout(() => {
      widthState.resizeTimer = null;
      resetLockedWidth();
      refreshLayout();
    }, 150);
  };

  function render() {
    updateClasses();
    updateAria();
    syncToggleAria();
    refreshLayout();
    scheduleWidthLock();
  }

  function scheduleInitialLayoutSync() {
    refreshLayout();
  }

  function setStep(nextStep) {
    const normalized = normalizeStep(nextStep);
    if (isBlindMode && normalized !== state.step && typeof window !== 'undefined') {
      const direction = normalized === 'results' ? 'down' : 'up';
      root.dataset.transition = direction;
      root.classList.add('is-animating');
      if (animationState.timer) {
        window.clearTimeout(animationState.timer);
      }
      animationState.timer = window.setTimeout(() => {
        root.classList.remove('is-animating');
        animationState.timer = null;
        refreshLayout();
      }, 450);
    }
    state.step = normalized;
    if (state.step !== 'results') {
      state.drawerOpen = false;
    }
    render();
  }

  function setDrawerOpen(isOpen) {
    if (state.step !== 'results') {
      state.drawerOpen = false;
      render();
      return;
    }
    state.drawerOpen = !!isOpen;
    render();
  }

  const handleNext = (event) => {
    if (event && event.defaultPrevented) {
      return;
    }
    if (event) {
      event.preventDefault();
    }
    if (state.step === 'results') {
      setDrawerOpen(false);
      return;
    }
    const canProceedNow = typeof canProceed === 'function'
      ? !!canProceed(event)
      : (typeof canProceed === 'boolean' ? canProceed : true);
    if (!canProceedNow) {
      if (event) {
        event.stopImmediatePropagation();
      }
      return;
    }
    const nextButton = event?.currentTarget || event?.target?.closest?.(selectors.next);
    const isDisabled = !!(nextButton && (nextButton.disabled || nextButton.getAttribute('aria-disabled') === 'true'));
    if (isDisabled) {
      if (event) {
        event.stopImmediatePropagation();
      }
      return;
    }
    setStep('results');
  };

  const handleBack = (event) => {
    event.preventDefault();
    setStep('inputs');
  };

  const handleToggle = (event) => {
    event.preventDefault();
    if (state.step !== 'results') {
      return;
    }
    if (isBlindMode) {
      setStep('inputs');
      return;
    }
    setDrawerOpen(!state.drawerOpen);
  };

  const handleClose = (event) => {
    event.preventDefault();
    setDrawerOpen(false);
  };

  const handleInputsStepClick = (event) => {
    if (!isBlindMode || state.step !== 'results') {
      return;
    }
    if (event.target.closest(selectors.toggle)) {
      return;
    }
    if (event.target.closest(selectors.next)) {
      return;
    }
    setStep('inputs');
  };

  nextButtons.forEach(btn => addListener(btn, 'click', handleNext));
  backButtons.forEach(btn => addListener(btn, 'click', handleBack));
  toggleButtons.forEach(btn => addListener(btn, 'click', handleToggle));
  closeButtons.forEach(btn => addListener(btn, 'click', handleClose));
  if (inputsStep) {
    addListener(inputsStep, 'click', handleInputsStepClick);
  }

  if (typeof window !== 'undefined') {
    window.addEventListener('resize', handleWindowResize);
  }

  if (typeof ResizeObserver !== 'undefined') {
    const widthHost = getWidthHost();
    if (widthHost && widthHost !== root) {
      widthState.hostWidth = Math.ceil(widthHost.getBoundingClientRect().width || 0);
      widthState.hostObserver = new ResizeObserver(entries => {
        entries.forEach(entry => {
          syncHostWidth(entry.contentRect.width);
        });
      });
      widthState.hostObserver.observe(widthHost);
    }
  }

  if (isBlindMode && typeof ResizeObserver !== 'undefined') {
    const contentTargets = [inputsBody, resultsBody].filter((el) => el instanceof HTMLElement);
    if (contentTargets.length > 0) {
      layoutHeightState.contentResizeObserver = new ResizeObserver(() => {
        queueLayoutHeightRefresh();
      });
      contentTargets.forEach((el) => {
        layoutHeightState.contentResizeObserver.observe(el);
      });
    }
  }

  if (isBlindMode && typeof window !== 'undefined' && window.visualViewport) {
    const vvHandler = () => queueLayoutHeightRefresh();
    layoutHeightState.visualViewportHandler = vvHandler;
    window.visualViewport.addEventListener('resize', vvHandler);
  }

  render();
  scheduleInitialLayoutSync();

  return {
    root,
    setStep,
    setDrawerOpen,
    refreshLayout,
    getState: () => ({ ...state }),
    destroy: () => {
      listeners.forEach(({ element, type, handler }) => {
        element.removeEventListener(type, handler);
      });
      if (widthState.resizeObserver) {
        widthState.resizeObserver.disconnect();
        widthState.resizeObserver = null;
      }
      if (widthState.hostObserver) {
        widthState.hostObserver.disconnect();
        widthState.hostObserver = null;
      }
      if (typeof window !== 'undefined') {
        window.removeEventListener('resize', handleWindowResize);
        if (layoutHeightState.queuedRefreshRaf) {
          window.cancelAnimationFrame(layoutHeightState.queuedRefreshRaf);
          layoutHeightState.queuedRefreshRaf = null;
        }
        if (layoutHeightState.contentResizeObserver) {
          layoutHeightState.contentResizeObserver.disconnect();
          layoutHeightState.contentResizeObserver = null;
        }
        if (layoutHeightState.visualViewportHandler && window.visualViewport) {
          window.visualViewport.removeEventListener('resize', layoutHeightState.visualViewportHandler);
          layoutHeightState.visualViewportHandler = null;
        }
        if (widthState.resizeTimer) {
          window.clearTimeout(widthState.resizeTimer);
        }
        if (widthState.rafId) {
          window.cancelAnimationFrame(widthState.rafId);
        }
        if (animationState.timer) {
          window.clearTimeout(animationState.timer);
        }
        clearPendingLayoutSync();
      }
    }
  };
}

function normalizeStep(value) {
  return value === 'results' ? 'results' : 'inputs';
}

function normalizeMode(value) {
  return value === 'drawer' ? 'drawer' : 'blind';
}
