/* Landing widgets — visuals referenced from landing.jsx
   All charts are pure-SVG, no external chart libs. */

/* global React, window */
const { useMemo, useEffect, useState, useRef } = React;

// ─── Mini live map for hero ────────────────────────────────────────────────
function HeroMap() {
  const W = 420, H = 420;
  const padX = 24, padY = 24;
  const innerW = W - padX * 2, innerH = H - padY * 2;
  const polandAspect = 1.05;
  const scaleW = Math.min(innerW, innerH * polandAspect);
  const scaleH = scaleW / polandAspect;
  const offX = (W - scaleW) / 2;
  const offY = (H - scaleH) / 2;
  const toPx = (x, y) => [offX + x * scaleW, offY + y * scaleH];

  const [tick, setTick] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setTick(t => t + 1), 80);
    return () => clearInterval(id);
  }, []);

  // Pick a handful of trains to animate
  const trains = (window.TRAINS || []).filter(t => t.status === 'enroute').slice(0, 20);

  function trainPos(tr, progress) {
    const path = (window.ROUTE_PATHS || {})[tr.route];
    if (!path) return null;
    const segs = [];
    let total = 0;
    for (let i = 0; i < path.length - 1; i++) {
      const [x1, y1] = path[i], [x2, y2] = path[i + 1];
      const d = Math.hypot(x2 - x1, y2 - y1);
      segs.push({ x1, y1, x2, y2, d, cum: total });
      total += d;
    }
    const target = (progress % 1) * total;
    for (const s of segs) {
      if (target <= s.cum + s.d) {
        const k = (target - s.cum) / s.d;
        return toPx(s.x1 + (s.x2 - s.x1) * k, s.y1 + (s.y2 - s.y1) * k);
      }
    }
    return null;
  }

  const occColor = o => o < 0.40 ? '#86b06a' : o < 0.70 ? '#f59e0b' : '#b83826';

  const border = window.POLAND_BORDER || [];
  const borderD = border.map((p, i) => (i === 0 ? 'M' : 'L') + toPx(p[0], p[1]).join(' ')).join(' ') + ' Z';

  return (
    <svg className="chart" viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet">
      <defs>
        <radialGradient id="heroGlow" cx="50%" cy="50%" r="50%">
          <stop offset="0%" stopColor="rgba(224,17,95,0.12)" />
          <stop offset="100%" stopColor="rgba(224,17,95,0)" />
        </radialGradient>
      </defs>
      <rect width={W} height={H} fill="url(#heroGlow)" />

      {/* Grid */}
      {[0.25, 0.5, 0.75].map(g => (
        <line key={'x' + g} x1={padX + g * innerW} y1={padY}
          x2={padX + g * innerW} y2={H - padY}
          stroke="rgba(255,255,255,0.03)" />
      ))}
      {[0.25, 0.5, 0.75].map(g => (
        <line key={'y' + g} x1={padX} y1={padY + g * innerH}
          x2={W - padX} y2={padY + g * innerH}
          stroke="rgba(255,255,255,0.03)" />
      ))}

      {/* Poland outline */}
      <path d={borderD} fill="rgba(224,17,95,0.05)"
        stroke="rgba(224,17,95,0.7)" strokeWidth="1.4" strokeLinejoin="round" />

      {/* Route paths */}
      {Object.entries(window.ROUTE_PATHS || {}).map(([id, path]) => {
        const d = path.map((p, i) => (i === 0 ? 'M' : 'L') + toPx(p[0], p[1]).join(' ')).join(' ');
        return <path key={id} d={d} fill="none"
          stroke="rgba(224,17,95,0.15)" strokeWidth="1" strokeDasharray="3 3" />;
      })}

      {/* City dots */}
      {Object.entries(window.CITIES || {}).map(([name, c]) => {
        if (c.offMap) return null;
        const [x, y] = toPx(c.x, c.y);
        return (
          <circle key={name} cx={x} cy={y} r="2.5"
            fill="#e7e5df" stroke="#0f1114" strokeWidth="1.5" />
        );
      })}

      {/* Animated trains */}
      {trains.map((tr, i) => {
        const phase = (tr.progressPct + tick * 0.004 + i * 0.05) % 1;
        const pos = trainPos(tr, phase);
        if (!pos) return null;
        const [x, y] = pos;
        const meta = (window.CARRIERS || {})[tr.carrier] || { color: '#e0115f' };
        return (
          <g key={tr.id}>
            <circle cx={x} cy={y} r="7" fill={meta.color} fillOpacity="0.15"
              stroke={meta.color} strokeWidth="1" />
            <circle cx={x} cy={y} r="2.5" fill={occColor(tr.occupancy)} />
          </g>
        );
      })}
    </svg>
  );
}

