// Shared — Gridome tokens, simulated live data, scenarios, icons, small primitives.

// ─── Tokens (mirrored from reference/tokens.css) ────────────────────────────
const T = {
  bg: '#0A0C10',
  surface: '#111318',
  raised: '#181C24',
  hover: '#1E232E',
  border: '#222838',
  borderSubtle: '#1A1F2A',
  textPrimary: '#ECF0F8',
  textSecondary: '#8E97AE',
  textMuted: '#4E5670',
  green: '#2DD4A8',
  greenBright: '#5EECC8',
  blue: '#5B9CF5',
  blueBright: '#80B8FF',
  amber: '#F5B731',
  orange: '#F28322',
  red: '#F04848',
  violet: '#A388F5',
  brandHub: '#2A7B9B',
  tintGreen: 'rgba(45,212,168,0.08)',
  tintBlue: 'rgba(91,156,245,0.07)',
  tintAmber: 'rgba(245,183,49,0.06)',
  tintOrange: 'rgba(242,131,34,0.06)',
  tintRed: 'rgba(240,72,72,0.06)',
  tintViolet: 'rgba(163,136,245,0.08)',
  fontUI: "system-ui, -apple-system, 'Segoe UI', sans-serif",
  fontBrand: "'Space Grotesk', system-ui, sans-serif",
  fontMono: "'SF Mono', 'Fira Code', 'Cascadia Code', 'Consolas', monospace",
};

// Tier color helpers
const TIER_COLOR = { cheap: T.green, standard: T.blue, peak: T.orange, high: T.red };
const TIER_TINT = { cheap: T.tintGreen, standard: T.tintBlue, peak: T.tintOrange, high: T.tintRed };
const TIER_LABEL_PL = { cheap: 'Tanio', standard: 'Średnio', peak: 'Drogo', high: 'Szczyt' };

// ─── Scenarios ─────────────────────────────────────────────────────────────
// Each scenario defines the whole house state at a given moment. Values realistic
// for a Polish prosumer with ~10kWp PV + Deye hybrid + 10kWh battery + OCPP EV.

const SCENARIOS = {
  midday: {
    key: 'midday',
    label: 'Midday surplus',
    hour: 12.5,
    pv: 7.8,          // kW from solar
    home: 1.1,        // kW house load
    battery: -2.6,    // negative = charging
    batterySOC: 68,
    grid: -4.1,       // negative = exporting
    ev: 0,
    priceNow: 38,     // gr/kWh all-in
    tier: 'cheap',
    cheapestHours: '11:00–14:00',
    savedToday: 12.40,
    savedMonth: 214.80,
    recommendation: 'Run dishwasher now — 4.20 zł cheaper than evening',
    weather: 'sunny',
  },
  evening: {
    key: 'evening',
    label: 'Evening peak',
    hour: 19.2,
    pv: 0.2,
    home: 3.8,
    battery: 2.1,     // positive = discharging to house
    batterySOC: 54,
    grid: 1.5,        // importing a touch
    ev: 0,
    priceNow: 142,
    tier: 'high',
    cheapestHours: 'After 23:00',
    savedToday: 18.90,
    savedMonth: 221.30,
    recommendation: 'Skip the tumble dryer — wait 3h to save 6.80 zł',
    weather: 'cloudy',
  },
  overnight: {
    key: 'overnight',
    label: 'Overnight EV',
    hour: 2.4,
    pv: 0,
    home: 0.6,
    battery: -3.0,
    batterySOC: 42,
    grid: 10.6,
    ev: 7.0,
    priceNow: 29,
    tier: 'cheap',
    cheapestHours: '01:00–05:00',
    savedToday: 22.10,
    savedMonth: 236.50,
    recommendation: 'Charging Škoda to 80% by 06:30 — on plan',
    weather: 'clear',
  },
  morning: {
    key: 'morning',
    label: 'Morning ramp',
    hour: 7.6,
    pv: 1.4,
    home: 2.3,
    battery: 0.8,
    batterySOC: 48,
    grid: 0.1,
    ev: 0,
    priceNow: 74,
    tier: 'standard',
    cheapestHours: '11:00–13:00',
    savedToday: 1.90,
    savedMonth: 198.40,
    recommendation: 'Price rises at 08:00 — coffee now, laundry at 11',
    weather: 'partly',
  },
};

