/* global React */
/* Cyprus Airways RM — formatters, hand-rolled SVG charts, primitives (global). */
const { useState, useEffect, useRef, useMemo, useLayoutEffect } = React;

// ---------- Formatters (EUR) ----------
const fmtEUR = v => {
  if (v == null || isNaN(v)) return '—';
  const a = Math.abs(v);
  if (a >= 1e9) return '€' + (v/1e9).toFixed(2) + 'B';
  if (a >= 1e6) return '€' + (v/1e6).toFixed(1) + 'M';
  if (a >= 1e3) return '€' + (v/1e3).toFixed(0) + 'K';
  return '€' + Math.round(v);
};
const fmtEUR0 = v => v == null ? '—' : '€' + Number(v).toLocaleString('en-US', {maximumFractionDigits: 0});
const fmtN = v => v == null ? '—' : Number(v).toLocaleString('en-US');
const fmtK = v => { if (v == null) return '—'; const a = Math.abs(v);
  if (a >= 1e6) return (v/1e6).toFixed(2) + 'M'; if (a >= 1e3) return (v/1e3).toFixed(1) + 'K'; return Number(v).toFixed(0); };
const fmtPct = (v, d=1) => v == null ? '—' : Number(v).toFixed(d) + '%';
const fmtSignPct = (v, d=1) => v == null ? '—' : (v > 0 ? '+' : '') + Number(v).toFixed(d) + '%';
const MONTHS = ['','Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];

// ---------- Delta ----------
const Delta = ({ value, suffix = '%', digits = 1, inverse = false }) => {
  if (value == null || isNaN(value)) return null;
  const pos = inverse ? value < 0 : value > 0;
  const neg = inverse ? value > 0 : value < 0;
  const cls = pos ? 'text-pos' : neg ? 'text-neg' : 'text-muted';
  const arrow = value > 0 ? '▲' : value < 0 ? '▼' : '·';
  return React.createElement('span', { className: `mono ${cls}`, style: { fontSize: 10.5, fontWeight: 500 } },
    `${arrow} ${value > 0 ? '+' : ''}${Number(value).toFixed(digits)}${suffix}`);
};

// ---------- chart sizing ----------
function useSize(ref) {
  const [size, setSize] = useState({ w: 0, h: 0 });
  useLayoutEffect(() => {
    if (!ref.current) return;
    const ro = new ResizeObserver(es => { for (const e of es) setSize({ w: e.contentRect.width, h: e.contentRect.height }); });
    ro.observe(ref.current);
    setSize({ w: ref.current.clientWidth, h: ref.current.clientHeight });
    return () => ro.disconnect();
  }, [ref]);
  return size;
}

const Sparkline = ({ data, width = 80, height = 24, color, fill = true }) => {
  if (!data || data.length < 2) return null;
  const min = Math.min(...data), max = Math.max(...data); const range = max - min || 1;
  const dx = width / (data.length - 1);
  const pts = data.map((v, i) => `${i*dx},${height - ((v-min)/range)*height}`).join(' ');
  const c = color || 'var(--accent)';
  return React.createElement('svg', { width, height, className: 'spark' },
    fill && React.createElement('polygon', { points: `0,${height} ${pts} ${width},${height}`, fill: c, fillOpacity: 0.13 }),
    React.createElement('polyline', { points: pts, fill: 'none', stroke: c, strokeWidth: 1.4 }));
};

// ---------- Bar chart (vertical / horizontal, grouped) ----------
const BarChart = ({ data, height = 240, valueKey = 'value', labelKey = 'label', format = fmtN,
                   color, secondaryKey, secondaryColor, showLabels = true, horizontal = false,
                   valueLabel = false, tooltipFormat, onBarClick }) => {
  const ref = useRef(); const { w } = useSize(ref);
  const padL = horizontal ? 124 : 72, padR = 16, padT = 16, padB = horizontal ? 24 : 56;
  const innerW = Math.max(0, w - padL - padR); const innerH = Math.max(0, height - padT - padB);
  const c1 = color || 'var(--ink)'; const c2 = secondaryColor || 'var(--accent)';
  const grouped = !!secondaryKey;
  const allVals = data.flatMap(d => grouped ? [d[valueKey]||0, d[secondaryKey]||0] : [d[valueKey]||0]);
  const max = Math.max(...allVals, 0) * 1.12 || 1; const ticks = 4;
  const [hover, setHover] = useState(null);

  if (horizontal) {
    const rowH = innerH / data.length; const barH = Math.min(20, rowH * 0.66);
    return React.createElement('div', { ref, style: { width: '100%', height, position: 'relative' } },
      React.createElement('svg', { width: w, height, style: { display: 'block' } },
        Array.from({ length: ticks+1 }, (_, i) => { const x = padL + innerW*i/ticks;
          return React.createElement('g', { key: i },
            React.createElement('line', { x1: x, x2: x, y1: padT, y2: padT+innerH, className: 'grid-line' }),
            React.createElement('text', { x, y: height-6, textAnchor: 'middle', className: 'axis-text' }, format(max*i/ticks))); }),
        data.map((d, i) => { const y = padT + i*rowH + (rowH-barH)/2; const v = d[valueKey]||0; const bw = (v/max)*innerW;
          return React.createElement('g', { key: i },
            React.createElement('text', { x: padL-8, y: y+barH/2+3, textAnchor: 'end', className: 'axis-text' }, (d[labelKey]||'').slice(0,20)),
            React.createElement('rect', { x: padL, y, width: bw, height: barH, fill: c1, rx: 2, className: 'bar',
              onMouseEnter: e => setHover({ x: e.clientX, y: e.clientY, d, v }), onMouseLeave: () => setHover(null),
              style: onBarClick ? { cursor: 'pointer' } : undefined, onClick: onBarClick ? () => onBarClick(d) : undefined }),
            showLabels && bw > 34 && React.createElement('text', { x: padL+bw-5, y: y+barH/2+3, textAnchor: 'end',
              style: { fill: 'var(--paper)', fontWeight: 600, fontFamily: 'var(--mono)', fontSize: 9.5 } }, format(v))); })),
      hover && React.createElement('div', { className: 'tip',
        style: { left: hover.x - ref.current.getBoundingClientRect().left + 10, top: hover.y - ref.current.getBoundingClientRect().top - 30 } },
        `${hover.d[labelKey]}: ${format(hover.v)}`));
  }

  const groupW = innerW / data.length;
  const barW = grouped ? Math.min(17, groupW*0.36) : Math.min(30, groupW*0.62);
  const gap = grouped ? 2 : 0;
  // signed scale with a zero baseline so negative bars (e.g. Δ revenue) render downward
  const topV = (Math.max(...allVals, 0) || 1) * 1.08;
  const botV = Math.min(...allVals, 0) * 1.08;
  const span = (topV - botV) || 1;
  const yOf = v => padT + innerH - ((v - botV) / span) * innerH;
  const zeroY = yOf(0);
  return React.createElement('div', { ref, style: { width: '100%', height, position: 'relative' } },
    React.createElement('svg', { width: w, height, style: { display: 'block' } },
      Array.from({ length: ticks+1 }, (_, i) => { const tv = botV + span*i/ticks; const y = yOf(tv);
        return React.createElement('g', { key: i },
          React.createElement('line', { x1: padL, x2: padL+innerW, y1: y, y2: y, className: 'grid-line' }),
          React.createElement('text', { x: padL-6, y: y+3, textAnchor: 'end', className: 'axis-text' }, format(tv))); }),
      data.map((d, i) => { const cx = padL + i*groupW + groupW/2; const v1 = d[valueKey]||0; const v2 = grouped ? (d[secondaryKey]||0) : 0;
        const y1 = Math.min(yOf(v1), zeroY), h1 = Math.abs(yOf(v1) - zeroY);
        const y2 = Math.min(yOf(v2), zeroY), h2 = Math.abs(yOf(v2) - zeroY);
        const x1 = grouped ? cx-barW-gap/2 : cx-barW/2; const x2 = grouped ? cx+gap/2 : cx;
        const label = (d[labelKey]||'').toString();
        const fill1 = v1 < 0 ? 'var(--neg)' : c1;
        return React.createElement('g', { key: i },
          React.createElement('rect', { x: x1, y: y1, width: barW, height: Math.max(0.5, h1), fill: fill1, rx: 2, className: 'bar',
            style: onBarClick ? { cursor: 'pointer' } : undefined,
            onMouseEnter: e => setHover({ x: e.clientX, y: e.clientY, d, label, v: v1, k: valueKey }), onMouseLeave: () => setHover(null),
            onClick: onBarClick ? () => onBarClick(d) : undefined }),
          valueLabel && React.createElement('text', { x: x1+barW/2, y: v1 >= 0 ? y1-4 : y1+h1+11, textAnchor: 'middle',
            style: { fontFamily: 'var(--mono)', fontSize: 10, fontWeight: 600, fill: 'var(--text-dim)' } }, format(v1)),
          grouped && React.createElement('rect', { x: x2, y: y2, width: barW, height: Math.max(0.5, h2), fill: c2, rx: 2, className: 'bar',
            onMouseEnter: e => setHover({ x: e.clientX, y: e.clientY, d, label, v: v2, k: secondaryKey }), onMouseLeave: () => setHover(null) }),
          React.createElement('text', { x: cx, y: padT+innerH+14, textAnchor: label.length > 4 ? 'end' : 'middle', className: 'axis-text',
            transform: label.length > 4 ? `rotate(-32 ${cx} ${padT+innerH+14})` : '' }, label.length > 14 ? label.slice(0,13)+'…' : label)); })),
    hover && (() => { const body = tooltipFormat ? tooltipFormat(hover.d, hover.k) : `${hover.label}: ${format(hover.v)}`;
      return React.createElement('div', { className: 'tip',
        style: { left: hover.x - ref.current.getBoundingClientRect().left + 10, top: hover.y - ref.current.getBoundingClientRect().top - 30 } }, body); })());
};

// ---------- Composed: bars + line ----------
const ComposedChart = ({ data, height = 280, barKey, lineKey, labelKey = 'label',
                        barFormat = fmtEUR, lineFormat = v => Number(v).toFixed(0)+'%',
                        barColor = 'var(--ink)', lineColor = 'var(--accent)', barLabel = 'Bar', lineLabel = 'Line' }) => {
  const ref = useRef(); const { w } = useSize(ref);
  const padL = 78, padR = 54, padT = 18, padB = 34;
  const innerW = Math.max(0, w-padL-padR); const innerH = Math.max(0, height-padT-padB);
  const barMax = Math.max(...data.map(d => d[barKey]||0))*1.15 || 1;
  const lineVals = data.map(d => d[lineKey]||0);
  const lineMin = Math.min(...lineVals)*0.92; const lineMax = Math.max(...lineVals)*1.04 || 1;
  const lineRange = lineMax-lineMin || 1; const groupW = innerW/data.length; const barW = Math.min(26, groupW*0.55); const ticks = 4;
  const [hover, setHover] = useState(null);
  const linePts = data.map((d, i) => { const x = padL + i*groupW + groupW/2; const v = d[lineKey]||0;
    return { x, y: padT+innerH-((v-lineMin)/lineRange)*innerH, v, d }; });
  return React.createElement('div', { ref, style: { width: '100%', height, position: 'relative' } },
    React.createElement('svg', { width: w, height, style: { display: 'block' } },
      Array.from({ length: ticks+1 }, (_, i) => { const y = padT+innerH-innerH*i/ticks;
        return React.createElement('g', { key: i },
          React.createElement('line', { x1: padL, x2: padL+innerW, y1: y, y2: y, className: 'grid-line' }),
          React.createElement('text', { x: padL-6, y: y+3, textAnchor: 'end', className: 'axis-text' }, barFormat(barMax*i/ticks)),
          React.createElement('text', { x: padL+innerW+6, y: y+3, textAnchor: 'start', className: 'axis-text' }, lineFormat(lineMin+lineRange*i/ticks))); }),
      data.map((d, i) => { const cx = padL+i*groupW+groupW/2; const v = d[barKey]||0; const h = (v/barMax)*innerH;
        return React.createElement('g', { key: 'b'+i },
          React.createElement('rect', { x: cx-barW/2, y: padT+innerH-h, width: barW, height: h, fill: barColor, rx: 2, className: 'bar', opacity: 0.92,
            onMouseEnter: e => setHover({ x: e.clientX, y: e.clientY, d }), onMouseLeave: () => setHover(null) }),
          (i % Math.ceil(data.length / 13) === 0) && React.createElement('text', {
            x: cx, y: padT+innerH+(data.length > 10 ? 12 : 14), textAnchor: data.length > 10 ? 'end' : 'middle', className: 'axis-text',
            transform: data.length > 10 ? `rotate(-32 ${cx} ${padT+innerH+12})` : '' }, d[labelKey])); }),
      React.createElement('polyline', { points: linePts.map(p => `${p.x},${p.y}`).join(' '), fill: 'none', stroke: lineColor, strokeWidth: 1.9 }),
      linePts.map((p, i) => React.createElement('circle', { key: 'p'+i, cx: p.x, cy: p.y, r: 3, fill: lineColor }))),
    hover && React.createElement('div', { className: 'tip',
      style: { left: Math.max(0, hover.x - ref.current.getBoundingClientRect().left - 60), top: hover.y - ref.current.getBoundingClientRect().top - 50 } },
      React.createElement('div', { style: { fontWeight: 600, marginBottom: 4, color: 'var(--paper)' } }, hover.d[labelKey]),
      React.createElement('div', { style: { color: 'var(--paper)' } }, `${barLabel}: ${barFormat(hover.d[barKey])}`),
      React.createElement('div', { style: { color: 'var(--paper)', marginTop: 2 } }, `${lineLabel}: ${lineFormat(hover.d[lineKey])}`)));
};

function _smooth(points, tension = 0.2) {
  if (!points || points.length < 2) return points && points.length ? `M${points[0][0]},${points[0][1]}` : '';
  let d = `M${points[0][0]},${points[0][1]}`;
  for (let i = 0; i < points.length-1; i++) {
    const p0 = points[i-1]||points[i], p1 = points[i], p2 = points[i+1], p3 = points[i+2]||p2;
    d += ` C${p1[0]+(p2[0]-p0[0])*tension},${p1[1]+(p2[1]-p0[1])*tension} ${p2[0]-(p3[0]-p1[0])*tension},${p2[1]-(p3[1]-p1[1])*tension} ${p2[0]},${p2[1]}`;
  } return d;
}

// ---------- Line chart (multi-series, optional smooth) ----------
const LineChart = ({ data, height = 240, series = [], xKey = 'label', format = fmtN, xFormat = v => v, smooth = false }) => {
  const ref = useRef(); const { w } = useSize(ref);
  const padL = 60, padR = 18, padT = 16, padB = 28;
  const innerW = Math.max(0, w-padL-padR); const innerH = Math.max(0, height-padT-padB);
  const valid = v => v != null && !isNaN(v);
  const allVals = data.flatMap(d => series.map(s => d[s.key])).filter(valid);
  const min = Math.min(...allVals, 0); const max = (allVals.length ? Math.max(...allVals) : 1)*1.05 || 1; const range = max-min || 1;
  const dx = data.length > 1 ? innerW/(data.length-1) : innerW; const ticks = 4;
  const [hover, setHover] = useState(null);
  const yFor = v => padT+innerH-((v-min)/range)*innerH; const xFor = i => padL+i*dx;
  return React.createElement('div', { ref, style: { width: '100%', height, position: 'relative' } },
    React.createElement('svg', { width: w, height, style: { display: 'block' } },
      Array.from({ length: ticks+1 }, (_, i) => { const y = padT+innerH-innerH*i/ticks;
        return React.createElement('g', { key: i },
          React.createElement('line', { x1: padL, x2: padL+innerW, y1: y, y2: y, className: 'grid-line' }),
          React.createElement('text', { x: padL-6, y: y+3, textAnchor: 'end', className: 'axis-text' }, format(min+range*i/ticks))); }),
      data.map((d, i) => i % Math.ceil(data.length/8) === 0 && React.createElement('text', { key: 'x'+i, x: xFor(i), y: padT+innerH+14, textAnchor: 'middle', className: 'axis-text' }, xFormat(d[xKey]))),
      series.map((s, si) => {
        const pairs = data.map((d, i) => valid(d[s.key]) ? [xFor(i), yFor(d[s.key])] : null).filter(Boolean);
        const ptsStr = pairs.map(p => p.join(',')).join(' ');
        const lastIdx = data.reduce((a, d, i) => valid(d[s.key]) ? i : a, -1);
        const firstIdx = data.findIndex(d => valid(d[s.key]));
        const useSm = smooth && pairs.length > 1; const path = useSm ? _smooth(pairs) : null;
        return React.createElement('g', { key: si },
          s.fill && pairs.length > 0 && (useSm
            ? React.createElement('path', { d: `${path} L${xFor(lastIdx)},${padT+innerH} L${xFor(firstIdx)},${padT+innerH} Z`, fill: s.color, fillOpacity: 0.12, stroke: 'none' })
            : React.createElement('polygon', { points: `${xFor(firstIdx)},${padT+innerH} ${ptsStr} ${xFor(lastIdx)},${padT+innerH}`, fill: s.color, fillOpacity: 0.12 })),
          pairs.length > 1 && (useSm
            ? React.createElement('path', { d: path, fill: 'none', stroke: s.color, strokeWidth: s.width||1.7, strokeDasharray: s.dashed ? '7 4' : '', strokeLinecap: 'round' })
            : React.createElement('polyline', { points: ptsStr, fill: 'none', stroke: s.color, strokeWidth: s.width||1.7, strokeDasharray: s.dashed ? '7 4' : '' }))); }),
      data.map((d, i) => React.createElement('rect', { key: 'h'+i, x: xFor(i)-dx/2, y: padT, width: dx, height: innerH, fill: 'transparent',
        onMouseEnter: e => setHover({ x: e.clientX, y: e.clientY, d, i }), onMouseLeave: () => setHover(null) }))),
    hover && React.createElement('div', { className: 'tip', style: { left: Math.min(innerW-40, Math.max(0, xFor(hover.i)-50)), top: padT } },
      React.createElement('div', { style: { fontWeight: 600, marginBottom: 4, color: 'var(--paper)' } }, xFormat(hover.d[xKey])),
      series.map((s, si) => React.createElement('div', { key: si, style: { display: 'flex', alignItems: 'center', gap: 6, color: 'var(--paper)', marginTop: si ? 2 : 0 } },
        React.createElement('span', { style: { width: 10, height: 3, background: s.color, flexShrink: 0 } }),
        valid(hover.d[s.key]) ? `${s.label}: ${format(hover.d[s.key])}` : `${s.label}: —`))),
    React.createElement('div', { style: { position: 'absolute', top: 2, right: 12, display: 'flex', gap: 12, fontSize: 10 } },
      series.map((s, si) => React.createElement('div', { key: si, style: { display: 'flex', alignItems: 'center', gap: 5, color: 'var(--text-dim)' } },
        React.createElement('svg', { width: 18, height: 4 }, React.createElement('line', { x1: 0, y1: 2, x2: 18, y2: 2, stroke: s.color, strokeWidth: s.width||1.7, strokeDasharray: s.dashed ? '4 2' : 'none' })),
        s.label))));
};

// ---------- Chart from a copilot spec ({type,title,x,series,data}) ----------
const ChartFromSpec = ({ spec }) => {
  if (!spec || !spec.data || !spec.data.length) return null;
  const data = spec.data; const x = spec.x || 'label';
  const series = (spec.series || []).map((s, i) => ({ key: s.key, label: s.label || s.key,
    color: i === 0 ? 'var(--accent)' : i === 1 ? 'var(--ink)' : 'var(--amber)', fill: spec.type === 'line', width: 1.8 }));
  const moneyish = JSON.stringify(spec).toLowerCase().match(/revenue|eur|fare|yield/) ? true : false;
  const fmt = moneyish ? fmtEUR : fmtN;
  const norm = data.map(d => ({ ...d, label: d[x] }));
  const body = spec.type === 'line'
    ? React.createElement(LineChart, { data: norm, series, xKey: 'label', format: fmt, height: 220, smooth: true })
    : spec.type === 'grouped-bar' && series.length > 1
      ? React.createElement(BarChart, { data: norm, valueKey: series[0].key, secondaryKey: series[1].key, secondaryColor: 'var(--ink)', color: 'var(--accent)', format: fmt, height: 220 })
      : React.createElement(BarChart, { data: norm, valueKey: series[0] ? series[0].key : 'value', color: 'var(--accent)', format: fmt, height: 220 });
  return React.createElement('div', { style: { marginTop: 8, border: '1px solid var(--rule-soft)', borderRadius: 4, padding: '8px 8px 4px', background: 'var(--paper)' } },
    spec.title && React.createElement('div', { className: 'label', style: { padding: '2px 4px 6px' } }, spec.title), body);
};

// ---------- heat helpers ----------
const heatColor = (v, opts = {}) => {
  const { mid = 0, max = 10 } = opts; const t = Math.max(-1, Math.min(1, (v-mid)/max));
  if (Math.abs(t) < 0.08) return { bg: 'var(--paper-edge)', fg: 'var(--text-dim)' };
  const a = 0.15 + Math.abs(t)*0.55;
  if (t > 0) return { bg: `color-mix(in srgb, var(--green) ${(a*100).toFixed(0)}%, var(--paper-soft))`, fg: a > 0.45 ? '#fff' : 'var(--green)' };
  return { bg: `color-mix(in srgb, var(--neg) ${(a*100).toFixed(0)}%, var(--paper-soft))`, fg: a > 0.45 ? '#fff' : 'var(--neg)' };
};
const occColor = v => {
  if (v == null) return { bg: 'var(--paper-edge)', fg: 'var(--text-dim)' };
  if (v >= 92) return { bg: 'var(--accent)', fg: '#fff' };
  if (v >= 82) return { bg: 'color-mix(in srgb, var(--accent) 68%, var(--paper))', fg: '#fff' };
  if (v >= 70) return { bg: 'color-mix(in srgb, var(--accent) 38%, var(--paper))', fg: 'var(--ink)' };
  if (v >= 55) return { bg: 'color-mix(in srgb, var(--accent) 16%, var(--paper))', fg: 'var(--ink)' };
  return { bg: 'var(--paper-edge)', fg: 'var(--text-dim)' };
};

// ---------- primitives ----------
const Panel = ({ title, sub, actions, children, flush = false, className = '' }) =>
  React.createElement('div', { className: `panel ${className}` },
    (title || actions) && React.createElement('div', { className: 'panel-head' },
      React.createElement('div', null,
        title && React.createElement('div', { className: 'panel-head-title' }, title),
        sub && React.createElement('div', { className: 'panel-head-sub' }, sub)),
      actions && React.createElement('div', { className: 'row gap-2' }, actions)),
    React.createElement('div', { className: flush ? 'panel-body-flush' : 'panel-body' }, children));

const KPI = ({ label, value, sub, delta, deltaInverse, sparkline, sparklineColor }) =>
  React.createElement('div', { className: 'kpi' },
    React.createElement('div', { className: 'kpi-label' }, label),
    React.createElement('div', { className: 'kpi-value' }, value),
    React.createElement('div', { className: 'kpi-sub' },
      sub && React.createElement('span', null, sub),
      delta != null && React.createElement(Delta, { value: delta, inverse: deltaInverse })),
    sparkline && React.createElement('div', { style: { marginTop: 4 } },
      React.createElement(Sparkline, { data: sparkline, width: 84, height: 26, color: sparklineColor || 'var(--accent)' })));

const Pill = ({ kind = 'info', children }) => React.createElement('span', { className: `pill pill-${kind}` }, children);

Object.assign(window, {
  fmtEUR, fmtEUR0, fmtN, fmtK, fmtPct, fmtSignPct, MONTHS,
  Delta, Sparkline, BarChart, ComposedChart, LineChart, ChartFromSpec, heatColor, occColor,
  Panel, KPI, Pill, useSize, useState, useEffect, useRef, useMemo, useLayoutEffect,
});
