// screens-overview.jsx — Org overview, Sites list, Site detail

// [TASK_START:T005]
function Sparkline({ kind }) {
  if (kind === "progress") return (
    <div className="spark" style={{ background: "#F2F5F9" }}>
      <svg viewBox="0 0 100 32" preserveAspectRatio="none" style={{ width: "100%", height: "100%" }}>
        <rect x="0" y="9" width="100" height="14" rx="5" ry="5" fill="#E3EAF2" />
        <rect x="0" y="9" width="36" height="14" rx="5" ry="5" fill="#FFB300" />
        <circle cx="36" cy="16" r="3" fill="#D59000" />
      </svg>
    </div>
  );
  const colors = { honey:"#FFB300", ok:"#26972B", crit:"#E5342B" };
  const points = kind === "crit"
    ? "0,8 10,10 20,6 30,12 40,8 50,14 60,10 70,16 80,18 90,22 100,24"
    : kind === "ok"
    ? "0,18 10,20 20,16 30,14 40,18 50,12 60,14 70,10 80,12 90,8 100,6"
    : "0,22 10,18 20,20 30,14 40,16 50,10 60,12 70,8 80,10 90,6 100,4";
  return (
    <div className="spark" style={{background: kind === "crit" ? "linear-gradient(180deg,rgba(229,52,43,.08),transparent)" : kind === "ok" ? "linear-gradient(180deg,rgba(38,151,43,.08),transparent)" : "linear-gradient(180deg,rgba(255,179,0,.12),transparent)"}}>
      <svg viewBox="0 0 100 32" preserveAspectRatio="none" style={{width:"100%",height:"100%"}}>
        <polyline fill="none" stroke={colors[kind]} strokeWidth="1.5" points={points}/>
      </svg>
    </div>
  );
}
// [TASK_COMPLETE:T005]

function _toNumber(value, fallback = 0) {
  const n = Number(value);
  return Number.isFinite(n) ? n : fallback;
}

function _normalizeKind(value) {
  if (value === "critical") return "crit";
  if (value === "warning") return "warn";
  if (value === "info") return "info";
  if (value === "crit" || value === "warn" || value === "info") return value;
  return "warn";
}

function _relativeTimeLabel(value) {
  if (!value) return "—";
  if (typeof value === "string" && (value.includes("Сегодня") || value.includes("вчера"))) {
    return value;
  }
  const ts = new Date(value);
  if (Number.isNaN(ts.getTime())) return String(value);
  const deltaMs = Date.now() - ts.getTime();
  const mins = Math.floor(deltaMs / 60000);
  if (mins < 1) return "только что";
  if (mins < 60) return `${mins} мин назад`;
  const hours = Math.floor(mins / 60);
  if (hours < 24) return `${hours} ч назад`;
  const days = Math.floor(hours / 24);
  return `${days} дн назад`;
}

function _buildOverviewFallback(tenant) {
  const devices = Array.isArray(DATA?.devices) ? DATA.devices : [];
  const alerts = Array.isArray(DATA?.alerts) ? DATA.alerts : [];
  const tasks = Array.isArray(DATA?.tasks) ? DATA.tasks : [];
  const totalTasks = tasks.length;
  const doneTasks = tasks.filter((t) => t.col === "done").length;
  const openTasks = totalTasks - doneTasks;
  const taskCompletionPct = totalTasks ? Number(((doneTasks / totalTasks) * 100).toFixed(1)) : 0;
  const devicesOnline = devices.filter((d) => d.status !== "critical").length;

  return {
    kpis: {
      uptime_pct: devices.length ? Number(((devicesOnline / devices.length) * 100).toFixed(1)) : 0,
      devices_online: devicesOnline,
      devices_total: devices.length,
      hive_activity_pct: 76,
      open_alerts: alerts.filter((a) => a.kind === "crit" || a.kind === "warn").length,
      total_alerts: alerts.length,
      open_tasks: openTasks,
      total_tasks: totalTasks,
      task_completion_pct: taskCompletionPct,
      total_sites: Array.isArray(DATA?.sites) ? DATA.sites.length : tenant?.greenhouses || 0,
      total_greenhouses: tenant?.greenhouses || 0,
      total_hives: 0,
    },
    alerts,
    sites: Array.isArray(DATA?.sites) ? DATA.sites : [],
  };
}

