/*
 * HTML-Legende (außerhalb des 3D-Canvas):
 * Zeilen mit Farbswatch + Label. Add-on-Plugins koennen ueber
 * `window.__CE_PD_SCENE_EXT__.customizeLegendHtml(layout, ctx)` ein abweichendes
 * Legenden-Markup liefern (z. B. die Surface-Gradient-Leiste oder eine multi-
 * series Variante fuer Wave). Wenn der Hook `null`/`undefined` liefert, kommt
 * das Free-Default zum Einsatz.
 */

import { i18nStr, escapeHtml } from '../../shared/config.js';
import { getFallbackChartNumberFormatter } from '../../shared/numberFormat.js';
import { bindNativeTitleDismissOnTouch } from './nativeTitleTouchDismiss.js';

export function createLegend({
  wrapper,
  opts,
  DATA,
  state,
  legendPosition,
  backgroundColor,
  backgroundTransparent,
  contrastTextColor,
  bubblePackLegendHint,
  clusterLayout,
  axisYMin,
  axisYMax,
  axisYPrefix,
  axisYSuffix,
  scatterAxisYLabel,
  intToCssHex,
  barColorAtIndex,
  barGradientStopsAtIndex,
  setDataIndexHidden,
  onExternalLegendMount,
  refreshHeaderFooterHeight,
  markSkipHeightRecalc,
  recalcFit,
}) {
  const legendAside = wrapper.querySelector('.ce-diagram-legend') || wrapper.querySelector('[data-ce-legend-aside]');
  const legendBtn = wrapper.querySelector('.ce-diagram-legend-toggle-btn');
  let onLegendBtnClick = null;
  let onLegendRowClick = null;
  let externalLegendEl = null;

  if (opts.legendEnabled !== false && legendPosition !== 'hidden' && legendAside && legendBtn && DATA.length > 0) {
    const effectiveLegendColor = opts.legendTextColor || (!backgroundTransparent ? contrastTextColor(backgroundColor) : '');
    if (effectiveLegendColor) legendAside.style.setProperty('--ce-legend-color', effectiveLegendColor);
    const i18nLShow = i18nStr(opts.i18nLegendShow, 'Show legend');
    const i18nLHide = i18nStr(opts.i18nLegendHide, 'Hide legend');
    const formatTick = typeof opts.formatChartNumber === 'function'
      ? opts.formatChartNumber
      : getFallbackChartNumberFormatter().formatTick;
    function buildLegendInnerHtml() {
      const sceneExt = typeof window !== 'undefined' ? window.__CE_PD_SCENE_EXT__ : null;
      if (sceneExt && typeof sceneExt.customizeLegendHtml === 'function') {
        try {
          const custom = sceneExt.customizeLegendHtml(state.layout, {
            opts,
            DATA,
            state,
            legendPosition,
            axisYMin,
            axisYMax,
            axisYPrefix,
            axisYSuffix,
            scatterAxisYLabel,
            bubblePackLegendHint,
            clusterLayout,
            formatTick,
            intToCssHex,
            barColorAtIndex,
            barGradientStopsAtIndex,
          });
          if (typeof custom === 'string') {
            return custom;
          }
        } catch (_) { /* ignore broken extension */ }
      }
      const legendRowIndices = DATA.map((_, i) => i);
      /* Stacked: eine Legenden-Zeile pro Palette-Slot. `rowToDataIndices[k]`
       *  enth\u00e4lt alle DATA-Indizes, die zu Slot k geh\u00f6ren — n\u00f6tig fuer den
       *  Klick-Toggle (alle Bars dieses Slots gleichzeitig zeigen/verstecken). */
      const rowToDataIndices = [];
      if (
        (state.layout === 'stacked') &&
        clusterLayout &&
        clusterLayout.slotInGroup &&
        clusterLayout.G < DATA.length
      ) {
        const slotToIndices = new Map();
        for (let li = 0; li < DATA.length; li++) {
          const slot = clusterLayout.slotInGroup[li];
          if (!slotToIndices.has(slot)) slotToIndices.set(slot, []);
          slotToIndices.get(slot).push(li);
        }
        const slotsSorted = Array.from(slotToIndices.keys()).sort((a, b) => a - b);
        legendRowIndices.length = 0;
        for (const s of slotsSorted) {
          const arr = slotToIndices.get(s);
          legendRowIndices.push(arr[0]);
          rowToDataIndices.push(arr);
        }
      } else {
        for (let i = 0; i < legendRowIndices.length; i++) {
          rowToDataIndices.push([legendRowIndices[i]]);
        }
      }
      const interactive = typeof setDataIndexHidden === 'function';
      /* Verlaufs-Swatch (Gradient-Balken): echter linear-gradient + Mittelfarbe als
       * background-color (PNG-Export liest getComputedStyle().backgroundColor). */
      const swatchStyleFor = (i) => {
        const stops = typeof barGradientStopsAtIndex === 'function' ? barGradientStopsAtIndex(i) : null;
        if (stops) {
          const mid = intToCssHex(stops[1]);
          return 'background-color:' + mid + ';background-image:linear-gradient(to right, ' + intToCssHex(stops[0]) + ', ' + mid + ', ' + intToCssHex(stops[2]) + ')';
        }
        return 'background-color:' + intToCssHex(barColorAtIndex(i));
      };
      const rows = legendRowIndices.map((i, k) => {
        const item = DATA[i];
        const raw = (item.label || '').trim();
        const label = escapeHtml(raw || ('#' + String(i + 1)));
        const indicesAttr = rowToDataIndices[k].join(',');
        const tag = interactive ? 'button' : 'div';
        const attrs = interactive
          ? ' type="button" aria-pressed="false" data-ce-pd-indices="' + escapeHtml(indicesAttr) + '"'
          : '';
        return (
          '<' + tag + ' class="ce-diagram-legend__row"' + attrs + '>' +
          '<span class="ce-diagram-legend__swatch" style="' + swatchStyleFor(i) + '"></span>' +
          '<span class="ce-diagram-legend__text">' + label + '</span>' +
          '</' + tag + '>'
        );
      }).join('');
      return rows;
    }
    legendAside.innerHTML = buildLegendInnerHtml();
    let legendVisible = opts.legendVisibleDefault !== false;
    if (legendPosition === 'bottom' && opts.legendOutsideChart === true) {
      const footnoteEl = wrapper.querySelector('.ce-diagram-footnote');
      wrapper.insertBefore(legendAside, footnoteEl || null);
      wrapper.classList.add('ce-diagram-wrapper--legend-external');
      externalLegendEl = legendAside;
      if (onExternalLegendMount) onExternalLegendMount(externalLegendEl);
    }
    function syncLegendUi() {
      legendBtn.setAttribute('aria-pressed', legendVisible ? 'true' : 'false');
      legendBtn.setAttribute('aria-label', legendVisible ? i18nLHide : i18nLShow);
      legendBtn.title = legendVisible ? i18nLHide : i18nLShow;
      wrapper.classList.toggle('ce-diagram-wrapper--legend-hidden', !legendVisible);
      if (legendVisible) {
        legendAside.removeAttribute('hidden');
        legendAside.setAttribute('aria-hidden', 'false');
      } else {
        legendAside.setAttribute('hidden', '');
        legendAside.setAttribute('aria-hidden', 'true');
      }
      if (externalLegendEl) {
        if (refreshHeaderFooterHeight) refreshHeaderFooterHeight();
      } else if (window.innerWidth > 640) {
        if (markSkipHeightRecalc) markSkipHeightRecalc(400);
      }
      recalcFit();
    }
    /* Direkt am Button wie Vollbild/Datentabelle — Theme/Parent kann Bubbling zu wrapper blockieren. */
    onLegendBtnClick = (e) => {
      e.preventDefault();
      e.stopPropagation();
      legendVisible = !legendVisible;
      syncLegendUi();
    };
    legendBtn.addEventListener('click', onLegendBtnClick);
    bindNativeTitleDismissOnTouch(legendBtn);
    syncLegendUi();

    /* Klick auf Legenden-Zeile = entsprechende Bars/Slice(s) ausblenden.
     *  Event-Delegation am Container, damit nach `innerHTML`-Rebuilds
     *  (Add-on-Pfad customizeLegendHtml) kein Re-Bind n\u00f6tig ist. */
    if (typeof setDataIndexHidden === 'function') {
      onLegendRowClick = (e) => {
        const target = e.target;
        if (!target || typeof target.closest !== 'function') return;
        const row = target.closest('.ce-diagram-legend__row[data-ce-pd-indices]');
        if (!row || !legendAside.contains(row)) return;
        e.preventDefault();
        const raw = row.getAttribute('data-ce-pd-indices') || '';
        const parts = raw.split(',');
        const indices = [];
        for (let i = 0; i < parts.length; i++) {
          const n = parseInt(parts[i], 10);
          if (Number.isInteger(n) && n >= 0) indices.push(n);
        }
        if (indices.length === 0) return;
        const wasPressed = row.getAttribute('aria-pressed') === 'true';
        const nextHidden = !wasPressed;
        for (let i = 0; i < indices.length; i++) setDataIndexHidden(indices[i], nextHidden);
        row.setAttribute('aria-pressed', nextHidden ? 'true' : 'false');
        row.classList.toggle('ce-diagram-legend__row--hidden', nextHidden);
      };
      legendAside.addEventListener('click', onLegendRowClick);
    }
  } else if (legendBtn) {
    legendBtn.style.display = 'none';
  }

  return {
    externalLegendEl,
    unbind() {
      if (legendBtn && onLegendBtnClick) legendBtn.removeEventListener('click', onLegendBtnClick);
      if (legendAside && onLegendRowClick) legendAside.removeEventListener('click', onLegendRowClick);
    },
  };
}
