/**
 * PacificChart — thin ApexCharts wrapper.
 *
 * Reasons to route every dashboard chart through this instead of calling
 * new ApexCharts(...) directly:
 *   · Every chart gets the Pacific brand palette without re-typing hex.
 *   · TZS number formatting (yaxis labels + tooltip) in one place.
 *   · Empty-state placeholder when the series is all zero — silences the
 *     "no data" ApexCharts default which looks broken next to real charts.
 *   · Sensible defaults for grid / stroke / animations that suit an
 *     internal ops dashboard rather than a marketing page.
 *
 * Usage:
 *   new PacificChart('#el', 'area', {
 *     series:     [{ name: 'Revenue', data: [1,2,3] }],
 *     categories: ['Jan','Feb','Mar'],
 *     tzs: true,             // format axis + tooltip as TZS
 *     title: 'Revenue trend' // optional inline title
 *   });
 */
(function () {
  if (typeof window.ApexCharts === 'undefined') {
    console.warn('[PacificChart] ApexCharts is not loaded — charts will not render.');
  }

  const BRAND = {
    blue:    '#2626F5',
    blueDk:  '#1414D6',
    blueLt:  '#5A5AF8',
    tint:    '#EBEFFA',
    ink:     '#0F1220',
    muted:   '#6B7484',
    rule:    '#E2E7EF',
    ok:      '#0E9F6E',
    warn:    '#F59E0B',
    bad:     '#DC2626',
    info:    '#455266',
  };

  const PALETTES = {
    single:  [BRAND.blue],
    duo:     [BRAND.blue, BRAND.muted],
    trio:    [BRAND.blue, BRAND.ok, BRAND.warn],
    quad:    [BRAND.blue, BRAND.ok, BRAND.warn, BRAND.bad],
    penta:   [BRAND.blue, BRAND.ok, BRAND.warn, BRAND.bad, BRAND.info],
    // Aging buckets green→red, matches Aged AR/AP views
    aging:   [BRAND.ok, BRAND.blueLt, BRAND.warn, BRAND.bad, '#7C1D1D'],
  };

  function tzs(v) {
    if (v === null || v === undefined || isNaN(v)) return '—';
    const n = Number(v);
    if (Math.abs(n) >= 1_000_000) return 'TZS ' + (n / 1_000_000).toFixed(1) + 'M';
    if (Math.abs(n) >= 1_000)     return 'TZS ' + (n / 1_000).toFixed(0) + 'k';
    return 'TZS ' + n.toFixed(0);
  }

  function tzsExact(v) {
    if (v === null || v === undefined || isNaN(v)) return '—';
    return 'TZS ' + Number(v).toLocaleString('en-US', { maximumFractionDigits: 0 });
  }

  function seriesAllZero(series) {
    return series.every(s => {
      const d = s.data || s;
      return !d.some(v => Number(v) > 0.01);
    });
  }

  function drawEmpty(el, msg) {
    if (typeof el === 'string') el = document.querySelector(el);
    if (!el) return;
    el.innerHTML = `
      <div style="display:flex; flex-direction:column; align-items:center; justify-content:center;
                  height:100%; min-height:180px; color:${BRAND.muted}; text-align:center;">
        <div style="font-size:28px; opacity:.4; margin-bottom:6px;">
          <i class="fas fa-chart-simple"></i>
        </div>
        <div style="font-size:12px;">${msg || 'No data yet.'}</div>
      </div>`;
  }

  /* ══════════════ Chart config builders ══════════════ */

  const commonDefaults = {
    chart: {
      fontFamily: '"Open Sans", system-ui, -apple-system, sans-serif',
      toolbar: { show: false },
      animations: { enabled: true, speed: 350, easing: 'easeout' },
      foreColor: BRAND.muted,
    },
    grid: {
      borderColor: BRAND.rule,
      strokeDashArray: 3,
      xaxis: { lines: { show: false } },
    },
    dataLabels: { enabled: false },
    stroke: { curve: 'smooth', width: 2 },
    xaxis: {
      axisBorder: { show: false },
      axisTicks:  { show: false },
      labels: { style: { colors: BRAND.muted, fontSize: '11px' } },
    },
    yaxis: {
      labels: { style: { colors: BRAND.muted, fontSize: '11px' } },
    },
    tooltip: {
      theme: 'light',
      style: { fontFamily: '"Open Sans", sans-serif', fontSize: '12px' },
    },
    legend: {
      position: 'top', horizontalAlign: 'right',
      labels: { colors: BRAND.ink },
      fontSize: '12px', fontWeight: 500,
      markers: { width: 8, height: 8, radius: 4 },
    },
  };

  function build(type, opts) {
    const {
      series, categories, tzs: isTzs, colors, title,
      height, stacked, horizontal, distributed, dataLabels,
      max, min, subtitle,
    } = opts;

    const cfg = JSON.parse(JSON.stringify(commonDefaults));
    cfg.chart.type   = type === 'donut' || type === 'pie' ? type
                       : type === 'radialBar' ? 'radialBar'
                       : type;
    cfg.chart.height = height || 260;
    cfg.series = series;

    if (colors) cfg.colors = Array.isArray(colors) ? colors : PALETTES[colors] || PALETTES.single;
    else        cfg.colors = PALETTES.single;

    if (categories) cfg.xaxis.categories = categories;
    if (stacked)    cfg.chart.stacked   = true;
    if (dataLabels) cfg.dataLabels.enabled = true;

    if (isTzs) {
      cfg.yaxis.labels.formatter = tzs;
      cfg.tooltip.y = { formatter: tzsExact };
    }

    if (title) {
      cfg.title = {
        text: title, align: 'left',
        style: { fontSize: '13px', fontWeight: 700, color: BRAND.ink },
      };
      if (subtitle) cfg.subtitle = {
        text: subtitle, align: 'left',
        style: { fontSize: '11px', color: BRAND.muted },
      };
    }

    /* ── Type-specific overrides ─────────────────────── */
    switch (type) {
      case 'area':
        cfg.stroke = { curve: 'smooth', width: 2.5 };
        cfg.fill = {
          type: 'gradient',
          gradient: { shadeIntensity: 1, opacityFrom: 0.35, opacityTo: 0.05, stops: [0, 90, 100] },
        };
        break;

      case 'bar':
        cfg.plotOptions = {
          bar: {
            horizontal: !!horizontal,
            borderRadius: 4,
            columnWidth: '55%',
            distributed: !!distributed,
          },
        };
        if (distributed) cfg.legend = { show: false };
        break;

      case 'donut':
      case 'pie':
        cfg.stroke = { width: 0 };
        cfg.legend = { position: 'right', fontSize: '11.5px', labels: { colors: BRAND.ink } };
        cfg.labels = categories || [];
        cfg.plotOptions = {
          pie: {
            donut: {
              size: '68%',
              labels: {
                show: type === 'donut',
                total: {
                  show: true, showAlways: true, label: 'Total',
                  color: BRAND.muted, fontSize: '11px',
                  formatter: function (w) {
                    const sum = w.globals.seriesTotals.reduce((a, b) => a + b, 0);
                    return isTzs ? tzs(sum) : sum.toLocaleString();
                  },
                },
                value: {
                  color: BRAND.ink, fontSize: '20px', fontWeight: 700,
                  formatter: (v) => isTzs ? tzs(v) : Number(v).toLocaleString(),
                },
              },
            },
          },
        };
        if (isTzs) cfg.tooltip.y = { formatter: tzsExact };
        break;

      case 'radialBar':
        cfg.chart.type = 'radialBar';
        cfg.plotOptions = {
          radialBar: {
            hollow:    { size: '62%' },
            track:     { background: BRAND.rule, strokeWidth: '100%' },
            dataLabels: {
              name:  { fontSize: '11px', color: BRAND.muted, offsetY: -6 },
              value: {
                fontSize: '24px', fontWeight: 700, color: BRAND.ink,
                offsetY: 4,
                formatter: (val) => opts.suffix ? `${val}${opts.suffix}` : `${val}%`,
              },
            },
          },
        };
        cfg.labels = opts.label ? [opts.label] : [''];
        cfg.stroke = { lineCap: 'round' };
        break;

      case 'heatmap':
        cfg.plotOptions = {
          heatmap: {
            radius: 2, useFillColorAsStroke: false,
            colorScale: {
              ranges: [
                { from: 0,     to: 0,     color: BRAND.tint,  name: 'None'   },
                { from: 1,     to: 3,     color: BRAND.blueLt, name: 'Low'   },
                { from: 4,     to: 7,     color: BRAND.blue,   name: 'Mid'   },
                { from: 8,     to: 999,   color: BRAND.blueDk, name: 'High'  },
              ],
            },
          },
        };
        cfg.stroke = { width: 0 };
        cfg.dataLabels = { enabled: false };
        break;

      case 'rangeBar':
        cfg.plotOptions = {
          bar: { horizontal: true, barHeight: '55%', borderRadius: 4 },
        };
        break;

      case 'line':
        cfg.stroke = { curve: 'smooth', width: 2 };
        cfg.markers = { size: 3, hover: { size: 5 } };
        break;
    }

    if (typeof max === 'number') cfg.yaxis.max = max;
    if (typeof min === 'number') cfg.yaxis.min = min;

    return cfg;
  }

  /* ══════════════ Public class ══════════════ */

  window.PacificChart = function PacificChart(target, type, opts) {
    const el = typeof target === 'string' ? document.querySelector(target) : target;
    if (!el) { console.warn('[PacificChart] target not found:', target); return null; }

    // Empty-state fast path
    if (opts && opts.series && seriesAllZero(opts.series)) {
      drawEmpty(el, opts.emptyMessage);
      return null;
    }

    const cfg = build(type, opts || {});
    const chart = new ApexCharts(el, cfg);
    chart.render();
    return chart;
  };

  // Expose the palette so views can style non-chart bits (badges, chips) with
  // the exact same colours the chart uses.
  window.PacificChart.palette = BRAND;
  window.PacificChart.tzs     = tzs;
  window.PacificChart.tzsExact= tzsExact;
})();