function _normalizeOverviewPayload(payload, fallback) {
  const kpis = (payload && payload.kpis && typeof payload.kpis === "object") ? payload.kpis : {};
  const base = fallback.kpis;
  return {
    kpis: {
      uptime_pct: _toNumber(kpis.uptime_pct, base.uptime_pct),
      devices_online: _toNumber(kpis.devices_online, base.devices_online),
      devices_total: _toNumber(kpis.devices_total, base.devices_total),
      hive_activity_pct: _toNumber(kpis.hive_activity_pct, base.hive_activity_pct),
      open_alerts: _toNumber(kpis.open_alerts, base.open_alerts),
      total_alerts: _toNumber(kpis.total_alerts, base.total_alerts),
      open_tasks: _toNumber(kpis.open_tasks, base.open_tasks),
      total_tasks: _toNumber(kpis.total_tasks, base.total_tasks),
      task_completion_pct: _toNumber(kpis.task_completion_pct, base.task_completion_pct),
      total_sites: _toNumber(kpis.total_sites, base.total_sites),
      total_greenhouses: _toNumber(kpis.total_greenhouses, base.total_greenhouses),
      total_hives: _toNumber(kpis.total_hives, base.total_hives),
    },
    alerts: Array.isArray(payload?.alerts) ? payload.alerts : fallback.alerts,
    sites: Array.isArray(payload?.sites) ? payload.sites : fallback.sites,
  };
}