// ─── 24h price curve (gr/kWh all-in, shape stays; scenario sets "now") ─────
function buildPriceCurve(scenario) {
  // shape is scenario-shaped but same 24-slot curve skeleton
  const base = [
    32, 28, 26, 29, 30, 35, 48, 72, 95, 84, 62, 44,
    38, 36, 42, 58, 82, 118, 142, 138, 112, 78, 52, 38,
  ];
  // tier by price
  return base.map((p, h) => ({
    h,
    price: p,
    tier: p < 50 ? 'cheap' : p < 95 ? 'standard' : p < 130 ? 'peak' : 'high',
  }));
}

// ─── Live-feel jitter hook — tiny oscillation on scenario values ──────────
function useLiveJitter(base, amount = 0.04) {
  const [val, setVal] = React.useState(base);
  React.useEffect(() => {
    setVal(base);
    const id = setInterval(() => {
      setVal(base + (Math.random() - 0.5) * 2 * amount * Math.abs(base || 1));
    }, 1400);
    return () => clearInterval(id);
  }, [base, amount]);
  return val;
}

// ─── Small primitives ──────────────────────────────────────────────────────
function Dot({ color, size = 8, pulse = false }) {
  return (
    <span style={{
      display: 'inline-block',
      width: size, height: size,
      borderRadius: '50%',
      background: color,
      boxShadow: pulse ? `0 0 0 0 ${color}` : 'none',
      animation: pulse ? 'dot-pulse 1.6s ease-out infinite' : undefined,
      flexShrink: 0,
    }} />
  );
}

function Mono({ children, size, color, weight = 500, style }) {
  return (
    <span style={{
      fontFamily: T.fontMono, fontSize: size,
      color: color || T.textPrimary, fontWeight: weight,
      fontVariantNumeric: 'tabular-nums', letterSpacing: -0.2,
      ...style,
    }}>{children}</span>
  );
}

function Label({ children, color = T.textMuted }) {
  return (
    <span style={{
      fontSize: 10, fontWeight: 600, letterSpacing: 1.2,
      textTransform: 'uppercase', color,
    }}>{children}</span>
  );
}

// Simple ticking clock
function useClock() {
  const [d, setD] = React.useState(new Date());
  React.useEffect(() => {
    const id = setInterval(() => setD(new Date()), 1000);
    return () => clearInterval(id);
  }, []);
  return d;
}

// Format time as HH:MM given scenario hour
function fmtHour(h) {
  const hh = Math.floor(h);
  const mm = Math.floor((h - hh) * 60);
  return `${String(hh).padStart(2, '0')}:${String(mm).padStart(2, '0')}`;
}

// Icons — minimal line glyphs inline
const Icons = {
  sun: (s=16, c='currentColor') => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.6" strokeLinecap="round">
      <circle cx="12" cy="12" r="4.2"/><path d="M12 2v2M12 20v2M2 12h2M20 12h2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4"/>
    </svg>
  ),
  bolt: (s=16, c='currentColor') => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.6" strokeLinejoin="round">
      <path d="M13 2L4 14h7l-1 8 9-12h-7l1-8z"/>
    </svg>
  ),
  battery: (s=16, c='currentColor') => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.6">
      <rect x="3" y="7" width="16" height="10" rx="2"/><path d="M21 10v4" strokeLinecap="round"/>
    </svg>
  ),
  home: (s=16, c='currentColor') => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.6" strokeLinejoin="round">
      <path d="M3 11l9-7 9 7v9a1 1 0 01-1 1h-5v-7h-6v7H4a1 1 0 01-1-1v-9z"/>
    </svg>
  ),
  grid: (s=16, c='currentColor') => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.6" strokeLinecap="round">
      <path d="M5 3l-2 18M19 3l2 18M8 3l-1 18M16 3l1 18M3 9h18M3 15h18"/>
    </svg>
  ),
  car: (s=16, c='currentColor') => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.6" strokeLinejoin="round">
      <path d="M3 14l2-6a2 2 0 012-1.5h10A2 2 0 0119 8l2 6v4a1 1 0 01-1 1h-1a1 1 0 01-1-1v-1H6v1a1 1 0 01-1 1H4a1 1 0 01-1-1v-4z"/>
      <circle cx="7.5" cy="14.5" r="1.2" fill={c}/><circle cx="16.5" cy="14.5" r="1.2" fill={c}/>
    </svg>
  ),
  leaf: (s=16, c='currentColor') => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.6" strokeLinejoin="round">
      <path d="M5 19c0-8 6-14 14-14 0 8-6 14-14 14zM5 19c3-3 6-5 10-7"/>
    </svg>
  ),
  cloud: (s=16, c='currentColor') => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.6" strokeLinejoin="round">
      <path d="M7 18h11a3 3 0 000-6 5 5 0 00-9.8-1A4 4 0 007 18z"/>
    </svg>
  ),
  arrow: (s=12, c='currentColor', dir='down') => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round"
         style={{transform: {down:'rotate(0)', up:'rotate(180deg)', left:'rotate(90deg)', right:'rotate(-90deg)'}[dir]}}>
      <path d="M12 5v14M6 13l6 6 6-6"/>
    </svg>
  ),
  dish: (s=16, c='currentColor') => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.6">
      <rect x="4" y="3" width="16" height="18" rx="2"/><path d="M4 8h16M8 12h1M8 15h1M8 18h1"/>
    </svg>
  ),
  dryer: (s=16, c='currentColor') => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke={c} strokeWidth="1.6">
      <rect x="4" y="3" width="16" height="18" rx="2"/><circle cx="12" cy="13" r="5"/><circle cx="8" cy="6.5" r="0.8" fill={c}/>
    </svg>
  ),
};

