/*
 * PNG-Export (hochaufgelöstes Rendering + optionaler Composite mit Title/Subtitle/Legende/Footnote).
 *
 * Zwei Eintrittspunkte:
 * - `wrapper._cePdExportPng(scaleFactor)` → DataURL vom reinen 3D-Chart.
 * - Toolbar-Button rendert zusätzlich Titel/Untertitel/Legende/Footnote in einen 2D-Canvas
 *   und startet den Browser-Download.
 */

import { bindNativeTitleDismissOnTouch } from './nativeTitleTouchDismiss.js';

export function createPngExport({
  THREE,
  wrapper,
  container,
  ownerDoc,
  state,
  opts,
  i18nPngDownload,
  pngDownloadBtn,
  renderer,
  scene,
  getActiveCamera,
  backgroundTransparent,
  backgroundColor,
  wake,
  hibernate,
}) {
  /** PNG export: CSS size × multiplier, then uniformly scaled down so width and height ≤ this (aspect preserved). */
  const CE_PD_EXPORT_MAX_PX = 2560;
  const _cePdExportSizePrev = new THREE.Vector2();

  const allowPngExport = wrapper.classList.contains('ce-diagram-editor-preview') || opts.viewerPngDownloadEnabled === true;
  if (allowPngExport) {
    wrapper._cePdExportPng = function cePdExportPng(scaleFactor) {
      const baseMul = Math.max(1, Math.min(8, Number(scaleFactor) || 3));
      const w = container.clientWidth;
      const h = container.clientHeight;
      if (w <= 0 || h <= 0 || state.contextLost) return null;
      const wasHibernated = state.hibernated;
      if (wasHibernated) wake();
      const targetW = w * baseMul;
      const targetH = h * baseMul;
      const fit = Math.min(CE_PD_EXPORT_MAX_PX / targetW, CE_PD_EXPORT_MAX_PX / targetH, 1);
      const outW = Math.max(1, Math.floor(targetW * fit));
      const outH = Math.max(1, Math.floor(targetH * fit));
      const prevPR = renderer.getPixelRatio();
      renderer.getSize(_cePdExportSizePrev);
      const prevW = _cePdExportSizePrev.x;
      const prevH = _cePdExportSizePrev.y;
      const prevBg = scene.background;
      if (backgroundTransparent) scene.background = new THREE.Color('#ffffff');
      renderer.setPixelRatio(1);
      renderer.setSize(outW, outH, false);
      renderer.render(scene, getActiveCamera());
      /** Export läuft über einen separaten 2D-Canvas (nicht `ownCanvas`, weil dessen Größe
       *  die Viewport-Größe ist und nicht mit der temporären Export-Auflösung zusammenpasst).
       *  Damit bleibt `preserveDrawingBuffer: false` sicher — das Blitting erfolgt
       *  synchron direkt nach dem Render, bevor der Browser den Drawing-Buffer cleared. */
      const exportCanvas = ownerDoc.createElement('canvas');
      exportCanvas.width = outW; exportCanvas.height = outH;
      const exportCtx = exportCanvas.getContext('2d');
      exportCtx.drawImage(renderer.domElement, 0, 0);
      const dataUrl = exportCanvas.toDataURL('image/png');
      scene.background = prevBg;
      renderer.setPixelRatio(prevPR);
      renderer.setSize(prevW, prevH, false);
      if (wasHibernated) hibernate();
      return dataUrl;
    };
  }

  let onPngDownloadClick = null;
  if (pngDownloadBtn && opts.viewerPngDownloadEnabled === true) {
    pngDownloadBtn.setAttribute('aria-label', i18nPngDownload);
    pngDownloadBtn.title = i18nPngDownload;
    bindNativeTitleDismissOnTouch(pngDownloadBtn);
    const pngLbl = pngDownloadBtn.querySelector('.ce-diagram-expand-btn__label');
    if (pngLbl) pngLbl.textContent = i18nPngDownload;
    onPngDownloadClick = () => {
      if (typeof wrapper._cePdExportPng !== 'function') return;
      const chartDataUrl = wrapper._cePdExportPng(3);
      if (!chartDataUrl) return;

      function triggerDl(url) {
        const a = ownerDoc.createElement('a');
        a.href = url;
        a.download = 'ce-diagram-export.png';
        a.rel = 'noopener';
        ownerDoc.body.appendChild(a);
        a.click();
        ownerDoc.body.removeChild(a);
      }

      const _header = wrapper.querySelector('.ce-diagram-header');
      const _footer = wrapper.querySelector('.ce-diagram-footnote');
      const _titleEl = _header ? _header.querySelector('.ce-diagram-chart-title') : null;
      const _subtitleEl = _header ? _header.querySelector('.ce-diagram-chart-subtitle') : null;
      const _titleText = _titleEl ? _titleEl.textContent.trim() : '';
      const _subtitleText = _subtitleEl ? _subtitleEl.textContent.trim() : '';
      const _footnoteText = _footer ? _footer.textContent.trim() : '';
      const _legAside = wrapper.querySelector('.ce-diagram-legend');
      const _legVis = _legAside && !_legAside.hasAttribute('hidden') && !wrapper.classList.contains('ce-diagram-wrapper--legend-hidden');
      const _legRowEls = _legVis ? Array.from(_legAside.querySelectorAll('.ce-diagram-legend__row')) : [];

      if (!_titleText && !_subtitleText && !_footnoteText && _legRowEls.length === 0) {
        triggerDl(chartDataUrl);
        return;
      }

      const cImg = new Image();
      cImg.onload = () => {
        const cW = cImg.width;
        const cH = cImg.height;
        const sc = cW / Math.max(1, container.clientWidth);
        const pad = Math.round(20 * sc);
        const sm = Math.round(6 * sc);
        const win = ownerDoc.defaultView;

        function rFont(el, sz, wt) {
          if (!el) return wt + ' ' + Math.round(sz * sc) + 'px sans-serif';
          const cs = win.getComputedStyle(el);
          return (cs.fontWeight || wt) + ' ' + Math.round(parseFloat(cs.fontSize) * sc) + 'px ' + (cs.fontFamily || 'sans-serif');
        }
        function rColor(el, fb) { return el ? (win.getComputedStyle(el).color || fb) : fb; }
        function fontPx(f) { const m = f.match(/(\d+)px/); return m ? parseFloat(m[1]) : 16; }
        function lH(f) { return Math.round(fontPx(f) * 1.35); }

        const c = ownerDoc.createElement('canvas');
        const cx = c.getContext('2d');

        const tF = rFont(_titleEl, 24, '800');
        const sF = rFont(_subtitleEl, 16, '300');
        const fF = rFont(_footer, 13, '300');
        const maxTextW = cW - 2 * pad;

        function wrapLines(text, font) {
          cx.font = font;
          if (cx.measureText(text).width <= maxTextW) return [text];
          const words = text.split(/\s+/);
          const lines = [];
          let cur = '';
          for (const w of words) {
            const test = cur ? cur + ' ' + w : w;
            if (cx.measureText(test).width > maxTextW && cur) { lines.push(cur); cur = w; }
            else cur = test;
          }
          if (cur) lines.push(cur);
          return lines;
        }

        const titleLines = _titleText ? wrapLines(_titleText, tF) : [];
        const subtitleLines = _subtitleText ? wrapLines(_subtitleText, sF) : [];
        const footnoteLines = _footnoteText ? wrapLines(_footnoteText, fF) : [];
        const tLH = lH(tF);
        const sLH = lH(sF);
        const fLH = lH(fF);

        let hdrH = titleLines.length * tLH + subtitleLines.length * sLH;
        if (hdrH > 0) hdrH += sm;

        const swR = Math.round(6 * sc);
        const swD = swR * 2;
        const swGap = Math.round(6 * sc);
        const itemGapX = Math.round(16 * sc);
        const itemGapY = Math.round(8 * sc);
        let legFont = rFont(_legAside, 13, '400');
        cx.font = legFont;
        const legItemH = Math.max(swD, lH(legFont)) + itemGapY;

        const items = _legRowEls.map(r => {
          const sw = r.querySelector('.ce-diagram-legend__swatch');
          const tx = r.querySelector('.ce-diagram-legend__text');
          const col = sw ? win.getComputedStyle(sw).backgroundColor : '#999';
          const txt = tx ? tx.textContent.trim() : '';
          cx.font = legFont;
          const w = swD + swGap + cx.measureText(txt).width + itemGapX;
          return { col, txt, w };
        });

        let legRows = 0;
        if (items.length > 0) {
          legRows = 1;
          let rw = 0;
          for (const it of items) {
            if (rw > 0 && rw + it.w > maxTextW) { legRows++; rw = it.w; }
            else rw += it.w;
          }
        }
        const legH = legRows > 0 ? legRows * legItemH + pad : 0;
        const ftH = footnoteLines.length > 0 ? footnoteLines.length * fLH + sm : 0;

        const totalH = pad + hdrH + cH + legH + ftH + pad;
        c.width = cW;
        c.height = totalH;

        cx.fillStyle = backgroundTransparent ? '#ffffff' : backgroundColor;
        cx.fillRect(0, 0, cW, totalH);

        let y = pad;
        if (titleLines.length > 0) {
          cx.font = tF;
          cx.fillStyle = rColor(_titleEl, '#111');
          for (const ln of titleLines) { cx.fillText(ln, pad, y + tLH * 0.78); y += tLH; }
        }
        if (subtitleLines.length > 0) {
          cx.font = sF;
          cx.fillStyle = rColor(_subtitleEl, '#555');
          for (const ln of subtitleLines) { cx.fillText(ln, pad, y + sLH * 0.78); y += sLH; }
        }
        if (hdrH > 0) y += sm;

        cx.drawImage(cImg, 0, y, cW, cH);
        y += cH;

        if (items.length > 0) {
          y += Math.round(pad * 0.6);
          const legTextColor = _legAside ? (win.getComputedStyle(_legAside).color || '#333') : '#333';
          let lx = pad;
          let ly = y;
          const fpx = fontPx(legFont);
          for (const it of items) {
            if (lx > pad && lx + it.w > maxTextW + pad) { lx = pad; ly += legItemH; }
            cx.fillStyle = it.col;
            cx.beginPath();
            cx.arc(lx + swR, ly + swR, swR, 0, Math.PI * 2);
            cx.fill();
            cx.fillStyle = legTextColor;
            cx.font = legFont;
            cx.fillText(it.txt, lx + swD + swGap, ly + swR + fpx * 0.35);
            lx += it.w;
          }
        }

        if (footnoteLines.length > 0) {
          y = totalH - pad - ftH + sm;
          cx.font = fF;
          cx.fillStyle = rColor(_footer, '#777');
          for (const ln of footnoteLines) { cx.fillText(ln, pad, y + fLH * 0.78); y += fLH; }
        }

        triggerDl(c.toDataURL('image/png'));
      };
      cImg.src = chartDataUrl;
    };
    pngDownloadBtn.addEventListener('click', onPngDownloadClick);
  }

  return {
    unbind() {
      if (pngDownloadBtn && onPngDownloadClick) pngDownloadBtn.removeEventListener('click', onPngDownloadClick);
      if (wrapper._cePdExportPng) {
        try { delete wrapper._cePdExportPng; } catch (_) { wrapper._cePdExportPng = undefined; }
      }
    },
  };
}