function Overview({ tenant, onNav, onOpenHive }) {
  const [overview, setOverview] = React.useState(() => _buildOverviewFallback(tenant));
  // [TASK_START:T010]
  function go(route) {
    if (!route) return;
    if (window.Keeper?.router?.go) {
      window.Keeper.router.go(route);
      return;
    }
    if (typeof onNav === "function") onNav(route);
  }
  // [TASK_COMPLETE:T010]

  // [TASK_START:T012]
  React.useEffect(() => {
    let cancelled = false;
    async function load() {
      const fallback = _buildOverviewFallback(tenant);
      if (!cancelled) setOverview(fallback);
      try {
        const live = await Keeper.api.overview();
        if (cancelled) return;
        setOverview(_normalizeOverviewPayload(live, fallback));
      } catch (_) {
        if (!cancelled) setOverview(fallback);
      }
    }
    load();
    return () => { cancelled = true; };
  }, [tenant?.id]);
  // [TASK_COMPLETE:T012]

  const kpis = overview.kpis;
  // [TASK_START:T004]
  const cards = [
    {
      lbl: "Устройств онлайн",
      val: String(kpis.devices_online ?? 0),
      unit: `/${kpis.devices_total ?? 0}`,
      delta: `${kpis.uptime_pct ?? 0}% аптайм`,
      deltaCls: "up",
      icon: "ri-router-line",
      spark: "honey",
      nav: "devices",
    },
    {
      lbl: "Активность ульев",
      val: String(kpis.hive_activity_pct ?? 0),
      unit: "%",
      delta: `${kpis.total_hives ?? 0} ульев`,
      deltaCls: "up",
      icon: "ri-pulse-line",
      spark: "ok",
      nav: null,
    },
    {
      lbl: "Инциденты",
      val: String(kpis.open_alerts ?? 0),
      unit: "откр.",
      delta: `всего ${kpis.total_alerts ?? 0}`,
      deltaCls: "dn",
      icon: "ri-alarm-warning-line",
      spark: "crit",
      nav: "alerts",
    },
    {
      lbl: "Открытых задач",
      val: String(kpis.open_tasks ?? 0),
      unit: `из ${kpis.total_tasks ?? 0}`,
      delta: `${kpis.task_completion_pct ?? 0}% выполнено`,
      deltaCls: "",
      icon: "ri-task-line",
      spark: "progress",
      nav: "tasks",
    },
  ];
  // [TASK_COMPLETE:T004]

  const alertsPreview = (Array.isArray(overview.alerts) ? overview.alerts : [])
    .filter((a) => !a.status || a.status === "open")
    .slice(0, 3);

  const allHives = Object.values(DATA?.hives || {}).flat();
  const hivesNeedAttention = allHives
    .filter((h) => {
      const state = String(h.state || h.status || "ok").toLowerCase();
      return state !== "ok" && state !== "green";
    })
    .slice(0, 3)
    .map((h) => {
      const state = String(h.state || h.status || "warn").toLowerCase();
      return {
        id: h.id,
        zone: h.zone_id || h.zone || "—",
        activity: h.departures_per_min ?? h.departures ?? "—",
        temp: h.temperature_c == null ? "—" : h.temperature_c,
        state: state === "crit" || state === "critical" ? "cri" : "att",
        note: state === "crit" || state === "critical" ? "Требует срочного вмешательства" : "Нестабильная активность",
      };
    });

  const dayLabels = ["Пн", "Вт", "Ср", "Чт", "Пт", "Сб", "Вс"];
  const timeWindows = ["06:00", "11:00", "18:00", "21:00"];
  const scheduleMatrix = [
    ["open", "open", "open", "empty", "open", "open", "open"],
    ["close", "close", "close", "empty", "close", "close", "close"],
    ["open", "open", "open", "empty", "open", "open", "open"],
    ["close", "close", "close", "empty", "close", "close", "close"],
  ];

  const efficiencySeries = [62, 68, 71, 74, 72, 76, 78];
  const today = new Date();
  const dateCaption = today.toLocaleDateString("ru-RU", { day: "numeric", month: "long" });

  return (
    <div className="page" data-screen-label="02 Обзор">
      {/* [TASK_START:T011] */}
      <div className="page-head">
        <div>
          <div className="page-title">Доброе утро, {DATA?.user?.name || "оператор"}</div>
          <div className="page-sub">{dateCaption} · {(kpis.total_greenhouses ?? tenant?.greenhouses ?? 0)} теплиц · {(kpis.open_alerts ?? 0)} инцидента требуют внимания</div>
        </div>
        <div className="actions">
          <button className="btn btn--secondary" onClick={() => go("reports")}><i className="ri-download-line"></i>Экспорт отчёта</button>
          <button className="btn btn--primary" onClick={() => go("hives")}><i className="ri-map-pin-line"></i>Открыть карту</button>
        </div>
      </div>
      {/* [TASK_COMPLETE:T011] */}

      <div className="kpi-grid">
        {cards.map((k, i) => (
          <div key={i} className="kpi" onClick={() => go(k.nav)}>
            <div className="kpi-lbl">{k.lbl}<i className={k.icon}></i></div>
            <div className="kpi-val">{k.val}<span className="kpi-unit">{k.unit}</span></div>
            <div className={"kpi-delta " + k.deltaCls}>{k.delta}</div>
            <Sparkline kind={k.spark} />
          </div>
        ))}
      </div>

      <div className="page-row row-2">
        {/* [TASK_START:T006] */}
        <div className="card">
          <h3 className="card-title">Активные уведомления <a href="#" onClick={(e)=>{e.preventDefault();go("alerts")}}>View all · {kpis.open_alerts ?? 0}</a></h3>
          {alertsPreview.length === 0 && (
            <div style={{padding:"8px 0", color:"var(--fg-muted)", fontSize:13}}>Открытых инцидентов нет.</div>
          )}
          {alertsPreview.map((a, i) => {
            const kind = _normalizeKind(a?.severity || a?.kind);
            return (
              <div key={a?.id || i} className={"alert-row " + kind} onClick={() => go("alerts")}>
                <div className="ic"><i className={a?.icon || "ri-alert-line"}></i></div>
                <div>
                  <div className="alert-title">{a?.title || "Инцидент"}</div>
                  <div className="alert-sub">{a?.zone ? `Зона ${a.zone}` : "Зона —"}{a?.sub ? ` · ${a.sub}` : ""}</div>
                </div>
                <span className="alert-time">{_relativeTimeLabel(a?.time)}</span>
              </div>
            );
          })}
        </div>
        {/* [TASK_COMPLETE:T006] */}

        {/* [TASK_START:T007] */}
        <div className="card">
          <h3 className="card-title">Ульи, требующие внимания <a href="#" onClick={(e)=>{e.preventDefault();go("hives")}}>все</a></h3>
          {hivesNeedAttention.length === 0 && (
            <div style={{padding:"8px 0", color:"var(--fg-muted)", fontSize:13}}>Все ульи в норме.</div>
          )}
          {hivesNeedAttention.map((h, i, arr) => (
            <div key={h.id} style={{display:"grid",gridTemplateColumns:"auto 1fr auto auto",gap:12,alignItems:"center",padding:"12px 0",borderBottom:i<arr.length-1?"1px solid var(--n-150)":"none"}}>
              <span className={"tri tri-" + h.state}></span>
              <div>
                <div style={{font:"600 14px Inter",color:"var(--fg-strong)"}}>Улей {h.id} <span style={{color:"var(--fg-muted)",fontWeight:400,marginLeft:6}}>· {h.zone}</span></div>
                <div style={{fontSize:12,color:"var(--fg-muted)",marginTop:2}}>{h.note}</div>
              </div>
              <div style={{fontSize:12,fontVariantNumeric:"tabular-nums",color:"var(--fg-muted)",textAlign:"right"}}>
                <div><b style={{color:"var(--fg-strong)"}}>{h.activity}</b>/мин</div>
                <div>{h.temp} °C</div>
              </div>
              <button
                className="btn btn--secondary btn--sm"
                onClick={() => onOpenHive ? onOpenHive(h.id) : go("hivepage")}
              >
                Open
              </button>
            </div>
          ))}
        </div>
        {/* [TASK_COMPLETE:T007] */}
      </div>

      <div className="page-row row-2-1">
        {/* [TASK_START:T008] */}
        <div className="card">
          <h3 className="card-title">Расписание опыления · Блок AB1 <a href="#">изменить</a></h3>
          <div className="sched">
            <div className="h"></div>{dayLabels.map((d) => <div key={d} className="h">{d}</div>)}
            {timeWindows.map((time, ri) => (
              <React.Fragment key={time}>
                <div className="h">{time}</div>
                {dayLabels.map((_, di) => {
                  const state = scheduleMatrix[ri][di];
                  if (state === "empty") return <div key={di} className="cell empty">—</div>;
                  return <div key={di} className={"cell " + (state === "open" ? "open" : "close")}>{state === "open" ? "откр" : "закр"}</div>;
                })}
              </React.Fragment>
            ))}
          </div>
        </div>
        {/* [TASK_COMPLETE:T008] */}
        {/* [TASK_START:T009] */}
        <div className="card">
          <h3 className="card-title">Эффективность опыления · 7 дней</h3>
          <svg viewBox="0 0 340 150" style={{width:"100%",height:150,marginTop:8}}>
            {efficiencySeries.map((value, index) => {
              const max = 100;
              const chartBase = 120;
              const barWidth = 30;
              const step = 46;
              const x = 12 + (index * step);
              const h = Math.max(6, Math.round((value / max) * 94));
              const y = chartBase - h;
              const isLast = index === efficiencySeries.length - 1;
              return (
                <g key={index}>
                  <rect
                    x={x}
                    y={y}
                    width={barWidth}
                    height={h}
                    rx="4"
                    fill="url(#effBarGrad)"
                  />
                  <text
                    x={x + (barWidth / 2)}
                    y="140"
                    textAnchor="middle"
                    fontSize="11"
                    fontWeight={isLast ? "700" : "500"}
                    fill={isLast ? "var(--fg-strong)" : "var(--fg-muted)"}
                  >
                    {dayLabels[index]}
                  </text>
                  {isLast && (
                    <text
                      x={x + (barWidth / 2)}
                      y={Math.max(y - 8, 12)}
                      textAnchor="middle"
                      fontSize="11"
                      fontWeight="700"
                      fill="var(--fg-strong)"
                    >
                      {value}%
                    </text>
                  )}
                </g>
              );
            })}
            <defs>
              <linearGradient id="effBarGrad" x1="0" y1="0" x2="0" y2="1">
                <stop offset="0%" stopColor="#E8B84A" />
                <stop offset="100%" stopColor="#FFB300" />
              </linearGradient>
            </defs>
          </svg>
        </div>
        {/* [TASK_COMPLETE:T009] */}
      </div>
    </div>
  );
}