// ── Gridome dome mark (simplified, from brand) ────────────────────────────
function GridomeMark({ size = 24 }) {
  return (
    <svg width={size} height={size} viewBox="0 0 32 32" fill="none">
      <path d="M4 22 Q16 2 28 22" stroke={T.textPrimary} strokeWidth="1.8" strokeLinecap="round"/>
      <path d="M8 22 Q16 10 24 22" stroke={T.textPrimary} strokeWidth="1.8" strokeLinecap="round" opacity="0.55"/>
      <circle cx="16" cy="22" r="2.6" fill={T.brandHub}/>
      <path d="M2 22 H30" stroke={T.textPrimary} strokeWidth="1.8" strokeLinecap="round"/>
    </svg>
  );
}

// ─── Helpers needed by evcc views ─────────────────────────────────────────
function cheapestWindow(curve, hours = 3) {
  let best = { start: 0, end: hours, sum: Infinity };
  for (let i = 0; i + hours <= curve.length; i++) {
    let sum = 0;
    for (let j = 0; j < hours; j++) sum += curve[i+j].price;
    if (sum < best.sum) best = { start: i, end: i + hours, sum };
  }
  return best;
}

const EV_STATE = {
  midday:    { soc: 62, target: 80, charging: false, waiting: true,  power: 0,  eta: '06:30', done: false },
  evening:   { soc: 54, target: 80, charging: false, waiting: true,  power: 0,  eta: '06:30', done: false },
  overnight: { soc: 71, target: 80, charging: true,  waiting: false, power: 11, eta: '05:20', done: false },
  morning:   { soc: 80, target: 80, charging: false, waiting: false, power: 0,  eta: null,    done: true  },
};

function foodFor(zl) {
  // Polish food translations — pick by amount
  if (zl >= 18) return { emoji: '🍩', text: `= ${Math.floor(zl/4.5)} pączków` };
  if (zl >= 10) return { emoji: '🥟', text: `= ${Math.floor(zl/2.2)} pierogów` };
  if (zl >= 5)  return { emoji: '🥐', text: `= ${Math.floor(zl/3.5)} croissantów` };
  return { emoji: '☕', text: `= ${Math.floor(zl/1.6)} kaw` };
}

// Density-aware bar params: adapts gap, radius for any slot count.
function barDensity(count) {
  if (count <= 24) return { gap: 3, radius: 3 };
  if (count <= 48) return { gap: 2, radius: 2 };
  if (count <= 96) return { gap: 1, radius: 1.5 };
  return { gap: 0, radius: 0 };
}

// Find the NOW slot index for any granularity.
function nowSlotIndex(nowHour, totalSlots, startHour) {
  const slotsPerDay = totalSlots <= 48 ? totalSlots : totalSlots / 2;
  const slotDuration = 24 / slotsPerDay;
  const elapsed = ((nowHour - (startHour || 0)) % 24 + 24) % 24;
  return Math.floor(elapsed / slotDuration);
}

Object.assign(window, {
  T, TIER_COLOR, TIER_TINT, TIER_LABEL_PL,
  SCENARIOS, buildPriceCurve, cheapestWindow, EV_STATE, foodFor,
  useLiveJitter, useClock, fmtHour,
  Dot, Mono, Label, Icons, GridomeMark,
  barDensity, nowSlotIndex,
});