// ─── Booking curve chart ───────────────────────────────────────────────────
function BookingCurve() {
  const W = 520, H = 320;
  const pad = { t: 28, r: 24, b: 32, l: 36 };

  // Generate a forecast band and actuals. X = days to departure (90 → 0). Y = load %
  const days = Array.from({ length: 46 }, (_, i) => 90 - i * 2);
  const forecast = days.map(d => {
    // S-curve from ~8% at 90 days to ~78% at 0 days
    const t = 1 - d / 90;
    return 6 + 80 / (1 + Math.exp(-(t * 10 - 4.5)));
  });
  const upper = forecast.map(v => Math.min(100, v + 6));
  const lower = forecast.map(v => Math.max(0, v - 6));
  // Actuals — stop at day 12, follow curve with noise, then a recent uptick
  const actual = [];
  for (let i = 0; i < days.length; i++) {
    const d = days[i];
    if (d < 12) break;
    const noise = Math.sin(i * 1.7) * 2 + Math.cos(i * 0.6) * 1.5;
    const push = d < 30 ? 4 : 0; // beating forecast in the last 30 days
    actual.push(forecast[i] + noise + push);
  }

  const x = i => pad.l + (i / (days.length - 1)) * (W - pad.l - pad.r);
  const y = v => pad.t + (1 - v / 100) * (H - pad.t - pad.b);

  const forecastD = forecast.map((v, i) => (i === 0 ? 'M' : 'L') + x(i) + ' ' + y(v)).join(' ');
  const bandD =
    upper.map((v, i) => (i === 0 ? 'M' : 'L') + x(i) + ' ' + y(v)).join(' ') +
    ' ' +
    lower.map((v, i) => 'L' + x(days.length - 1 - i) + ' ' + y(lower[days.length - 1 - i])).join(' ') +
    ' Z';
  const actualD = actual.map((v, i) => (i === 0 ? 'M' : 'L') + x(i) + ' ' + y(v)).join(' ');

  const actualLast = { i: actual.length - 1, v: actual[actual.length - 1] };

  return (
    <svg className="chart" viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet">
      {/* Y grid */}
      {[0, 25, 50, 75, 100].map(g => (
        <g key={g}>
          <line x1={pad.l} y1={y(g)} x2={W - pad.r} y2={y(g)} stroke="var(--border)" />
          <text x={pad.l - 6} y={y(g) + 3} textAnchor="end">{g}%</text>
        </g>
      ))}
      {/* X axis */}
      {[90, 60, 30, 0].map(d => {
        const i = days.indexOf(d);
        return (
          <g key={d}>
            <text x={x(i)} y={H - pad.b + 14} textAnchor="middle">{d}d</text>
          </g>
        );
      })}
      {/* Forecast band */}
      <path d={bandD} fill="rgba(224,17,95,0.08)" stroke="none" />
      {/* Forecast line */}
      <path d={forecastD} fill="none" stroke="rgba(224,17,95,0.55)" strokeWidth="1.2" strokeDasharray="4 3" />
      {/* Actual line */}
      <path d={actualD} fill="none" stroke="var(--hi)" strokeWidth="2" />
      {/* Actual end marker */}
      <circle cx={x(actualLast.i)} cy={y(actualLast.v)} r="4" fill="var(--hi)" />
      <circle cx={x(actualLast.i)} cy={y(actualLast.v)} r="9" fill="none" stroke="var(--hi)" strokeOpacity="0.4" />
      {/* Labels */}
      <text x={W - pad.r} y={pad.t - 12} textAnchor="end" fill="var(--hi)" style={{ fontWeight: 600 }}>
        ACTUAL · WAW→KRK · 18 May
      </text>
      <text x={pad.l} y={pad.t - 12} fill="var(--text-dim)">
        FORECAST ±1σ
      </text>
    </svg>
  );
}