/* ── Sites list ───────────────────────────────────────────── */
function Sites({ onNav, onSelectSite }) {
  return (
    <div className="page" data-screen-label="03 Теплицы">
      <div className="page-head">
        <div>
          <div className="page-title">Теплицы</div>
          <div className="page-sub">{DATA.sites.length} объектов · 6,2 га суммарно · 109 ульев · 318 устройств</div>
        </div>
        <div className="actions">
          <div className="segmented"><button className="on">Карточки</button><button>Таблица</button></div>
          <button className="btn btn--secondary"><i className="ri-filter-line"></i>Фильтр</button>
          <button className="btn btn--primary"><i className="ri-add-line"></i>Добавить теплицу</button>
        </div>
      </div>

      <div style={{display:"grid",gridTemplateColumns:"repeat(3,1fr)",gap:14}}>
        {DATA.sites.map(s=>(
          <div
            key={s.id}
            className="site-card"
            onClick={() => {
              // [TASK_START:T008]
              if (onSelectSite) onSelectSite(s.id);
              onNav("greenhouses");
              // [TASK_COMPLETE:T008]
            }}
          >
            <div className="site-thumb" style={{backgroundImage:`url(${s.photo})`}}>
              <span className={"status status--"+(s.crit?"critical":s.warn?"warn":"ok")}><span className="dot"></span>{s.crit?"Авария":s.warn?"Внимание":"Норма"}</span>
            </div>
            <div className="site-card-body">
              <h3>{s.name}</h3>
              <div className="meta">{s.area} · {s.crop}</div>
              <div className="site-card-stats">
                <div><div className="l">Ульи</div><div className="v">{s.hives}</div></div>
                <div><div className="l">Устройства</div><div className="v">{s.devices}</div></div>
                <div><div className="l">Внимание</div><div className={"v "+(s.warn?"warn":"")}>{s.warn}</div></div>
                <div><div className="l">Авария</div><div className={"v "+(s.crit?"crit":"")}>{s.crit}</div></div>
              </div>
            </div>
          </div>
        ))}
      </div>
    </div>
  );
}

