/* global React, WeatherData, fmtNum, Modal */
const { useState: _useStS } = React;

// =========================================================
// Hero widget — meteostanice header. Renders locality, current
// temperature with weather icon on the same row, and a meta strip
// (min/max, humidity, wind, precip, pressure). Optional webcam
// thumbnail in a second column when config.showWebcam is on.
// =========================================================

// Feels-like as on the station page (/ms, data.js): NWS / Environment Canada —
// wind chill up to 10 °C with wind over 4.8 km/h, heat index from 26.7 °C at
// RH ≥ 40 %, otherwise the air temperature.
function stFeelsLike(t, rh, windMs) {
  if (t == null || isNaN(t)) return null;
  const kmh = windMs != null && !isNaN(windMs) ? windMs * 3.6 : 0;
  if (t <= 10 && kmh > 4.8) {
    const p = Math.pow(kmh, 0.16);
    return 13.12 + 0.6215 * t - 11.37 * p + 0.3965 * t * p;
  }
  if (t >= 26.7 && rh != null && !isNaN(rh) && rh >= 40) {
    const f = t * 9 / 5 + 32;
    let hi = 0.5 * (f + 61 + (f - 68) * 1.2 + rh * 0.094);
    if (hi >= 80) {
      hi = -42.379 + 2.04901523 * f + 10.14333127 * rh - 0.22475541 * f * rh
        - 0.00683783 * f * f - 0.05481717 * rh * rh + 0.00122874 * f * f * rh
        + 0.00085282 * f * rh * rh - 0.00000199 * f * f * rh * rh;
      if (rh > 85 && f <= 87) hi += ((rh - 85) / 10) * ((87 - f) / 5);
    }
    return (hi - 32) * 5 / 9;
  }
  return t;
}
// Temperature scale shared with the station page: cool blue → neutral grey
// around 10 °C → warm orange/red (two arms, no rainbow).
const ST_TEMP_STOPS = {
  dark:  [[-20, '#6366f1'], [-10, '#3b82f6'], [0, '#7dd3fc'], [10, '#cbd5e1'], [20, '#fdba74'], [28, '#f97316'], [36, '#ef4444']],
  light: [[-20, '#4338ca'], [-10, '#1d4ed8'], [0, '#0284c7'], [10, '#64748b'], [20, '#ea580c'], [28, '#c2410c'], [36, '#b91c1c']],
};
// Colour for a temperature on that scale — same interpolation as the station
// page (obloha.js tempColor); used for „Akcent podle teploty“.
window.tempColor = function tempColor(t, dark = true) {
  const stops = ST_TEMP_STOPS[dark ? 'dark' : 'light'];
  if (t == null || isNaN(t)) return stops[3][1];
  if (t <= stops[0][0]) return stops[0][1];
  const hex = (c) => [1, 3, 5].map((i) => parseInt(c.slice(i, i + 2), 16));
  for (let i = 1; i < stops.length; i++) {
    if (t <= stops[i][0]) {
      const [t0, c0] = stops[i - 1], [t1, c1] = stops[i];
      const k = (t - t0) / (t1 - t0);
      const a = hex(c0), b = hex(c1);
      return 'rgb(' + a.map((v, j) => Math.round(v + (b[j] - v) * k)).join(',') + ')';
    }
  }
  return stops[stops.length - 1][1];
};
// 24 h range bar: the full scale −20…36 °C faint, the measured min–max range
// solid, a dot for now and a tick at 0 °C. Same element as on /ms.
// Kdy byla teplota naposledy na dané hodnotě (min / max za 24 h).
function stTimeOf(station, v) {
  const ms = station?.measurements || [];
  for (let i = ms.length - 1; i >= 0; i--) if (ms[i].temp === v && ms[i].time) return ms[i].time;
  return null;
}
function stPointTime(d) {
  const t = new Date(d), today = new Date();
  const hm = t.toLocaleTimeString('cs-CZ', { hour: '2-digit', minute: '2-digit' });   // jako stránka stanice
  const day = (x) => new Date(x.getFullYear(), x.getMonth(), x.getDate()).getTime();
  const diff = Math.round((day(today) - day(t)) / 86400e3);
  return diff === 0 ? hm : diff === 1 ? `včera ${hm}` : `${t.getDate()}. ${t.getMonth() + 1}. ${hm}`;
}
function StTempRange({ min, max, now, minAt, maxAt }) {
  if (min == null || max == null || now == null) return null;
  const dark = document.documentElement.getAttribute('data-theme') !== 'light';
  const lo = -20, hi = 36;
  const pos = (v) => Math.max(0, Math.min(100, ((v - lo) / (hi - lo)) * 100));
  const grad = ST_TEMP_STOPS[dark ? 'dark' : 'light'].map(([t, c]) => `${c} ${pos(t)}%`).join(', ');
  const COL = (v) => (window.tempColor ? window.tempColor(v, dark) : 'var(--accent)');
  const F = (v) => fmtNum(v, 1), T = window.fmtTipTime;
  return (
    <div className="trange" tabIndex={0} aria-label={`Teplota za 24 h: nejníž ${F(min)} °C, teď ${F(now)} °C, nejvýš ${F(max)} °C`}>
      <div className="trange-tip" role="tooltip">
        <div className="tt-h">Teplota za posledních 24 h</div>
        <div className="tt-row"><i style={{ background: COL(min) }}></i><span>nejníž</span><b>{F(min)} °C</b><small>{minAt ? T(minAt) : ''}</small></div>
        <div className="tt-row"><i style={{ background: COL(now) }}></i><span>teď</span><b>{F(now)} °C</b><small></small></div>
        <div className="tt-row"><i style={{ background: COL(max) }}></i><span>nejvýš</span><b>{F(max)} °C</b><small>{maxAt ? T(maxAt) : ''}</small></div>
        <div className="tt-foot">Pruh je teplotní škála od −20 do +36 °C. Barevný úsek = rozpětí za 24 h, kolečko = teď, svislá čárka = 0 °C.</div>
      </div>

      <span className="trange-val">{fmtNum(min, 1)}°</span>
      <div className="trange-track">
        <div className="trange-scale" style={{ background: `linear-gradient(90deg, ${grad})` }}/>
        <div className="trange-span" style={{ background: `linear-gradient(90deg, ${grad})`,
             clipPath: `inset(0 ${100 - Math.max(pos(max), pos(min) + 1.5)}% 0 ${pos(min)}% round 999px)` }}/>
        <div className="trange-now" style={{ left: pos(now) + '%' }}/>
        <div className="trange-zero" style={{ left: pos(0) + '%' }}/>
      </div>
      <span className="trange-val">{fmtNum(max, 1)}°</span>
    </div>
  );
}
// Měsíc v řádku stavu — jen když je Slunce pod obzorem, stejné názvy fází
// jako hlavní panel stránky stanice (mstest obloha.js moonPhase).
function stMoon() {
  const A = window.Astronomy;
  if (!A) return null;
  const now = new Date();
  const c = A.getCoords(window.StationData?.siteId);
  if (A.sunAltitude(now, c.lat, c.lon) >= 0) return null;
  const phase = A.moonPhase(now);
  const name = phase < 0.03 || phase > 0.97 ? 'nov'
    : phase < 0.22 ? 'dorůstající srpek'
    : phase < 0.28 ? 'první čtvrť'
    : phase < 0.47 ? 'dorůstá'
    : phase < 0.53 ? 'úplněk'
    : phase < 0.72 ? 'couvá'
    : phase < 0.78 ? 'poslední čtvrť' : 'couvající srpek';
  return { phase, lit: Math.round(A.illumFraction(phase) * 100), name };
}
// Měsíc ve fázi (terminátor jako elipsa, dorůstající svítí vpravo) — stejná
// kresba jako MoonIcon na stránce stanice (sky.jsx), barvy z --moon-lit/-dark.
function StMoonIcon({ phase, size = 16 }) {
  const r = 9, c = 12;
  const k = Math.cos(2 * Math.PI * phase);
  const waxing = phase < 0.5;
  const lit = `M${c} ${c - r} A${r} ${r} 0 0 ${waxing ? 1 : 0} ${c} ${c + r} A${Math.abs(k) * r} ${r} 0 0 ${(k > 0) === waxing ? 0 : 1} ${c} ${c - r} Z`;
  return (
    <svg width={size} height={size} viewBox="0 0 24 24" aria-hidden="true">
      <circle cx={c} cy={c} r={r} fill="var(--moon-dark)" stroke="var(--muted)" strokeWidth="0.8" />
      <path d={lit} fill="var(--moon-lit)" />
    </svg>
  );
}