// ─── Pricing ladder ────────────────────────────────────────────────────────
function PricingLadder() {
  const classes = [
    { k: 'A', cur: 39, rec: 49, cap: 60, label: 'Super Economy' },
    { k: 'B', cur: 69, rec: 79, cap: 99, label: 'Economy' },
    { k: 'C', cur: 109, rec: 119, cap: 149, label: 'Standard' },
    { k: 'D', cur: 159, rec: 169, cap: 199, label: 'Flex' },
    { k: 'E', cur: 229, rec: 249, cap: 299, label: 'Business' },
  ];
  const W = 520, H = 320;
  const pad = { t: 24, r: 28, b: 24, l: 110 };
  const maxP = 320;
  const rowH = (H - pad.t - pad.b) / classes.length;
  const x = v => pad.l + (v / maxP) * (W - pad.l - pad.r);

  return (
    <svg className="chart" viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet">
      {classes.map((c, i) => {
        const yTop = pad.t + i * rowH;
        const yMid = yTop + rowH / 2;
        return (
          <g key={c.k}>
            <text x={pad.l - 10} y={yMid + 3} textAnchor="end" fill="var(--text)" style={{ fontSize: 11 }}>
              {c.k} · {c.label}
            </text>
            {/* floor→ceiling corridor */}
            <line x1={x(c.cur - 20)} y1={yMid} x2={x(c.cap)} y2={yMid}
              stroke="var(--border-strong)" strokeWidth="1" />
            {/* current */}
            <rect x={x(c.cur) - 2} y={yMid - 7} width="4" height="14" fill="var(--text-dim)" />
            {/* recommended */}
            <rect x={x(c.rec) - 3} y={yMid - 10} width="6" height="20" fill="var(--accent)" />
            {/* ceiling */}
            <rect x={x(c.cap) - 1} y={yMid - 5} width="2" height="10" fill="var(--text-mute)" />
            {/* labels */}
            <text x={x(c.cur)} y={yMid - 12} textAnchor="middle" fill="var(--text-dim)">
              {c.cur} zł
            </text>
            <text x={x(c.rec)} y={yMid + 22} textAnchor="middle" fill="var(--accent)" style={{ fontWeight: 600 }}>
              → {c.rec} zł
            </text>
          </g>
        );
      })}
      <text x={pad.l} y={14} fill="var(--text-dim)">
        CURRENT · RECOMMENDED · CEILING
      </text>
      <text x={W - pad.r} y={14} textAnchor="end" fill="var(--hi)" style={{ fontWeight: 600 }}>
        +18,420 zł / train · if applied
      </text>
    </svg>
  );
}

// ─── Competitive intelligence bars ─────────────────────────────────────────
function CompeteBars() {
  const rows = [
    { op: 'You · IC',        price: 129, cap: 820, color: '#e0115f', own: true },
    { op: 'RegioJet',         price: 99,  cap: 450, color: '#FABB00' },
    { op: 'Leo Express',      price: 109, cap: 380, color: '#F08200' },
    { op: 'FlixBus (bus)',    price: 79,  cap: 260, color: '#6aa1d9' },
    { op: 'PKS (bus)',        price: 89,  cap: 180, color: '#8f8f97' },
    { op: 'Ryanair (KRK–WAW)',price: 59,  cap: 189, color: '#b4b4b4' },
  ];
  const maxP = 160;
  const W = 520, H = 320;
  const pad = { t: 28, r: 72, b: 20, l: 140 };
  const rowH = (H - pad.t - pad.b) / rows.length;

  return (
    <svg className="chart" viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet">
      <text x={pad.l - 10} y={16} textAnchor="end" fill="var(--text-dim)">
        OPERATOR
      </text>
      <text x={pad.l + 4} y={16} fill="var(--text-dim)">
        PRICE (avg, 7-day, WAW↔KRK)
      </text>
      <text x={W - pad.r + 8} y={16} fill="var(--text-dim)">
        CAPACITY
      </text>
      {rows.map((r, i) => {
        const y = pad.t + i * rowH + 6;
        const barW = (r.price / maxP) * (W - pad.l - pad.r);
        return (
          <g key={r.op}>
            <text x={pad.l - 10} y={y + rowH / 2 + 1} textAnchor="end"
              fill={r.own ? 'var(--accent)' : 'var(--text)'}
              style={{ fontWeight: r.own ? 600 : 400 }}>
              {r.op}
            </text>
            <rect x={pad.l} y={y} width={barW} height={rowH - 12}
              fill={r.color} fillOpacity={r.own ? 1 : 0.4}
              stroke={r.color} strokeWidth={r.own ? 0 : 1} />
            <text x={pad.l + barW + 6} y={y + rowH / 2 + 1}
              fill={r.own ? 'var(--accent)' : 'var(--text)'}>
              {r.price} zł
            </text>
            <text x={W - pad.r + 8} y={y + rowH / 2 + 1} fill="var(--text-dim)">
              {r.cap} seats
            </text>
          </g>
        );
      })}
    </svg>
  );
}