/* ── Site detail (summary header above the greenhouse map nav) ─ */
function Site({ siteId, onNav, onOpenGreenhouses }) {
  const site = DATA.sites.find((item) => item.id === siteId) || DATA.sites[0];
  return (
    <div className="page" data-screen-label="04 Теплица № 1">
      <div className="page-head">
        <div>
          <div className="page-title">{site.name}</div>
          <div className="page-sub">{site.area} · {site.crop} · {site.hives} ульев · {site.devices} устройств · обновлено 14:38</div>
        </div>
        <div className="actions">
          <button className="btn btn--secondary"><i className="ri-history-line"></i>История</button>
          {/* [TASK_START:T009] */}
          <button
            className="btn btn--secondary"
            onClick={() => onOpenGreenhouses ? onOpenGreenhouses(site.id) : onNav("greenhouses")}
          >
            <i className="ri-layout-grid-line"></i>Просмотр теплиц
          </button>
          {/* [TASK_COMPLETE:T009] */}
          <button className="btn btn--primary" onClick={()=>onNav("hives")}><i className="ri-map-2-line"></i>Открыть карту</button>
        </div>
      </div>

      <div className="kpi-grid">
        {[
          {lbl:"Активность ульев",val:"76",unit:"%",icon:"ri-pulse-line",spark:"ok",delta:"▲ 3,2 пп",cls:"up"},
          {lbl:"Темп. воздуха",val:"24,3",unit:"°C",icon:"ri-temp-hot-line",spark:"honey",delta:"норма 22–26",cls:""},
          {lbl:"Влажность",val:"68",unit:"%",icon:"ri-drop-line",spark:"honey",delta:"норма 60–75",cls:""},
          {lbl:"EC субстрата",val:"2,4",unit:"mS/cm",icon:"ri-flask-line",spark:"crit",delta:"1 датчик ↑",cls:"dn"},
          {lbl:"CO₂",val:"812",unit:"ppm",icon:"ri-bubble-chart-line",spark:"honey",delta:"норма 450–1100",cls:""},
          {lbl:"Освещённость",val:"18 400",unit:"лк",icon:"ri-sun-line",spark:"ok",delta:"ест. свет",cls:"up"},
        ].map((k,i)=>(
          <div key={i} className="kpi">
            <div className="kpi-lbl">{k.lbl}<i className={k.icon}></i></div>
            <div className="kpi-val">{k.val}<span className="kpi-unit">{k.unit}</span></div>
            <div className={"kpi-delta "+k.cls}>{k.delta}</div>
            <Sparkline kind={k.spark}/>
          </div>
        ))}
      </div>

      <div className="page-row row-2">
        <div className="card">
          <h3 className="card-title">Сегодня <a href="#">журнал</a></h3>
          <div className="history">
            <div className="h-row"><time>14:38</time><span>Закрыта задача T-1035 «Чистка фильтров полива L1»</span></div>
            <div className="h-row"><time>14:32</time><span><b style={{color:"#9a1f18"}}>Авария</b> · аномалия EC в зоне AB2</span></div>
            <div className="h-row"><time>14:02</time><span><b style={{color:"#9a1f18"}}>Авария</b> · TDS-Sensor-12 — нет связи</span></div>
            <div className="h-row"><time>12:08</time><span>Замена улья B-09 — задача создана</span></div>
            <div className="h-row"><time>11:42</time><span>Сработало правило «Закрыть ульи при перегреве»</span></div>
            <div className="h-row"><time>06:00</time><span>Открытие летков по расписанию · 28 из 29 успешно</span></div>
          </div>
        </div>
        <div className="card">
          <h3 className="card-title">Парк устройств <a href="#" onClick={(e)=>{e.preventDefault();onNav("devices")}}>все · 84</a></h3>
          <div style={{display:"grid",gridTemplateColumns:"repeat(3,1fr)",gap:8}}>
            {[
              {n:"Gateway",v:"1",icon:"ri-router-line",s:"ok"},
              {n:"Задвижки",v:"29",icon:"ri-door-open-line",s:"ok"},
              {n:"TDS",v:"12",icon:"ri-flask-line",s:"warn"},
              {n:"Активность",v:"29",icon:"ri-pulse-line",s:"ok"},
              {n:"Влажность",v:"8",icon:"ri-drop-line",s:"warn"},
              {n:"Камеры",v:"5",icon:"ri-camera-line",s:"ok"},
            ].map((c,i)=>(
              <div key={i} style={{padding:"10px 12px",border:"1px solid var(--border)",borderRadius:8,background:"var(--n-50)",display:"flex",justifyContent:"space-between",alignItems:"center",cursor:"pointer"}}>
                <div style={{display:"flex",gap:8,alignItems:"center"}}>
                  <i className={c.icon} style={{fontSize:16,color:c.s==="warn"?"#a04200":"var(--fg-muted)"}}></i>
                  <span style={{font:"500 13px Inter"}}>{c.n}</span>
                </div>
                <b style={{font:"700 14px Inter",fontVariantNumeric:"tabular-nums",color:"var(--fg-strong)"}}>{c.v}</b>
              </div>
            ))}
          </div>
        </div>
      </div>
    </div>
  );
}

