// GreenhousesList.jsx — Table view of greenhouses for a given site.
// Fetches from Keeper.api.greenhouses(siteId) and falls back to
// window.DATA.greenhouses[siteId] demo data when the backend is offline.

function GreenhousesList({ siteId, selectedGreenhouseId, onNav, onSelectGreenhouse }) {
  const i18n = window.Keeper && window.Keeper.i18n ? window.Keeper.i18n : null;
  function tr(key, fallback, params) {
    if (i18n && typeof i18n.t === "function") return i18n.t(key, params, { fallback });
    return fallback;
  }
  const interaction = window.Keeper && window.Keeper.interaction ? window.Keeper.interaction : null;
  const interactionLifecycle = interaction || {
    createState() {
      return {
        phase: "idle",
        loading: false,
        success: false,
        error: "",
        requestToken: 0,
        activeRequestToken: null,
        meta: {},
      };
    },
    start(prev, options) {
      const safePrev = prev && typeof prev === "object" ? prev : this.createState();
      const nextToken = (Number.isInteger(safePrev.requestToken) ? safePrev.requestToken : 0) + 1;
      return Object.assign({}, safePrev, {
        phase: "loading",
        loading: true,
        success: false,
        error: "",
        requestToken: nextToken,
        activeRequestToken: nextToken,
        meta: options && typeof options.meta === "object" ? options.meta : (safePrev.meta || {}),
      });
    },
    succeed(prev, token) {
      const safePrev = prev && typeof prev === "object" ? prev : this.createState();
      if (safePrev.activeRequestToken !== token) return safePrev;
      return Object.assign({}, safePrev, {
        phase: "success",
        loading: false,
        success: true,
        error: "",
        activeRequestToken: null,
      });
    },
    fail(prev, token, error, options) {
      const safePrev = prev && typeof prev === "object" ? prev : this.createState();
      if (safePrev.activeRequestToken !== token) return safePrev;
      const fallbackMessage = options && typeof options.fallbackMessage === "string"
        ? options.fallbackMessage
        : ((error && error.message) || "");
      const patch = options && typeof options.patch === "object" ? options.patch : {};
      return Object.assign({}, safePrev, {
        phase: "error",
        loading: false,
        success: false,
        error: fallbackMessage,
        activeRequestToken: null,
      }, patch);
    },
    isStaleResponse(state, token) {
      return !state || state.activeRequestToken !== token;
    },
  };

  // Resolve siteId: prop > query-param hash > first site fallback
  const resolvedSiteId = siteId
    || (function() {
         try {
           const hash = window.location.hash; // e.g. "#greenhouses?siteId=2"
           const qi = hash.indexOf("?");
           if (qi !== -1) {
             const params = new URLSearchParams(hash.slice(qi + 1));
             const v = params.get("siteId");
             if (v) return isNaN(Number(v)) ? v : Number(v);
           }
         } catch (_) {}
         return null;
       })()
    || (DATA.sites && DATA.sites[0] && DATA.sites[0].id)
    || 1;

  const [rows, setRows]       = React.useState([]);
  const [listInteraction, setListInteraction] = React.useState(() =>
    Object.assign({}, interactionLifecycle.createState(), { phase: "loading", loading: true })
  );
  const [search, setSearch]   = React.useState("");
  const [statusFilter, setStatusFilter] = React.useState("all"); // "all" | "ok" | "warn" | "crit"
  const listInteractionRef = React.useRef(listInteraction);

  React.useEffect(() => {
    listInteractionRef.current = listInteraction;
  }, [listInteraction]);

  function commitListInteraction(nextState) {
    listInteractionRef.current = nextState;
    setListInteraction(nextState);
  }

  const listActionRunnerRef = React.useRef(null);
  if (!listActionRunnerRef.current && interaction && typeof interaction.createActionRunner === "function") {
    listActionRunnerRef.current = interaction.createActionRunner({
      getState: () => listInteractionRef.current,
      setState: commitListInteraction,
    });
  }

  function isStaleInteraction(state, token) {
    return interactionLifecycle.isStaleResponse(state, token);
  }

  // Find site metadata for subtitle
  const site = DATA.sites && DATA.sites.find(s => s.id === resolvedSiteId);

  React.useEffect(() => {
    let cancelled = false;
    const listRunner = listActionRunnerRef.current;

    (async () => {
      if (listRunner) {
        await listRunner.run(async ({ token }) => {
          const data = await Keeper.api.greenhouses(resolvedSiteId);
          if (cancelled || listRunner.isStale(token)) return null;
          setRows(Array.isArray(data) ? data : []);
          return null;
        }, {
          meta: { actionType: "greenhouses.load" },
          onError: (error) => {
            if (cancelled) return {};
            const demo = (DATA.greenhouses && DATA.greenhouses[resolvedSiteId]) || [];
            if (Array.isArray(demo) && demo.length > 0) {
              setRows(demo);
              return { patch: { phase: "success", loading: false, success: true, error: "", activeRequestToken: null } };
            }
            setRows([]);
            const fallbackMessage = tr("greenhousesList.errors.loadFailed", "Failed to load greenhouse list");
            const formatted = typeof Keeper.formatApiFailure === "function"
              ? Keeper.formatApiFailure(error, { fallbackMessage })
              : fallbackMessage;
            return { fallbackMessage: formatted };
          },
        });
        return;
      }

      const startedState = interactionLifecycle.start(listInteractionRef.current, { meta: { actionType: "greenhouses.load" } });
      commitListInteraction(startedState);
      const requestToken = startedState.activeRequestToken;

      try {
        const data = await Keeper.api.greenhouses(resolvedSiteId);
        if (cancelled) return;
        if (isStaleInteraction(listInteractionRef.current, requestToken)) return;

        setRows(Array.isArray(data) ? data : []);
        const successState = interactionLifecycle.succeed(listInteractionRef.current, requestToken);
        commitListInteraction(successState);
      } catch (error) {
        if (cancelled) return;
        if (isStaleInteraction(listInteractionRef.current, requestToken)) return;

        const demo = (DATA.greenhouses && DATA.greenhouses[resolvedSiteId]) || [];
        if (Array.isArray(demo) && demo.length > 0) {
          setRows(demo);
          const successState = interactionLifecycle.succeed(listInteractionRef.current, requestToken);
          commitListInteraction(successState);
          return;
        }

        setRows([]);
        const fallbackMessage = tr("greenhousesList.errors.loadFailed", "Failed to load greenhouse list");
        const formatted = typeof Keeper.formatApiFailure === "function"
          ? Keeper.formatApiFailure(error, { fallbackMessage })
          : fallbackMessage;
        const errorState = interactionLifecycle.fail(listInteractionRef.current, requestToken, error, { fallbackMessage: formatted });
        commitListInteraction(errorState);
      }
    })();

    return () => {
      cancelled = true;
    };
  }, [resolvedSiteId]);

  function reloadRows() {
    const listRunner = listActionRunnerRef.current;
    if (listRunner) {
      listRunner.run(async ({ token }) => {
        const data = await Keeper.api.greenhouses(resolvedSiteId);
        if (listRunner.isStale(token)) return null;
        setRows(Array.isArray(data) ? data : []);
        return null;
      }, {
        meta: { actionType: "greenhouses.retry" },
        onError: (error) => {
          const fallbackMessage = tr("greenhousesList.errors.loadFailed", "Failed to load greenhouse list");
          const formatted = typeof Keeper.formatApiFailure === "function"
            ? Keeper.formatApiFailure(error, { fallbackMessage })
            : fallbackMessage;
          return { fallbackMessage: formatted };
        },
      });
      return;
    }

    const startedState = interactionLifecycle.start(listInteractionRef.current, { meta: { actionType: "greenhouses.retry" } });
    commitListInteraction(startedState);

    Keeper.api.greenhouses(resolvedSiteId)
      .then((data) => {
        if (isStaleInteraction(listInteractionRef.current, startedState.activeRequestToken)) return;
        setRows(Array.isArray(data) ? data : []);
        const successState = interactionLifecycle.succeed(listInteractionRef.current, startedState.activeRequestToken);
        commitListInteraction(successState);
      })
      .catch((error) => {
        if (isStaleInteraction(listInteractionRef.current, startedState.activeRequestToken)) return;
        const fallbackMessage = tr("greenhousesList.errors.loadFailed", "Failed to load greenhouse list");
        const formatted = typeof Keeper.formatApiFailure === "function"
          ? Keeper.formatApiFailure(error, { fallbackMessage })
          : fallbackMessage;
        const errorState = interactionLifecycle.fail(listInteractionRef.current, startedState.activeRequestToken, error, { fallbackMessage: formatted });
        commitListInteraction(errorState);
      });
  }

  const loading = !!listInteraction.loading;
  const error = listInteraction.error || "";

  // ── Derived filtered list ────────────────────────────────────────────────
  const filtered = rows.filter(gh => {
    const q = search.trim().toLowerCase();
    const matchSearch = !q
      || gh.id.toLowerCase().includes(q)
      || gh.name.toLowerCase().includes(q)
      || (gh.zone  && gh.zone.toLowerCase().includes(q))
      || (gh.crop  && gh.crop.toLowerCase().includes(q));
    const matchStatus = statusFilter === "all" || gh.status === statusFilter;
    return matchSearch && matchStatus;
  });

  // ── Status colour helpers ────────────────────────────────────────────────
  function statusClass(s) {
    if (s === "crit" || s === "critical") return "status--critical";
    if (s === "warn")                     return "status--warn";
    return "status--ok";
  }

  // ── Summary counts ───────────────────────────────────────────────────────
  const total      = rows.length;
  const critCount  = rows.filter(r => r.status === "crit" || r.status === "critical").length;
  const warnCount  = rows.filter(r => r.status === "warn").length;
  const totalHives = rows.reduce((s, r) => s + (r.hives   || 0), 0);
  const totalDevs  = rows.reduce((s, r) => s + (r.devices || 0), 0);
  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]);

  // ── Render ───────────────────────────────────────────────────────────────
  return (
    <div className="page" data-screen-label="Greenhouse blocks">

      {/* Page header */}
      <div className="page-head">
        <div>
          <div className="page-title">
            {site ? site.name : tr("greenhousesList.siteFallback", "Greenhouse blocks")}
          </div>
          <div className="page-sub">
            {tr("greenhousesList.subtitle", "{total} blocks · {hives} hives · {devices} devices", { total, hives: totalHives, devices: totalDevs })}
            {critCount > 0 && <span style={{color:"var(--status-crit-fg)",marginLeft:8}}>· {critCount} {tr("greenhousesList.critCount", critCount === 1 ? "fault" : "faults", { count: critCount })}</span>}
            {warnCount > 0 && <span style={{color:"var(--status-alert-fg)",marginLeft:8}}>· {warnCount} {tr("greenhousesList.warnCount", warnCount === 1 ? "warning" : "warnings", { count: warnCount })}</span>}
          </div>
        </div>
        <div className="actions">
          <button
            className="btn btn--secondary"
            onClick={() => onNav && onNav("site")}
          >
            <i className="ri-arrow-left-line"></i>{tr("greenhousesList.actions.backToSite", "Back to site")}
          </button>
          <button
            className="btn btn--secondary"
            disabled={!mapGreenhouseId}
            onClick={() => {
              if (!mapGreenhouseId || !onNav) return;
              if (onSelectGreenhouse) onSelectGreenhouse(mapGreenhouseId);
              onNav("hives", { greenhouseId: mapGreenhouseId, zoneId: null, deviceId: null });
            }}
          >
            <i className="ri-map-2-line"></i>{tr("greenhousesList.actions.map", "Map")}
          </button>
          {Keeper.hasRole(Keeper.ROLES.agronomist) && (
            <button className="btn btn--primary">
              <i className="ri-add-line"></i>{tr("greenhousesList.actions.addBlock", "Add block")}
            </button>
          )}
        </div>
      </div>

      {/* Search + filter bar */}
      <div style={{display:"flex",gap:8,flexWrap:"wrap"}}>
        <div className="search" style={{maxWidth:280}}>
          <i className="ri-search-line"></i>
          <input
            aria-label={tr("greenhousesList.filters.searchAria", "Search greenhouse blocks")}
            placeholder={tr("greenhousesList.filters.searchPlaceholder", "ID, name, zone, crop…")}
            value={search}
            onChange={e => setSearch(e.target.value)}
          />
        </div>

        {/* Status filter chips */}
        <div className="segmented">
          {[
            {value:"all",  label: tr("greenhousesList.filters.all", "All")},
            {value:"ok",   label: tr("greenhousesList.filters.ok", "OK")},
            {value:"warn", label: tr("greenhousesList.filters.warn", "Warning")},
            {value:"crit", label: tr("greenhousesList.filters.crit", "Fault")},
          ].map(opt => (
            <button
              key={opt.value}
              className={statusFilter === opt.value ? "on" : ""}
              onClick={() => setStatusFilter(opt.value)}
              aria-pressed={statusFilter === opt.value}
            >
              {opt.label}
            </button>
          ))}
        </div>
      </div>

      {/* Loading state */}
      {loading && (
        <FeedbackPresenter
          state="loading"
          className="card"
          message={tr("greenhousesList.loading", "Loading blocks…")}
        />
      )}

      {/* Error state */}
      {!loading && error && (
        <FeedbackPresenter
          state="error"
          className="card"
          message={error}
          title={tr("greenhousesList.loadError", "Load error")}
          onRetry={reloadRows}
          retryLabel={tr("greenhousesList.retryLabel", "Retry")}
        />
      )}

      {/* Empty state */}
      {!loading && !error && filtered.length === 0 && (
        <FeedbackPresenter
          state="empty"
          className="card"
          icon={rows.length === 0 ? "ri-plant-line" : "ri-filter-off-line"}
          message={rows.length === 0 ? tr("greenhousesList.empty.noBlocks", "No blocks found") : tr("greenhousesList.empty.filtered", "Nothing matches the filter")}
          action={rows.length === 0 ? null : (
            <button
              className="btn btn--secondary btn--sm"
              type="button"
              onClick={() => {
                setSearch("");
                setStatusFilter("all");
              }}
            >
              {tr("greenhousesList.resetFilters", "Reset filters")}
            </button>
          )}
        />
      )}

      {/* Greenhouses table */}
      {!loading && !error && filtered.length > 0 && (
        <div className="card" style={{padding:0,overflow:"hidden"}}>
          <table>
            <thead>
              <tr>
                <th>ID</th>
                <th>{tr("greenhousesList.table.nameBlock", "Block / Name")}</th>
                <th>{tr("greenhousesList.table.zone", "Zone")}</th>
                <th>{tr("greenhousesList.table.crop", "Crop")}</th>
                <th>{tr("greenhousesList.table.area", "Area")}</th>
                <th>{tr("greenhousesList.table.hives", "Hives")}</th>
                <th>{tr("greenhousesList.table.devices", "Devices")}</th>
                <th>{tr("greenhousesList.table.temp", "Temp.")}</th>
                <th>{tr("greenhousesList.table.humidity", "Humidity")}</th>
                <th>{tr("greenhousesList.table.updated", "Updated")}</th>
                <th>{tr("greenhousesList.table.status", "Status")}</th>
              </tr>
            </thead>
            <tbody>
              {filtered.map(gh => (
                <tr
                  key={gh.id}
                  style={{cursor:"pointer"}}
                  onClick={() => {
                    if (onSelectGreenhouse) onSelectGreenhouse(gh.id);
                    if (onNav) onNav("hives", { greenhouseId: gh.id, zoneId: null, deviceId: null });
                  }}
                >
                  <td className="id-mono">{gh.id}</td>
                  <td>
                    <div style={{display:"flex",gap:10,alignItems:"center"}}>
                      <i
                        className="ri-plant-line"
                        style={{fontSize:16,color:"var(--fg-muted)",flexShrink:0}}
                      ></i>
                      <b style={{font:"600 13px Inter",color:"var(--fg-strong)"}}>{gh.name}</b>
                    </div>
                  </td>
                  <td style={{color:"var(--fg-muted)",fontVariantNumeric:"tabular-nums"}}>{gh.zone || "—"}</td>
                  <td>{gh.crop || "—"}</td>
                  <td style={{fontVariantNumeric:"tabular-nums"}}>{gh.area || "—"}</td>
                  <td style={{fontVariantNumeric:"tabular-nums",textAlign:"center"}}>
                    {gh.hives > 0
                      ? <span style={{display:"inline-flex",alignItems:"center",gap:5}}>
                          <i className="ri-seedling-line" style={{fontSize:13,color:"var(--fg-muted)"}}></i>
                          {gh.hives}
                        </span>
                      : <span style={{color:"var(--fg-subtle)"}}>—</span>
                    }
                  </td>
                  <td style={{fontVariantNumeric:"tabular-nums",textAlign:"center"}}>{gh.devices ?? "—"}</td>
                  <td style={{fontVariantNumeric:"tabular-nums"}}>
                    {gh.temp != null
                      ? <span>{gh.temp} °C</span>
                      : <span style={{color:"var(--fg-subtle)"}}>—</span>
                    }
                  </td>
                  <td style={{fontVariantNumeric:"tabular-nums"}}>
                    {gh.humidity != null
                      ? <span style={{color: gh.humidity > 80 || gh.humidity < 50 ? "var(--status-alert-fg)" : "inherit"}}>
                          {gh.humidity} %
                        </span>
                      : <span style={{color:"var(--fg-subtle)"}}>—</span>
                    }
                  </td>
                  <td style={{color:"var(--fg-muted)",fontSize:12,fontVariantNumeric:"tabular-nums"}}>{gh.updated || "—"}</td>
                  <td>
                    <span className={"status " + statusClass(gh.status)}>
                      <span className="dot"></span>
                      {gh.statusLbl || gh.status || "—"}
                    </span>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

    </div>
  );
}

window.GreenhousesList = GreenhousesList;