// ─── OD Matrix heatmap ─────────────────────────────────────────────────────
function ODMatrix() {
  const stops = ['WAW', 'KRK', 'GDN', 'POZ', 'WRO', 'KAT', 'SZC'];
  // Symmetric-ish demand matrix (0–1)
  const seed = 'odmatrix'.split('').reduce((a, c) => a + c.charCodeAt(0), 0);
  let s = seed;
  const rand = () => { s = (s * 9301 + 49297) % 233280; return s / 233280; };
  const m = stops.map((_, i) =>
    stops.map((__, j) => {
      if (i === j) return null;
      // Warsaw corridor is denser
      const boost = (stops[i] === 'WAW' || stops[j] === 'WAW') ? 0.3 : 0;
      return Math.min(1, 0.15 + rand() * 0.6 + boost);
    })
  );
  const W = 520, H = 320;
  const cell = Math.min((W - 80) / (stops.length + 1), (H - 40) / (stops.length + 1));
  const offX = (W - cell * (stops.length + 1)) / 2;
  const offY = 20;
  const heat = v => {
    if (v === null) return '#14161a';
    const a = 0.08 + v * 0.9;
    return `rgba(224,17,95,${a})`;
  };
  return (
    <svg className="chart" viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet">
      {/* Column labels */}
      {stops.map((s, j) => (
        <text key={'c' + s} x={offX + (j + 1) * cell + cell / 2}
          y={offY + cell / 2 + 3} textAnchor="middle" fill="var(--text-dim)">
          {s}
        </text>
      ))}
      {/* Row labels + cells */}
      {stops.map((r, i) => (
        <g key={r}>
          <text x={offX + cell / 2} y={offY + (i + 1) * cell + cell / 2 + 3}
            textAnchor="middle" fill="var(--text-dim)">
            {r}
          </text>
          {m[i].map((v, j) => {
            const x = offX + (j + 1) * cell;
            const y = offY + (i + 1) * cell;
            return (
              <g key={j}>
                <rect x={x + 1} y={y + 1} width={cell - 2} height={cell - 2}
                  fill={heat(v)} />
                {v !== null && v > 0.55 && (
                  <text x={x + cell / 2} y={y + cell / 2 + 3} textAnchor="middle"
                    fill="#0c0d10" style={{ fontWeight: 600 }}>
                    {Math.round(v * 100)}
                  </text>
                )}
              </g>
            );
          })}
        </g>
      ))}
      <text x={offX} y={H - 8} fill="var(--text-dim)">
        O&D DEMAND INDEX · 7-DAY AVG · ROW=ORIGIN · COL=DEST
      </text>
    </svg>
  );
}