function statusLabelClass(status) {
  if (status === "crit" || status === "critical") return "status--critical";
  if (status === "warn" || status === "warning") return "status--warn";
  return "status--ok";
}

function GreenhousesList({ siteId, selectedGreenhouseId, onNav, onSelectGreenhouse }) {
  const activeSite = DATA.sites.find((item) => item.id === siteId) || DATA.sites[0];
  const [rows, setRows] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState("");
  const mapGreenhouseId = React.useMemo(() => {
    if (!Array.isArray(rows) || rows.length === 0) return null;
    const selected = rows.find((item) => String(item.id) === String(selectedGreenhouseId));
    return selected?.id ?? rows[0]?.id ?? null;
  }, [rows, selectedGreenhouseId]);

  React.useEffect(() => {
    let cancelled = false;
    async function load() {
      setLoading(true);
      setError("");
      try {
        const live = await Keeper.api.greenhouses(activeSite.id);
        if (cancelled) return;
        setRows(Array.isArray(live) ? live : []);
      } catch (e) {
        if (cancelled) return;
        const fallback = DATA.greenhouses?.[activeSite.id] || [];
        setRows(fallback);
        if (e && e.status === 404) setError("Список теплиц не найден (404)");
      } finally {
        if (!cancelled) setLoading(false);
      }
    }
    load();
    return () => { cancelled = true; };
  }, [activeSite.id]);

  return (
    <div className="page" data-screen-label="05 Теплицы объекта">
      <div className="page-head">
        <div>
          <div className="page-title">Теплицы · {activeSite.name}</div>
          <div className="page-sub">{rows.length} теплиц · переход к зонам по клику на строку</div>
        </div>
        <div className="actions">
          <button className="btn btn--secondary" onClick={() => onNav("sites")}><i className="ri-arrow-left-line"></i>К объектам</button>
          <button
            className="btn btn--secondary"
            disabled={!mapGreenhouseId}
            onClick={() => {
              if (!mapGreenhouseId) return;
              if (onSelectGreenhouse) onSelectGreenhouse(mapGreenhouseId);
              onNav("hives", { greenhouseId: mapGreenhouseId, zoneId: null, deviceId: null });
            }}
          >
            <i className="ri-map-2-line"></i>Карта
          </button>
          <button className="btn btn--secondary"><i className="ri-filter-line"></i>Фильтр</button>
        </div>
      </div>

      <div className="card" style={{padding:0,overflow:"hidden"}}>
        <table>
          <thead>
            <tr>
              <th>Теплица</th>
              <th>Зон</th>
              <th>Ульев</th>
              <th>Устройств</th>
              <th>Статус</th>
            </tr>
          </thead>
          <tbody>
            {loading && (
              <tr>
                <td colSpan="5">Загрузка…</td>
              </tr>
            )}
            {!loading && error && (
              <tr>
                <td colSpan="5" style={{color:"#9a1f18"}}>{error}</td>
              </tr>
            )}
            {!loading && rows.length === 0 && (
              <tr>
                <td colSpan="5">Теплицы не найдены</td>
              </tr>
            )}
            {!loading && rows.map((item) => {
              const zoneCount = item.zone_count ?? item.zones_count ?? item.zones ?? 0;
              return (
                <tr
                  key={item.id}
                  style={{cursor:"pointer"}}
                  onClick={() => {
                    if (onSelectGreenhouse) onSelectGreenhouse(item.id);
                    onNav("zones", { greenhouseId: item.id, zoneId: null, deviceId: null });
                  }}
                >
                  <td>{item.name || item.id}</td>
                  <td>{zoneCount}</td>
                  <td>{item.hive_count ?? item.hives_count ?? item.hives ?? 0}</td>
                  <td>{item.device_count ?? item.devices_count ?? item.devices ?? 0}</td>
                  <td>
                    <span className={"status " + statusLabelClass(item.status)}>
                      <span className="dot"></span>
                      {item.status_label || item.statusLbl || "Норма"}
                    </span>
                  </td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </div>
    </div>
  );
}

// [TASK_START:T005]
function ZonesList({ greenhouseId, onNav, onSelectZone }) {
  const [rows, setRows] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState("");

  React.useEffect(() => {
    let cancelled = false;
    async function load() {
      setLoading(true);
      setError("");
      try {
        const live = await Keeper.api.zones(greenhouseId);
        if (cancelled) return;
        setRows(Array.isArray(live) ? live : []);
      } catch (e) {
        if (cancelled) return;
        const fallback = DATA.zones?.[greenhouseId] || [];
        setRows(fallback);
        if (e && e.status === 404) setError("Зоны не найдены (404)");
      } finally {
        if (!cancelled) setLoading(false);
      }
    }
    if (greenhouseId) load();
    else {
      setRows([]);
      setLoading(false);
    }
    return () => { cancelled = true; };
  }, [greenhouseId]);

  return (
    <div className="page" data-screen-label="06 Зоны теплицы">
      <div className="page-head">
        <div>
          <div className="page-title">Зоны · {greenhouseId || "—"}</div>
          <div className="page-sub">{rows.length} зон · переход к списку ульев по клику</div>
        </div>
        <div className="actions">
          <button className="btn btn--secondary" onClick={() => onNav("greenhouses")}><i className="ri-arrow-left-line"></i>К теплицам</button>
          <button className="btn btn--secondary"><i className="ri-filter-line"></i>Фильтр</button>
        </div>
      </div>

      <div className="card" style={{padding:0,overflow:"hidden"}}>
        <table>
          <thead>
            <tr>
              <th>Zone ID</th>
              <th>Ряд</th>
              <th>Ульев</th>
              <th>Устройств</th>
              <th>Статус</th>
            </tr>
          </thead>
          <tbody>
            {loading && (
              <tr>
                <td colSpan="5">Загрузка…</td>
              </tr>
            )}
            {!loading && error && (
              <tr>
                <td colSpan="5" style={{color:"#9a1f18"}}>{error}</td>
              </tr>
            )}
            {!loading && rows.length === 0 && (
              <tr>
                <td colSpan="5">В этой теплице пока нет зон</td>
              </tr>
            )}
            {!loading && rows.map((item) => (
              <tr
                key={item.id}
                style={{cursor:"pointer"}}
                onClick={() => {
                  if (onSelectZone) onSelectZone(item.id);
                  onNav("hiveslist", {
                    greenhouseId: greenhouseId || null,
                    zoneId: item.id,
                  });
                }}
              >
                <td className="id-mono">{item.id}</td>
                <td>{item.row_label || item.row || item.name || "—"}</td>
                <td>{item.hive_count ?? item.hives_count ?? 0}</td>
                <td>{item.device_count ?? item.devices_count ?? 0}</td>
                <td>
                  <span className={"status " + statusLabelClass(item.status)}>
                    <span className="dot"></span>
                    {item.status_label || item.statusLbl || "Норма"}
                  </span>
                </td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}
// [TASK_COMPLETE:T005]

// [TASK_START:T006]
function HivesList({ greenhouseId, zoneId, onNav, onSelectHive }) {
  const [rows, setRows] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [error, setError] = React.useState("");

  React.useEffect(() => {
    let cancelled = false;
    async function load() {
      setLoading(true);
      setError("");
      try {
        const live = await Keeper.api.hives(greenhouseId);
        if (cancelled) return;
        setRows(Array.isArray(live) ? live : []);
      } catch (e) {
        if (cancelled) return;
        const fallback = DATA.hives?.[greenhouseId] || [];
        setRows(fallback);
        if (e && e.status === 404) setError("Ульи не найдены (404)");
      } finally {
        if (!cancelled) setLoading(false);
      }
    }
    if (greenhouseId) load();
    else {
      setRows([]);
      setLoading(false);
    }
    return () => { cancelled = true; };
  }, [greenhouseId]);

  const filtered = zoneId ? rows.filter((item) => item.zone_id === zoneId || item.zoneId === zoneId) : rows;

  return (
    <div className="page" data-screen-label="07 Ульи зоны">
      <div className="page-head">
        <div>
          <div className="page-title">Ульи · {zoneId || greenhouseId || "—"}</div>
          <div className="page-sub">{filtered.length} ульев · откройте строку для карточки улья</div>
        </div>
        <div className="actions">
          <button
            className="btn btn--secondary"
            onClick={() => onNav("zones", {
              greenhouseId: greenhouseId || null,
              zoneId: zoneId || null,
            })}
          >
            <i className="ri-arrow-left-line"></i>К зонам
          </button>
          <button className="btn btn--secondary"><i className="ri-filter-line"></i>Фильтр</button>
        </div>
      </div>

      <div className="card" style={{padding:0,overflow:"hidden"}}>
        <table>
          <thead>
            <tr>
              <th>Hive ID</th>
              <th>State</th>
              <th>Departures/min</th>
              <th>Temperature</th>
              <th>Gate</th>
              <th>Last seen</th>
            </tr>
          </thead>
          <tbody>
            {loading && (
              <tr>
                <td colSpan="6">Загрузка…</td>
              </tr>
            )}
            {!loading && error && (
              <tr>
                <td colSpan="6" style={{color:"#9a1f18"}}>{error}</td>
              </tr>
            )}
            {!loading && filtered.length === 0 && (
              <tr>
                <td colSpan="6">Ульи в выбранной зоне не найдены</td>
              </tr>
            )}
            {!loading && filtered.map((item) => (
              <tr
                key={item.id}
                style={{cursor:"pointer"}}
                onClick={() => {
                  if (onSelectHive) onSelectHive(item.id);
                  if (onNav) onNav("hivepage", {
                    greenhouseId: greenhouseId || null,
                    zoneId: item.zone_id || item.zoneId || zoneId || null,
                    hiveId: item.id,
                  });
                }}
              >
                <td className="id-mono">{item.id}</td>
                <td>
                  <span className={"status " + statusLabelClass(item.state || item.status)}>
                    <span className="dot"></span>
                    {item.state_label || item.stateLabel || item.state || "ok"}
                  </span>
                </td>
                <td>{item.departures_per_min ?? item.departures ?? "—"}</td>
                <td>{item.temperature_c != null ? `${item.temperature_c} °C` : "—"}</td>
                <td>{item.gate_status || item.gate || "—"}</td>
                <td>{item.last_seen || item.updated_at || "—"}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
    </div>
  );
}
// [TASK_COMPLETE:T006]

window.Overview = Overview;
window.Sites = Sites;
window.Site = Site;
window.GreenhousesList = GreenhousesList;
window.ZonesList = ZonesList;
window.HivesList = HivesList;
