// TelemetryMetricsPanel.jsx — sectioned telemetry metrics display component.
// Renders microclimate, irrigation, pollination KPI cards and actuator status from a TelemetryEvent sample.
// Each section is hidden when its corresponding sub-object is null / undefined,
// except the actuators section which always renders and shows "—" when sample.actuators is null.
//
// Props:
//   sample    {object}  — TelemetryEvent-shaped object with microclimate / irrigation /
//                         pollination / actuators sub-objects.  Component returns null when sample is null.
//   flashKey  {*}       — optional value; when it changes the kpi--flash animation replays.
//                         Pass lastSampleTs or a tick counter for automatic pulse-on-update.
//   className {string}  — optional extra CSS class appended to the root wrapper div.
//
// Section visibility rules:
//   • microclimate section → rendered only when sample.microclimate is not null / undefined
//   • irrigation  section  → rendered only when sample.irrigation  is not null / undefined
//   • pollination section  → rendered only when sample.pollination is not null / undefined
//   • actuators   section  → always rendered; hive_gate shows "—" when sample.actuators is null
//
// Dependencies (expected on window):
//   React              — globally available via Babel transform
//   Keeper.i18n        — optional; falls back to Russian strings when absent
//   ActuatorStatusBar  — optional; renders hive gate badge (window.ActuatorStatusBar)

// ── Module-level constants (defined outside component to avoid recreation on every render) ─────

// KPI anomaly thresholds matching the simulator screen thresholds.
var _TMP_THRESHOLDS = {
  temperature_c:          { warn: [32, 35],   critical: [35, Infinity]  },
  humidity_pct:           { warn: [85, 95],   critical: [95, Infinity]  },
  co2_ppm:                { warn: [900, 1200], critical: [1200, Infinity] },
  substrate_moisture_pct: { warn: [0, 30],    critical: [0, 15]         },
  substrate_ec:           { warn: [3.5, 5],   critical: [5, Infinity]   },
  drain_ec:               { warn: [4, 5.5],   critical: [5.5, Infinity] },
};

// Microclimate metric definitions: temperature, humidity, CO₂, insolation.
var _MC_METRICS = [
  { field: "temperature_c",  labelKey: "sample.metrics.temperature", labelFallback: "Температура",        unit: "°C",    unitKey: null,                       icon: "ri-temp-hot-line",      color: "#FF7A00", tipKey: "sample.tips.temperature", tipFallback: "Температура воздуха в теплице"              },
  { field: "humidity_pct",   labelKey: "sample.metrics.humidity",    labelFallback: "Влажность",           unit: "%",     unitKey: null,                       icon: "ri-drop-line",          color: "#007BFB", tipKey: "sample.tips.humidity",    tipFallback: "Относительная влажность воздуха"            },
  { field: "co2_ppm",        labelKey: "sample.metrics.co2",         labelFallback: "CO₂",                 unit: "ppm",   unitKey: null,                       icon: "ri-bubble-chart-line",  color: "#7FB539", tipKey: "sample.tips.co2",         tipFallback: "Концентрация углекислого газа"              },
  { field: "insolation_lux", labelKey: "sample.metrics.insolation",  labelFallback: "Освещённость",        unit: "лк",    unitKey: "sample.units.lux",         icon: "ri-sun-line",           color: "#E8B84A", tipKey: "sample.tips.insolation",  tipFallback: "Уровень освещённости (люкс)"                },
];

// Irrigation metric definitions: soil moisture, drip flow, substrate EC, feed EC, drain EC.
var _IRR_METRICS = [
  { field: "substrate_moisture_pct", labelKey: "sample.metrics.substrateMoisture", labelFallback: "Влажность субстрата",          unit: "%",     unitKey: null,                              icon: "ri-drop-line",          color: "#26972B", tipKey: "sample.tips.substrateMoisture", tipFallback: "Содержание влаги в субстрате"                        },
  { field: "drip_flow_lh",           labelKey: "sample.metrics.irrigationFlow",    labelFallback: "Расход полива",                 unit: "л/ч",   unitKey: "sample.units.litersPerHour",      icon: "ri-water-flash-line",   color: "#007BFB", tipKey: "sample.tips.irrigationFlow",    tipFallback: "Расход капельного полива"                            },
  { field: "substrate_ec",           labelKey: "sample.metrics.substrateEc",       labelFallback: "EC субстрата",                  unit: "mS/cm", unitKey: null,                              icon: "ri-flask-line",         color: "#FFB300", tipKey: "sample.tips.substrateEc",       tipFallback: "Электропроводность субстрата"                        },
  { field: "feed_ec",                labelKey: "sample.metrics.feedEc",            labelFallback: "EC раствора",                   unit: "mS/cm", unitKey: null,                              icon: "ri-test-tube-line",     color: "#7FB539", tipKey: "sample.tips.feedEc",            tipFallback: "Электропроводность питательного раствора"            },
  { field: "drain_ec",               labelKey: "sample.metrics.drainEc",           labelFallback: "EC дренажа",                    unit: "mS/cm", unitKey: null,                              icon: "ri-flask-line",         color: "#FF7A00", tipKey: "sample.tips.drainEc",           tipFallback: "Электропроводность дренажа"                          },
];