// ─── Demo frame (wider fake dashboard preview) ─────────────────────────────
function DemoFrame() {
  // Simulated multi-panel dashboard: revenue over time + fare class stack + alerts
  const W = 760, H = 460;
  // 24 hours of revenue
  const hours = Array.from({ length: 24 }, (_, i) => i);
  const rev = hours.map(h => {
    // Double-bump morning + evening
    const m = Math.exp(-Math.pow((h - 8) / 2.4, 2)) * 1.0;
    const e = Math.exp(-Math.pow((h - 17) / 3.0, 2)) * 1.2;
    return 25 + (m + e) * 110 + Math.sin(h) * 6;
  });
  const pad = { t: 40, r: 24, b: 36, l: 40 };
  const chartW = W - pad.l - pad.r;
  const chartH = 180;
  const maxR = Math.max(...rev);
  const x = h => pad.l + (h / 23) * chartW;
  const y = v => pad.t + chartH - (v / maxR) * chartH;

  const areaD =
    'M' + x(0) + ' ' + y(rev[0]) + ' ' +
    rev.slice(1).map((v, i) => 'L' + x(i + 1) + ' ' + y(v)).join(' ') +
    ' L' + x(23) + ' ' + (pad.t + chartH) +
    ' L' + x(0)  + ' ' + (pad.t + chartH) + ' Z';
  const lineD = 'M' + x(0) + ' ' + y(rev[0]) + ' ' +
    rev.slice(1).map((v, i) => 'L' + x(i + 1) + ' ' + y(v)).join(' ');

  // Fare class stack
  const classes = [
    { k: 'A', v: 14, color: '#86b06a' },
    { k: 'B', v: 32, color: '#e0115f' },
    { k: 'C', v: 28, color: '#e0115f' },
    { k: 'D', v: 16, color: '#b83826' },
    { k: 'E', v: 10, color: '#b4b4b4' },
  ];
  const stackTotal = classes.reduce((a, c) => a + c.v, 0);
  const stackY = pad.t + chartH + 68;
  const stackW = chartW;
  let acc = 0;

  // Alerts
  const alerts = [
    { t: '08:42', m: 'RegioJet undercut detected · KRK→PRG · −18 zł', k: 'warn' },
    { t: '08:31', m: 'Forecast beating plan · WAW→GDN · +4.2%', k: 'ok' },
    { t: '08:17', m: 'Auto-repriced class C · WAW→POZ · +10 zł', k: 'ok' },
  ];

  return (
    <svg className="chart" viewBox={`0 0 ${W} ${H}`} preserveAspectRatio="xMidYMid meet">
      {/* Top row labels */}
      <text x={pad.l} y={20} fill="var(--text-dim)" style={{ fontWeight: 600 }}>
        REVENUE · LAST 24H · ALL CORRIDORS
      </text>
      <text x={W - pad.r} y={20} textAnchor="end" fill="var(--hi)" style={{ fontWeight: 600 }}>
        2.41 mln zł · +4.8%
      </text>

      {/* Grid */}
      {[0.25, 0.5, 0.75, 1].map(g => (
        <line key={g} x1={pad.l} y1={pad.t + chartH - g * chartH}
          x2={W - pad.r} y2={pad.t + chartH - g * chartH}
          stroke="var(--border)" />
      ))}
      {/* Revenue area */}
      <path d={areaD} fill="rgba(224,17,95,0.14)" />
      <path d={lineD} fill="none" stroke="var(--hi)" strokeWidth="1.8" />

      {/* Hour labels */}
      {[0, 6, 12, 18, 23].map(h => (
        <text key={h} x={x(h)} y={pad.t + chartH + 16} textAnchor="middle" fill="var(--text-mute)">
          {String(h).padStart(2, '0')}:00
        </text>
      ))}

      {/* Divider */}
      <line x1={pad.l} y1={stackY - 14} x2={W - pad.r} y2={stackY - 14} stroke="var(--border)" />

      {/* Stack */}
      <text x={pad.l} y={stackY - 20} fill="var(--text-dim)" style={{ fontWeight: 600 }}>
        FARE CLASS MIX
      </text>
      {classes.map(c => {
        const w = (c.v / stackTotal) * stackW;
        const rx = pad.l + acc;
        acc += w;
        return (
          <g key={c.k}>
            <rect x={rx} y={stackY} width={w - 1} height="18" fill={c.color} />
            <text x={rx + w / 2} y={stackY + 12} textAnchor="middle"
              fill="#0c0d10" style={{ fontWeight: 600 }}>
              {c.k} · {c.v}%
            </text>
          </g>
        );
      })}

      {/* Alerts */}
      <text x={pad.l} y={stackY + 50} fill="var(--text-dim)" style={{ fontWeight: 600 }}>
        ALERTS · LIVE
      </text>
      {alerts.map((a, i) => {
        const ay = stackY + 66 + i * 22;
        const color = a.k === 'warn' ? 'var(--bad)' : 'var(--ok)';
        return (
          <g key={i}>
            <circle cx={pad.l + 4} cy={ay - 3} r="3" fill={color} />
            <text x={pad.l + 16} y={ay} fill="var(--text-dim)">{a.t}</text>
            <text x={pad.l + 60} y={ay} fill="var(--text)">{a.m}</text>
          </g>
        );
      })}
    </svg>
  );
}

// Exports
Object.assign(window, { HeroMap, BookingCurve, PricingLadder, CompeteBars, ODMatrix, DemoFrame });
