/* ════════════════════════════════════════════════════════
 * page-growth.js
 * growth_analysis.html 的 Chart.js 圖表
 * Chart.js 由 analysis-chart-theme.js 懶載入，避免首屏阻塞。
 * ════════════════════════════════════════════════════════ */
(function () {
  'use strict';

  let chartsRendered = false;
  const isCompact = () =>
    window.matchMedia && window.matchMedia('(max-width: 768px)').matches;

  function readGrowthData() {
    const node = document.getElementById('chart-data');
    if (!node) return null;
    const rawPayload = [
      node.content && node.content.textContent,
      node.textContent,
      node.innerHTML
    ].find(value => value && value.trim());
    if (!rawPayload) {
      console.error('[growth_analysis] chart data is empty');
      return null;
    }
    try {
      return JSON.parse(rawPayload);
    } catch (error) {
      console.error('[growth_analysis] chart data parse failed:', error);
      return null;
    }
  }

  const data = readGrowthData();
  if (!data) return;

  const rootStyle = getComputedStyle(document.documentElement);
  const token = (name, fallback) => rootStyle.getPropertyValue(name).trim() || fallback;

  const chartPalette = {
    caramel: token('--momo-page-chart-2', '#c96442'),
    caramelSoft: token('--momo-warm-caramel-soft', 'rgba(201, 100, 66, 0.58)'),
    honey: token('--momo-page-accent', '#c89043'),
    honeySoft: token('--momo-page-accent-soft', 'rgba(200, 144, 67, 0.14)'),
    rust: token('--momo-danger-text', '#7a3210'),
    rustSoft: token('--momo-danger-bg', '#efd3c4')
  };
  const chartInstances = [];

  function rememberChart(chart) {
    if (chart) chartInstances.push(chart);
    return chart;
  }

  function stabilizeCharts() {
    window.requestAnimationFrame(() => {
      chartInstances.forEach(chart => {
        if (!chart) return;
        if (typeof chart.resize === 'function') chart.resize();
        if (typeof chart.update === 'function') chart.update('none');
      });
      window.dispatchEvent(new Event('resize'));
    });
  }

  function formatShort(value, mode) {
    const n = Number(value || 0);
    if (mode === 'pct') return `${n.toFixed(1)}%`;
    if (mode === 'currency') return `$${Math.round(n).toLocaleString()}`;
    return Math.round(n).toLocaleString();
  }

  function formatMetric(value, mode) {
    const n = Number(value || 0);
    if (mode === 'pct') return `${n >= 0 ? '+' : ''}${n.toFixed(1)}%`;
    if (mode === 'currency') return `$${Math.round(n).toLocaleString()}`;
    return Math.round(n).toLocaleString();
  }

  function moneyAxis(title) {
    return {
      beginAtZero: true,
      grace: '8%',
      title: { display: !isCompact(), text: title },
      ticks: { callback: value => formatMetric(value, 'currency') }
    };
  }

  function pctAxis(title) {
    return {
      beginAtZero: false,
      grace: '12%',
      title: { display: !isCompact(), text: title },
      ticks: { callback: value => formatMetric(value, 'pct') }
    };
  }

  function renderHtmlBars(canvasId, labels, values, options = {}) {
    const canvas = document.getElementById(canvasId);
    const wrap = canvas ? canvas.closest('.ga-chart-card__body') : null;
    if (!wrap) return;
    wrap.classList.add('chart-fallback-active');
    canvas.setAttribute('aria-hidden', 'true');
    if (wrap.querySelector('.ga-chart-snapshot, .ga-chart-fallback')) return;
    const pairs = (labels || []).map((label, index) => ({
      label: String(label || ''),
      value: Number((values || [])[index] || 0)
    })).filter(item => Number.isFinite(item.value));
    if (!pairs.length) return;
    const max = Math.max(...pairs.map(item => Math.abs(item.value)), 1);

    const chart = document.createElement('div');
    chart.className = 'ga-chart-fallback';
    pairs.forEach(item => {
      const bar = document.createElement('div');
      bar.className = `ga-chart-fallback__bar ${item.value < 0 ? 'is-negative' : ''}`;
      bar.style.setProperty('--bar-h', `${Math.max(4, Math.round(Math.abs(item.value) / max * 100))}%`);
      const label = document.createElement('span');
      label.textContent = item.label;
      const value = document.createElement('strong');
      value.textContent = formatShort(item.value, options.mode);
      bar.append(label, value);
      chart.appendChild(bar);
    });
    wrap.appendChild(chart);
  }

  function renderHtmlChartFallbacks() {
    renderHtmlBars('revenueChart', data.labels, data.revenue, { mode: 'currency' });
    renderHtmlBars('momChart', data.labels, data.mom, { mode: 'pct' });
    renderHtmlBars('aovChart', data.labels, data.aov, { mode: 'currency' });
    renderHtmlBars('marginChart', data.labels, data.margin_rate, { mode: 'pct' });
    renderHtmlBars('competitorPressureChart', data.labels, data.competitor_gap_pct, { mode: 'pct' });
  }

  function hasSeriesData(labels, ...seriesList) {
    return Array.isArray(labels) &&
      labels.length > 0 &&
      seriesList.some(series => Array.isArray(series) && series.length > 0);
  }

  function renderChartEmpty(canvasId, message) {
    const canvas = document.getElementById(canvasId);
    const wrap = canvas ? canvas.closest('.ga-chart-card__body') : null;
    if (!wrap || wrap.querySelector('.ga-chart-empty')) return;
    wrap.classList.add('chart-empty-active');
    canvas.setAttribute('aria-hidden', 'true');
    const empty = document.createElement('div');
    empty.className = 'ga-chart-empty';
    empty.innerHTML = `<strong>尚無可繪製資料</strong><span>${message}</span>`;
    wrap.appendChild(empty);
  }

  function loadChartJs() {
    if (window.EwoooCChartTheme && window.EwoooCChartTheme.loadChartJs) {
      return window.EwoooCChartTheme.loadChartJs();
    }
    if (window.Chart) return Promise.resolve(window.Chart);
    return Promise.reject(new Error('Chart.js loader unavailable'));
  }

  function renderCharts() {
    if (chartsRendered) return;
    chartsRendered = true;

    Chart.defaults.color = token('--momo-text-secondary', '#6b6155');
    Chart.defaults.borderColor = token('--momo-border-light', 'rgba(42, 37, 32, 0.10)');
    Chart.defaults.font.family = token('--momo-font-family', "'Inter', system-ui, sans-serif");

    const revenueEl = document.getElementById('revenueChart');
    const momEl = document.getElementById('momChart');
    const aovEl = document.getElementById('aovChart');
    const marginEl = document.getElementById('marginChart');
    const competitorEl = document.getElementById('competitorPressureChart');
    if (!revenueEl || !momEl || !aovEl || !marginEl) return;

    if (!hasSeriesData(data.labels, data.revenue, data.yoy)) {
      renderChartEmpty('revenueChart', '目前圖表 payload 沒有月營收或年增率序列。');
    } else {
    rememberChart(new Chart(revenueEl, {
      type: 'bar',
      data: {
        labels: data.labels,
        datasets: [
          {
            label: '月營收 ($)',
            data: data.revenue,
            backgroundColor: chartPalette.caramelSoft,
            borderColor: chartPalette.caramel,
            borderWidth: 1,
            maxBarThickness: 34,
            order: 2
          },
          {
            label: 'YoY 年增率 (%)',
            data: data.yoy,
            type: 'line',
            borderColor: chartPalette.rust,
            borderWidth: 2,
            yAxisID: 'y1',
            order: 1,
            tension: 0.34,
            cubicInterpolationMode: 'monotone',
            pointRadius: 2,
            pointHoverRadius: 5
          }
        ]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        interaction: { mode: 'index', intersect: false },
        plugins: {
          legend: { position: isCompact() ? 'bottom' : 'top' },
          tooltip: {
            callbacks: {
              label: ctx => {
                const mode = ctx.dataset.yAxisID === 'y1' ? 'pct' : 'currency';
                return `${ctx.dataset.label}: ${formatMetric(ctx.parsed.y, mode)}`;
              }
            }
          }
        },
        scales: {
          x: { grid: { display: false }, ticks: { maxTicksLimit: isCompact() ? 5 : 8 } },
          y: moneyAxis('月營收'),
          y1: {
            position: 'right',
            grid: { drawOnChartArea: false },
            ...pctAxis('YoY 年增率')
          }
        }
      }
    }));
    }

    if (!hasSeriesData(data.labels, data.mom)) {
      renderChartEmpty('momChart', '目前圖表 payload 沒有月增率序列。');
    } else {
    rememberChart(new Chart(momEl, {
      type: 'bar',
      data: {
        labels: data.labels,
        datasets: [{
          label: 'MoM 月增率 (%)',
          data: data.mom,
          backgroundColor: ctx => ctx.raw >= 0 ? chartPalette.honeySoft : chartPalette.rustSoft,
          borderColor: ctx => ctx.raw >= 0 ? chartPalette.honey : chartPalette.rust,
          borderWidth: 1,
          maxBarThickness: 34
        }]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        plugins: {
          legend: { display: false },
          tooltip: { callbacks: { label: ctx => formatMetric(ctx.parsed.y, 'pct') } }
        },
        scales: {
          x: { grid: { display: false }, ticks: { maxTicksLimit: isCompact() ? 5 : 8 } },
          y: pctAxis('MoM 月增率')
        }
      }
    }));
    }

    if (!hasSeriesData(data.labels, data.aov)) {
      renderChartEmpty('aovChart', '目前圖表 payload 沒有平均單價序列。');
    } else {
    rememberChart(new Chart(aovEl, {
      type: 'line',
      data: {
        labels: data.labels,
        datasets: [{
          label: '平均單價 ($)',
          data: data.aov,
          borderColor: chartPalette.caramel,
          backgroundColor: chartPalette.caramelSoft,
          fill: true,
          tension: 0.36,
          cubicInterpolationMode: 'monotone',
          pointRadius: 2,
          pointHoverRadius: 5
        }]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        interaction: { mode: 'index', intersect: false },
        plugins: {
          legend: { display: false },
          tooltip: { callbacks: { label: ctx => formatMetric(ctx.parsed.y, 'currency') } }
        },
        scales: {
          x: { grid: { display: false }, ticks: { maxTicksLimit: isCompact() ? 5 : 8 } },
          y: moneyAxis('平均單價')
        }
      }
    }));
    }

    if (!hasSeriesData(data.labels, data.margin_rate)) {
      renderChartEmpty('marginChart', '目前圖表 payload 沒有毛利率序列。');
    } else {
    rememberChart(new Chart(marginEl, {
      type: 'line',
      data: {
        labels: data.labels,
        datasets: [{
          label: '毛利率 (%)',
          data: data.margin_rate,
          borderColor: chartPalette.honey,
          backgroundColor: chartPalette.honeySoft,
          fill: true,
          tension: 0.36,
          cubicInterpolationMode: 'monotone',
          pointRadius: 2,
          pointHoverRadius: 5
        }]
      },
      options: {
        responsive: true,
        maintainAspectRatio: false,
        interaction: { mode: 'index', intersect: false },
        plugins: {
          legend: { display: false },
          tooltip: { callbacks: { label: ctx => formatMetric(ctx.parsed.y, 'pct') } }
        },
        scales: {
          x: { grid: { display: false }, ticks: { maxTicksLimit: isCompact() ? 5 : 8 } },
          y: pctAxis('毛利率')
        }
      }
    }));
    }

    if (competitorEl) {
      if (!hasSeriesData(data.labels, data.competitor_gap_pct, data.competitor_risk_count)) {
        renderChartEmpty('competitorPressureChart', '目前沒有可用的 PChome 月度價差序列。');
      } else {
        rememberChart(new Chart(competitorEl, {
          type: 'bar',
          data: {
            labels: data.labels,
            datasets: [
              {
                label: '價格壓力 SKU 數',
                data: data.competitor_risk_count || [],
                backgroundColor: chartPalette.rustSoft,
                borderColor: chartPalette.rust,
                borderWidth: 1,
                maxBarThickness: 34,
                yAxisID: 'y'
              },
              {
                label: '平均價差 (%)',
                data: data.competitor_gap_pct || [],
                type: 'line',
                borderColor: chartPalette.honey,
                borderWidth: 2,
                yAxisID: 'y1',
                tension: 0.34,
                cubicInterpolationMode: 'monotone',
                pointRadius: 2,
                pointHoverRadius: 5
              }
            ]
          },
          options: {
            responsive: true,
            maintainAspectRatio: false,
            interaction: { mode: 'index', intersect: false },
            plugins: {
              legend: { position: isCompact() ? 'bottom' : 'top' },
              tooltip: {
                callbacks: {
                  label: ctx => {
                    const mode = ctx.dataset.yAxisID === 'y1' ? 'pct' : 'number';
                    return `${ctx.dataset.label}: ${formatMetric(ctx.parsed.y, mode)}`;
                  }
                }
              }
            },
            scales: {
              x: { grid: { display: false }, ticks: { maxTicksLimit: isCompact() ? 5 : 8 } },
              y: {
                beginAtZero: true,
                title: { display: !isCompact(), text: '風險 SKU 數' }
              },
              y1: {
                position: 'right',
                grid: { drawOnChartArea: false },
                ...pctAxis('平均價差')
              }
            }
          }
        }));
      }
    }
    stabilizeCharts();
  }

  function bootCharts() {
    document.documentElement.dataset.growthCharts = 'loading';
    loadChartJs()
      .then(() => {
        renderCharts();
        document.documentElement.dataset.growthCharts = 'ready';
      })
      .catch(error => {
        document.documentElement.dataset.growthCharts = 'error';
        document.documentElement.dataset.growthChartsError = error && error.message ? error.message : String(error);
        console.error('[growth_analysis] Chart.js 載入失敗:', error);
        renderHtmlChartFallbacks();
      });
  }

  function scheduleChartBoot() {
    window.setTimeout(bootCharts, 0);
  }

  function observeCharts() {
    const targets = Array.from(document.querySelectorAll('.ga-chart-card'));
    if (!targets.length) return;
    if (!('IntersectionObserver' in window)) {
      bootCharts();
      return;
    }

    const observer = new IntersectionObserver(entries => {
      if (!entries.some(entry => entry.isIntersecting)) return;
      observer.disconnect();
      bootCharts();
    }, { rootMargin: '220px 0px' });

    targets.forEach(target => observer.observe(target));
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', scheduleChartBoot, { once: true });
  } else {
    scheduleChartBoot();
  }
})();