// Pollination metric definitions: departures, returns, activity index.
// noSeverity: true — no threshold colouring; raw counts / index displayed as-is.
var _POL_METRICS = [
  { field: "departures",     labelKey: "sample.metrics.departures",    labelFallback: "Вылеты",             unit: "",      unitKey: null, icon: "ri-flight-takeoff-line", color: "#7FB539", tipKey: null, noSeverity: true },
  { field: "returns",        labelKey: "sample.metrics.returns",       labelFallback: "Возвраты",            unit: "",      unitKey: null, icon: "ri-flight-land-line",    color: "#26972B", tipKey: null, noSeverity: true },
  { field: "activity_index", labelKey: "sample.metrics.activityIndex", labelFallback: "Индекс активности",  unit: "",      unitKey: null, icon: "ri-pie-chart-line",      color: "#E8B84A", tipKey: null, noSeverity: true },
];

// ── Module-level helpers ─────────────────────────────────────────────────────────────────────────
// These functions only read window.Keeper.i18n globals and module-level constants.
// Keeping them outside the component avoids re-creating them on every render.

// i18n helper — resolves a translation key via Keeper.i18n or falls back to the provided string.
function _tr(key, fallback, params) {
  var i18n = window.Keeper && window.Keeper.i18n ? window.Keeper.i18n : null;
  if (i18n && typeof i18n.t === "function") return i18n.t(key, params, { fallback: fallback });
  return fallback;
}

// Locale resolver — returns the active locale string (defaults to "ru").
function _locale() {
  return (window.Keeper && window.Keeper.i18n && typeof window.Keeper.i18n.getLocale === "function")
    ? window.Keeper.i18n.getLocale() || "ru"
    : "ru";
}

// Number formatter — integers: 0 decimal places; floats: 1 decimal place.
function _fmt(v) {
  if (v == null) return "—";
  if (typeof v === "number") {
    var decimals = Number.isInteger(v) ? 0 : 1;
    return new Intl.NumberFormat(_locale(), {
      minimumFractionDigits: decimals,
      maximumFractionDigits: decimals,
    }).format(v);
  }
  return String(v);
}

// Severity classifier — returns "" | "kpi--ok" | "kpi--warn" | "kpi--critical".
// Returns "" when value is null / non-numeric, or when no threshold is defined for the field.
// Returns "kpi--ok" when a threshold IS defined and the value falls within the normal range.
function _severity(field, value) {
  if (value == null || typeof value !== "number") return "";
  var t = _TMP_THRESHOLDS[field];
  if (!t) return "";
  if (t.critical && value >= t.critical[0] && value <= t.critical[1]) return "kpi--critical";
  if (t.warn    && value >= t.warn[0]    && value <= t.warn[1])    return "kpi--warn";
  return "kpi--ok";
}

// Timestamp formatter — converts an ISO string to a short locale-aware HH:MM:SS string.
function _fmtTs(iso) {
  if (!iso) return null;
  try {
    return new Intl.DateTimeFormat(_locale(), {
      hour:   "2-digit",
      minute: "2-digit",
      second: "2-digit",
    }).format(new Date(iso));
  } catch (_) {
    return iso;
  }
}

// KPI card renderer — pure given metric definitions + group data + grid class + flashKey.
// flashKey is passed explicitly so this stays module-level and does not close over component props.
// When flashKey changes, each card gets a new React key which re-triggers the kpi--flash animation.
function _renderCards(metrics, groupData, gridCls, flashKey) {
  var cards = metrics.map(function(m) {
    var val      = groupData ? groupData[m.field] : null;
    var sev      = m.noSeverity ? "" : _severity(m.field, val);
    var unit     = m.unitKey ? _tr(m.unitKey, m.unit) : m.unit;
    var label    = _tr(m.labelKey, m.labelFallback);
    var tip      = m.tipKey ? _tr(m.tipKey, m.tipFallback) : m.tipFallback;
    var flashCls = flashKey != null ? " kpi--flash" : "";
    var cardKey  = m.field + (flashKey != null ? "-" + String(flashKey) : "");

    return (
      <div
        key={cardKey}
        className={"kpi" + flashCls + (sev ? " " + sev : "")}
        title={tip || undefined}
        role="group"
        aria-label={label + (unit ? " (" + unit + ")" : "")}
      >
        <div className="kpi-lbl">
          {label}
          <i className={m.icon} style={{ color: m.color }} aria-hidden="true"></i>
        </div>
        <div className={"kpi-val" + (sev ? " " + sev : "")}>
          {_fmt(val)}
          {unit ? <span className="kpi-unit">{unit}</span> : null}
        </div>
      </div>
    );
  });

  return (
    <div className={"simulator-kpi-grid " + gridCls}>
      {cards}
    </div>
  );
}