// Temperature 24 h ago (nearest record within ±10 min) for the "vs yesterday" line.
function stTemp24hAgo(station) {
  const recs = station?.raw || [];
  if (!recs.length || !window.StationData?.parseDatum) return null;
  const last = window.StationData.parseDatum(recs[recs.length - 1].Datum).getTime();
  const target = last - 24 * 3600e3;
  let best = null, bd = Infinity;
  for (const r of recs) {
    if (r.TeplotaVnejsi == null || isNaN(r.TeplotaVnejsi)) continue;
    const d = Math.abs(window.StationData.parseDatum(r.Datum).getTime() - target);
    if (d < bd) { bd = d; best = r.TeplotaVnejsi; }
  }
  return bd <= 10 * 60e3 ? best : null;
}

window.StationWidget = function StationWidget({ station, stationStatus, hourly, nowWx, showStation, config = {} }) {
  const [modal, setModal] = _useStS(null);
  // Webcam is its own widget now — station never renders it by default.
  // (config.showWebcam can still force-enable here for users who liked the
  // old combined hero layout, but the dedicated WebcamWidget is preferred.)
  const showWebcam = config.showWebcam === true;
  const showMeta = config.showMeta !== false;
  // Show ±delta vs forecast next to each station value (temp, hum, wind, pres).
  // Off by default — for users who care about model accuracy at a glance.
  const showCompare = config.showCompare === true;
  // Drop decimal places everywhere in the hero — user-visible config switch
  // for those who want round whole-number readouts ("22°C" not "21.6°C").
  const hideDecimals = config.hideDecimals === true;
  // Feels-like + "vs yesterday" line and the 24 h range bar — like the
  // station page hero. On by default, both switchable in the gear popover.
  const showFeels = config.showFeels !== false;
  const showRange = config.showRange !== false;
  const moon = config.showMoon !== false ? stMoon() : null;
  const dT = hideDecimals ? 0 : 1;       // temp decimals
  const dW = hideDecimals ? 0 : 1;       // wind decimals
  const dP = 0;                           // precip + pressure are integer-ish
  if (!hourly || !hourly.length) return <div className="muted">Načítání…</div>;
  const h0 = hourly[0];
  const s = station?.latest || null;
  // Icon + label: the shared "now" rule (WeatherData.currentWeather), so the
  // station page and this widget never disagree.
  const nowIcon = nowWx?.icon || h0.icon;
  const cond = nowWx?.cond || h0.cond;

  // Delta = station reading - forecast for current hour. Renders as a small
  // chip (+1.5 / −0.8 …) with sign-based color. `tol` defines what counts as
  // "close enough" (chip stays muted), beyond that it picks a warm/cool tint
  // matching the metric's direction. Returns null when either side is missing
  // or when station fell back to forecast (delta would always be 0).
  const Delta = ({ stationVal, forecastVal, decimals = 0, tol = 0, transform }) => {
    if (!showCompare || !s) return null;
    if (stationVal == null || forecastVal == null) return null;
    const a = transform ? transform(stationVal) : stationVal;
    const b = transform ? transform(forecastVal) : forecastVal;
    const d = a - b;
    if (isNaN(d)) return null;
    const sign = d > 0 ? 'pos' : d < 0 ? 'neg' : 'zero';
    const big = Math.abs(d) > tol;
    const arrow = d > 0 ? '▲' : d < 0 ? '▼' : '·';
    const txt = (d > 0 ? '+' : d < 0 ? '−' : '±') + window.czNum(Math.abs(d), decimals);
    return (
      <span className={`hm-delta ${sign} ${big ? 'big' : 'near'}`}
            title={`Předpověď: ${fmtNum(b, decimals)}`}>
        <span className="hm-delta-arrow">{arrow}</span>{txt}
      </span>
    );
  };

  // Prefer station readings over forecast when present
  const view = s ? {
    temp:     s.TeplotaVnejsi  ?? h0.temp,
    humidity: s.VlhkostVnejsi  ?? h0.humidity,
    wind:     s.Vitr           ?? h0.wind,
    gust:     s.VitrNarazy     ?? h0.gust,
    windDir:  s.VitrSmer != null && window.windDir ? window.windDir(s.VitrSmer) : h0.windDir,
    pressure: s.TlakRel        ?? h0.pressure,
    precipDay: s.SrazkyDen     ?? null,
  } : {
    temp: h0.temp, humidity: h0.humidity, wind: h0.wind,
    gust: h0.gust, windDir: h0.windDir, pressure: h0.pressure,
    precipDay: null,
  };

  const dayMM = station?.dayMinMax?.('TeplotaVnejsi') || null;
  const locality = station?.locality || 'Meteostanice';
  // Snapshot from new Webkamera shape (IdWebcam → server snap, UrlWebcam → static).
  // Legacy string fallback: pre-shape API/config values where webcam was just a URL.
  const webcamSnap = station?.webcamSnapshot || null;
  const legacyUrl = !webcamSnap ? (station?.config?.webcam || window.SiteConfig?.webcam || null) : null;
  const webcamThumb = webcamSnap?.url
    || (legacyUrl ? legacyUrl + (legacyUrl.includes('?') ? '&' : '?') + '_=' + Math.floor(Date.now() / 60000) : null);
  const webcamDetail = webcamSnap?.detailUrl || webcamSnap?.url
    || (legacyUrl ? legacyUrl + (legacyUrl.includes('?') ? '&' : '?') + '_=' + Math.floor(Date.now() / 60000) : null);
  const isOwnStation = !!station?.webcam?.idWebcam;
  const webcamTaken = webcamSnap?.snimek_cas ? new Date(webcamSnap.snimek_cas * 1000) : null;
  // Value of a station field about `ms` ago (nearest record within ±15 min).
  const valueAgo = (key, ms) => {
    const recs = station?.raw || [];
    if (!recs.length || !window.StationData?.parseDatum) return null;
    const target = window.StationData.parseDatum(recs[recs.length - 1].Datum).getTime() - ms;
    let best = null, bd = Infinity;
    for (const r of recs) {
      if (r[key] == null || isNaN(r[key])) continue;
      const d = Math.abs(window.StationData.parseDatum(r.Datum).getTime() - target);
      if (d < bd) { bd = d; best = r[key]; }
    }
    return bd <= 15 * 60e3 ? best : null;
  };
  const wU = window.Units ? window.Units.windLabel() : 'm/s';
  const wC = (v) => (window.Units ? window.Units.wind(v) : v);
  const calm = view.wind != null && view.wind < 0.3;
  const p3 = s?.TlakRel != null ? valueAgo('TlakRel', 3 * 3600e3) : null;
  const pDelta = p3 != null ? s.TlakRel - p3 : null;
  const pArrow = pDelta == null ? null : pDelta > 0.5 ? 'arrow-up-right' : pDelta < -0.5 ? 'arrow-down-right' : 'arrow-right';
  const feels = s && s.TeplotaVnejsi != null ? stFeelsLike(s.TeplotaVnejsi, s.VlhkostVnejsi, s.Vitr) : null;
  const t24 = s && s.TeplotaVnejsi != null ? stTemp24hAgo(station) : null;
  const dY = t24 != null ? s.TeplotaVnejsi - t24 : null;
  const dTxt = dY == null ? null : Math.abs(dY) < 0.5 ? 'stejně jako včera'
    : `o ${window.czNum(Math.abs(dY), 1)} °C ${dY > 0 ? 'tepleji' : 'chladněji'} než včera`;
  const measured = station?.timestamp ? window.hhmm(station.timestamp) : null;
  const rows = [
    { k: 'hum', icon: 'droplet-half', label: 'Vlhkost', val: view.humidity != null ? `${fmtNum(view.humidity)} %` : null },
    { k: 'dew', icon: 'moisture', label: 'Rosný bod', val: s?.RosnyBod != null ? `${fmtNum(s.RosnyBod, 1)} °C` : null },
    { k: 'pres', icon: 'arrows-collapse', label: 'Tlak', val: view.pressure != null ? `${fmtNum(view.pressure, 0)} hPa` : null,
      extra: pArrow && <i className={`bi bi-${pArrow} now-trend`} title={`Za 3 h ${pDelta > 0 ? '+' : pDelta < 0 ? '−' : '±'}${window.czNum(Math.abs(pDelta), 1)} hPa`}></i> },
    { k: 'wind', icon: 'wind', label: 'Vítr', val: view.wind == null ? null : calm ? 'bezvětří'
      : `${fmtNum(wC(view.wind), dW)} ${wU} ${view.windDir || ''}`.trim(),
      sub: !calm && view.gust != null ? `nárazy ${fmtNum(wC(view.gust), dW)}` : null },
    { k: 'rain', icon: 'cloud-rain', label: 'Srážky dnes', val: view.precipDay != null ? `${fmtNum(view.precipDay, 1)} mm` : null },
  ].filter(r => r.val != null);
  // Wind (with gusts and direction) gets a row of its own at the end; with an
  // odd number of the others the last of them spans the row too (no empty
  // cell). Only in narrow tiles (CSS .now-wide) — wide ones keep one line.
  const wind = rows.find(r => r.k === 'wind');
  const others = rows.filter(r => r.k !== 'wind');
  if (others.length % 2 === 1 && wind) others[others.length - 1] = { ...others[others.length - 1], wide: true };
  const gridRows = wind ? [...others, { ...wind, wide: true }] : others;
  const variant = document.documentElement.getAttribute('data-variant');

  return (
    <div className="now">
      <div className="now-cond">
        <span>{cond}</span>
        {measured && <span className="now-age">· {s ? `stanice ${measured}` : 'předpověď'}</span>}
        {moon && (
          <span className="now-moon" title={`Měsíc: ${moon.name}, osvětleno ${moon.lit} %`}>
            <StMoonIcon phase={moon.phase} />
            {moon.name} · {moon.lit} %
          </span>
        )}
      </div>
      <div className="now-main">
        <div className="now-temp" title={s ? 'Naměřeno stanicí' : 'Předpověď'}>
          <span className="now-num">{fmtNum(view.temp, dT)}</span>
          <span className="now-unit">°C</span>
        </div>
        <img className="now-icon" src={WeatherData.iconUrl(nowIcon)} alt={cond} title={cond} />
      </div>
      {showFeels && (feels != null || dTxt) && (
        <div className="now-sub">
          {feels != null && <span>pocitově <b>{fmtNum(feels, dT)} °C</b></span>}
          {feels != null && dTxt && <span className="sep">·</span>}
          {dTxt && <span title="Proti stejnému času před 24 hodinami">{dTxt}</span>}
        </div>
      )}
      {showRange && dayMM?.min != null && <StTempRange min={dayMM.min} max={dayMM.max} now={view.temp}
                                                        minAt={stTimeOf(station, dayMM.min)} maxAt={stTimeOf(station, dayMM.max)} />}
      {showCompare && s && h0.temp != null && (
        <div className="now-fc">předpověď na tuto hodinu <b>{fmtNum(h0.temp, dT)} °C</b></div>
      )}
      {showMeta && rows.length > 0 && (
        <dl className="now-grid">
          {gridRows.map(r => (
            <div key={r.k} title={r.label} className={r.wide ? 'now-wide' : undefined}>
              <dt><i className={`bi bi-${r.icon}`} aria-hidden="true"></i><span className="now-lbl">{r.label}</span></dt>
              <dd>{r.val}{r.extra}{r.sub && <small>{r.sub}</small>}</dd>
            </div>
          ))}
        </dl>
      )}
      {/* jen když stanice data posílat má a teď nejdou – ne při načítání, bez klíče ani u lokality bez stanice */}
      {showStation && !station && stationStatus === 'offline' && !window.cteBezDat?.(window.StationData?.siteId) && (
        <div className="now-offline"><i className="bi bi-broadcast-pin"></i>Stanice teď neposílá data — zobrazena předpověď.</div>
      )}
    </div>
  );
};