// ── Component ────────────────────────────────────────────────────────────────────────────────────

/**
 * Sectioned telemetry KPI panel rendered from a single TelemetryEvent sample.
 * Shows microclimate, irrigation, pollination and actuator sub-sections; each section
 * is hidden when its corresponding sub-object is absent in the sample.
 * @param {{ sample: object|null, flashKey?: *, className?: string }} props
 */
function TelemetryMetricsPanel({ sample, flashKey, className }) {
  // Stable per-instance id suffix for aria-labelledby / id pairs.
  // Avoids duplicate IDs when the component is mounted more than once on a page.
  var uid = React.useMemo(function() {
    return Math.random().toString(36).slice(2, 7);
  }, []);

  // ── Guard: nothing to render until a sample arrives ──────────────────
  if (!sample) return null;

  var mc  = sample.microclimate != null ? sample.microclimate : null;
  var irr = sample.irrigation   != null ? sample.irrigation   : null;
  var pol = sample.pollination  != null ? sample.pollination  : null;
  var act = sample.actuators    != null ? sample.actuators    : null;

  var mcId  = "tmp-microclimate-" + uid;
  var irrId = "tmp-irrigation-"   + uid;
  var polId = "tmp-pollination-"  + uid;
  var actId = "tmp-actuators-"    + uid;

  var rootCls = "telemetry-metrics-panel" + (className ? " " + className : "");

  return (
    <div className={rootCls}>

      {/* ── Microclimate section: temperature, humidity, CO₂, insolation ── */}
      {mc != null && (
        <section aria-labelledby={mcId}>
          <h4 className="simulator-section-label" id={mcId}>
            <i className="ri-cloud-line" aria-hidden="true"></i>
            {_tr("sample.sections.microclimate", "Микроклимат")}
          </h4>
          {_renderCards(_MC_METRICS, mc, "simulator-kpi-grid--four", flashKey)}
        </section>
      )}

      {/* ── Irrigation section: soil moisture, drip flow, EC values ──── */}
      {irr != null && (
        <section aria-labelledby={irrId}>
          <h4 className="simulator-section-label" id={irrId}>
            <i className="ri-water-flash-line" aria-hidden="true"></i>
            {_tr("sample.sections.irrigation", "Полив и питание")}
          </h4>
          {_renderCards(_IRR_METRICS, irr, "simulator-kpi-grid--three", flashKey)}
        </section>
      )}

      {/* ── Pollination section: departures, returns, activity index ──── */}
      {pol != null && (
        <section aria-labelledby={polId}>
          <h4 className="simulator-section-label" id={polId}>
            <i className="ri-bug-2-line" aria-hidden="true"></i>
            {_tr("sample.sections.pollination", "Опыление")}
          </h4>
          {_renderCards(_POL_METRICS, pol, "simulator-kpi-grid--three", flashKey)}
        </section>
      )}

      {/* ── Actuators section: hive gate state — always shown; "—" when actuators is null ── */}
      {(() => {
        var ActBar    = window.ActuatorStatusBar;
        var gateState = act != null ? act.hive_gate : null;
        return (
          <section aria-labelledby={actId}>
            <h4 className="simulator-section-label" id={actId}>
              <i className="ri-settings-2-line" aria-hidden="true"></i>
              {_tr("sample.sections.actuators", "Актуаторы")}
            </h4>
            <div className="simulator-kpi-grid simulator-kpi-grid--one">
              <div className="kpi" role="group" aria-label={_tr("sample.metrics.hiveGate", "Шлюз улья")}>
                <div className="kpi-lbl">
                  {_tr("sample.metrics.hiveGate", "Шлюз улья")}
                  <i className="ri-door-open-line" style={{ color: "#9AA5B3" }} aria-hidden="true"></i>
                </div>
                <div className="kpi-val">
                  {gateState != null && ActBar
                    ? <ActBar state={gateState} />
                    : <span className="kpi-no-data" aria-label={_tr("sample.actuators.noData", "Нет данных об актуаторах")}>
                        <i className="ri-question-mark" aria-hidden="true"></i>
                        {_tr("sample.actuators.noData", "нет данных")}
                      </span>}
                </div>
              </div>
            </div>
          </section>
        );
      })()}

      {/* ── Freshness timestamp ── shows the time the last sample was produced ── */}
      {sample.timestamp && (
        <p className="telemetry-metrics-panel__freshness" aria-live="polite">
          <i className="ri-time-line" aria-hidden="true"></i>
          {_tr("sample.freshness", "Обновлено")}
          {" · "}
          <time dateTime={sample.timestamp}>{_fmtTs(sample.timestamp)}</time>
        </p>
      )}

    </div>
  );
}

window.TelemetryMetricsPanel = TelemetryMetricsPanel;
