// HiveDetail.jsx — slide-in panel with per-hive gate control

const GATE_COMMAND_STATUS_VIEW = {
  pending:   { cls: "info",     label: "В очереди" },
  sent:      { cls: "warn",     label: "Отправлена" },
  applied:   { cls: "ok",       label: "Выполнено" },
  failed:    { cls: "critical", label: "Ошибка" },
  timed_out: { cls: "warn",     label: "Нет ответа" },
};

function gateCommandStatusBadge(status) {
  const cfg = GATE_COMMAND_STATUS_VIEW[status] || { cls: "muted", label: status || "—" };
  return (
    <span className={"status status--" + cfg.cls}>
      <span className="dot"></span>
      {cfg.label}
    </span>
  );
}

function formatHiveCommandTs(value) {
  if (!value) return "—";
  const dt = new Date(value);
  if (Number.isNaN(dt.getTime())) return String(value);
  return dt.toLocaleString("ru-RU", {
    day: "2-digit",
    month: "2-digit",
    hour: "2-digit",
    minute: "2-digit",
  });
}

function findHiveFallbackById(hiveId) {
  const byGreenhouse = (DATA && DATA.hives) || {};
  const all = Object.values(byGreenhouse).flat();
  const row = all.find((item) => item.id === hiveId);
  if (!row) return null;
  return {
    id: row.id,
    name: `Улей ${row.id}`,
    zone_id: row.zone_id || null,
    status: row.state || row.status || "ok",
    activity_per_min: row.departures_per_min,
    gate_status: row.gate_status,
    gate_device_id: row.gate_device_id || null,
  };
}

function deriveGateState(hive) {
  const state = String(hive?.gate_status || hive?.gate_mode || "").toLowerCase();
  if (state === "open") return "open";
  if (state === "closed") return "closed";
  if (state === "offline") return "offline";
  return "closed";
}

function isUnavailableStatus(status) {
  return (
    status === "critical" ||
    status === "crit" ||
    status === "warn" ||
    status === "warning" ||
    status === "offline"
  );
}

function mapHiveStateClass(status) {
  if (status === "critical" || status === "crit") return "tri-cri";
  if (status === "warn" || status === "warning") return "tri-att";
  return "tri-ok";
}

function runGateSmokeAssertions() {
  if (window.__keeperGateSmokeChecked) return;
  window.__keeperGateSmokeChecked = true;
  console.assert(isUnavailableStatus("critical") === true, "gate smoke: critical must disable controls");
  console.assert(isUnavailableStatus("warn") === true, "gate smoke: warn must disable controls");
  console.assert(isUnavailableStatus("ok") === false, "gate smoke: ok must allow controls");
  console.assert(deriveGateState({ gate_status: "open" }) === "open", "gate smoke: open state mapping");
}

// [TASK_START:T005]
function GateConfirmModal({ action, hiveId, gateDeviceId, onCancel, onConfirm, loading }) {
  React.useEffect(() => {
    if (!action) return undefined;
    function onEsc(e) {
      if (e.key === "Escape" && !loading) onCancel();
    }
    window.addEventListener("keydown", onEsc);
    return () => window.removeEventListener("keydown", onEsc);
  }, [action, loading, onCancel]);

  if (!action) return null;
  const isOpenAction = action === "open";

  return (
    <div className="modal-overlay" data-testid="gate-confirm-modal" onClick={() => !loading && onCancel()}>
      <div className="modal" onClick={(e) => e.stopPropagation()}>
        <div className="modal-head">
          <div style={{ display: "flex", gap: 12, alignItems: "flex-start" }}>
            <div style={{ width: 36, height: 36, borderRadius: 8, background: "#FFE7CF", color: "#a04200", display: "flex", alignItems: "center", justifyContent: "center", fontSize: 18 }}><i className="ri-shield-check-line"></i></div>
            <div>
              <div style={{ font: "700 16px Inter", color: "var(--fg-strong)" }}>Подтвердите команду</div>
              <div style={{ fontSize: 13, color: "var(--fg-muted)", marginTop: 2 }}>
                {isOpenAction ? "Открыть" : "Закрыть"} задвижку для выбранного улья
              </div>
            </div>
          </div>
          <button className="icon-btn" onClick={onCancel} disabled={loading}><i className="ri-close-line"></i></button>
        </div>
        <div className="modal-body">
          <dl style={{ display: "grid", gridTemplateColumns: "96px 1fr", gap: "6px 12px", margin: 0, fontSize: 13 }}>
            <dt style={{ color: "var(--fg-muted)" }}>Действие</dt>
            <dd style={{ margin: 0, fontWeight: 600 }}>{isOpenAction ? "Открыть задвижку" : "Закрыть задвижку"}</dd>
            <dt style={{ color: "var(--fg-muted)" }}>Hive ID</dt>
            <dd style={{ margin: 0 }} className="id-mono">{hiveId}</dd>
            <dt style={{ color: "var(--fg-muted)" }}>Gate Device</dt>
            <dd style={{ margin: 0 }} className="id-mono">{gateDeviceId || "—"}</dd>
          </dl>
        </div>
        <div className="modal-foot">
          <button className="btn btn--ghost" onClick={onCancel} disabled={loading}>Отменить</button>
          <button className="btn btn--danger" onClick={onConfirm} disabled={loading}>
            <i className="ri-shield-check-line"></i>
            {loading ? "Отправка…" : "Подтвердить"}
          </button>
        </div>
      </div>
    </div>
  );
}
// [TASK_COMPLETE:T005]

// [TASK_START:T006]
function HiveGateControl({ hive, gateDeviceStatus }) {
  const GateBadge = window.GateStatusBadge;
  const gateDeviceId = hive?.gate_device_id || null;
  const unavailable = !gateDeviceId || isUnavailableStatus(gateDeviceStatus);

  const [confirmAction, setConfirmAction] = React.useState(null);
  const [submitting, setSubmitting] = React.useState(false);
  const [inlineError, setInlineError] = React.useState("");
  const [history, setHistory] = React.useState([]);
  const [gateState, setGateState] = React.useState(deriveGateState(hive));
  const [latestCommandId, setLatestCommandId] = React.useState("");
  const [latestCommandStatus, setLatestCommandStatus] = React.useState("");

  React.useEffect(() => {
    runGateSmokeAssertions();
  }, []);

  React.useEffect(() => {
    setGateState(deriveGateState(hive));
    setInlineError("");
    setLatestCommandId("");
    setLatestCommandStatus("");
    setHistory([]);
  }, [hive?.id]);

  React.useEffect(() => {
    if (!latestCommandId || (latestCommandStatus !== "pending" && latestCommandStatus !== "sent")) return undefined;
    let cancelled = false;
    const startedAt = Date.now();

    const timer = setInterval(async () => {
      if (cancelled || Date.now() - startedAt < 10000) return;
      try {
        const [command, audit] = await Promise.all([
          Keeper.api.command(latestCommandId),
          Keeper.api.getCommandAudit(latestCommandId, 10),
        ]);
        if (cancelled) return;

        const latestAudit = Array.isArray(audit?.entries) ? audit.entries[0] : null;
        const nextStatus = latestAudit?.status || command?.status;
        if (!nextStatus || nextStatus === latestCommandStatus) return;

        setLatestCommandStatus(nextStatus);
        setHistory((prev) => prev.map((row) => row.id === latestCommandId ? { ...row, status: nextStatus } : row));
        if (nextStatus === "timed_out") {
          setInlineError("Нет ответа от устройства");
        }
      } catch (_) {
        // Polling is best-effort; do not interrupt the operator flow on transient errors.
      }
    }, 2500);

    return () => {
      cancelled = true;
      clearInterval(timer);
    };
  }, [latestCommandId, latestCommandStatus]);

  function appendHistoryRow(commandId, action, actor, status, issuedAt) {
    const actionLabel = action === "open" ? "Открыть задвижку" : "Закрыть задвижку";
    const row = {
      id: commandId,
      action: actionLabel,
      actor: actor || "ui",
      at: issuedAt || new Date().toISOString(),
      status: status || "pending",
    };
    setHistory((prev) => [row, ...prev].slice(0, 5));
  }

  async function execute(action) {
    if (!hive?.id || !gateDeviceId) return;
    const previousGateState = gateState;
    const issuedBy = window.DATA?.user?.initials || window.DATA?.user?.name || "ui";

    setConfirmAction(null);
    setSubmitting(true);
    setInlineError("");
    setGateState("transitioning");
    setLatestCommandStatus("pending");

    try {
      const command = action === "open"
        ? await Keeper.api.openHiveGate(hive.id, issuedBy)
        : await Keeper.api.closeHiveGate(hive.id, issuedBy);

      const status = command?.status || "pending";
      const commandId = command?.id || `CMD-local-${Date.now()}`;
      setLatestCommandId(commandId);
      setLatestCommandStatus(status);
      appendHistoryRow(commandId, action, command?.issued_by || issuedBy, status, command?.issued_at);

      if (status === "applied") {
        setGateState(action === "open" ? "open" : "closed");
      } else if (status === "failed") {
        setGateState(previousGateState);
        setInlineError("Команда не выполнена · код 500");
      }
    } catch (e) {
      setGateState(previousGateState);
      setLatestCommandStatus("failed");
      const code = e && e.status ? e.status : "?";
      setInlineError(`Команда не выполнена · код ${code}`);
      appendHistoryRow(`LOCAL-FAIL-${Date.now()}`, action, issuedBy, "failed", new Date().toISOString());
    } finally {
      setSubmitting(false);
    }
  }

  const visualState = unavailable && gateDeviceId
    ? "offline"
    : gateState;

  return (
    <div className="gate-panel" data-testid="hive-gate-panel">
      <div className="gate-panel__head">
        <div>
          <div className="gate-panel__title">Управление задвижкой</div>
          <div className="gate-panel__meta">
            Hive: <span className="id-mono">{hive.id}</span> · Device: <span className="id-mono">{gateDeviceId || "—"}</span>
          </div>
        </div>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          {GateBadge ? <GateBadge state={visualState} /> : <span className="status status--muted"><span className="dot"></span>{visualState}</span>}
          {latestCommandStatus ? gateCommandStatusBadge(latestCommandStatus) : null}
        </div>
      </div>

      <div className="gate-controls">
        <button
          className="btn btn--primary btn--sm"
          data-testid="gate-open-button"
          onClick={() => setConfirmAction("open")}
          disabled={unavailable || submitting}
        >
          <i className="ri-lock-unlock-line"></i>
          Открыть задвижку
        </button>
        <button
          className="btn btn--secondary btn--sm"
          data-testid="gate-close-button"
          onClick={() => setConfirmAction("close")}
          disabled={unavailable || submitting}
        >
          <i className="ri-lock-line"></i>
          Закрыть задвижку
        </button>
      </div>

      {!gateDeviceId && (
        <div className="gate-empty">Задвижка не назначена</div>
      )}

      {isUnavailableStatus(gateDeviceStatus) && (
        <div className="gate-warning" data-testid="gate-controls-unavailable">Устройство недоступно</div>
      )}
      {inlineError && (
        <div className="gate-error" data-testid="gate-command-error">{inlineError}</div>
      )}

      {/* [TASK_START:T007] */}
      <div className="gate-history">
        <div className="gate-history__title">Последние команды</div>
        {history.length === 0 ? (
          <div className="gate-history__empty">Команды ещё не отправлялись в текущей сессии</div>
        ) : (
          <table>
            <thead>
              <tr>
                <th>ID</th>
                <th>Действие</th>
                <th>Кем</th>
                <th>Время</th>
                <th>Статус</th>
              </tr>
            </thead>
            <tbody>
              {history.map((row) => (
                <tr key={row.id}>
                  <td className="id-mono">{row.id}</td>
                  <td>{row.action}</td>
                  <td>{row.actor}</td>
                  <td>{formatHiveCommandTs(row.at)}</td>
                  <td>{gateCommandStatusBadge(row.status)}</td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>
      {/* [TASK_COMPLETE:T007] */}

      <GateConfirmModal
        action={confirmAction}
        hiveId={hive?.id}
        gateDeviceId={gateDeviceId}
        onCancel={() => setConfirmAction(null)}
        onConfirm={() => execute(confirmAction)}
        loading={submitting}
      />
    </div>
  );
}
// [TASK_COMPLETE:T006]

function HiveDetail({ hiveId, onClose }) {
  const [hive, setHive] = React.useState(null);
  const [loading, setLoading] = React.useState(true);
  const [gateDeviceStatus, setGateDeviceStatus] = React.useState("ok");

  React.useEffect(() => {
    let cancelled = false;

    async function loadHive() {
      setLoading(true);
      setGateDeviceStatus("ok");

      let currentHive = null;
      try {
        currentHive = await Keeper.api.hive(hiveId);
      } catch (_) {
        currentHive = findHiveFallbackById(hiveId);
      }
      if (cancelled) return;
      setHive(currentHive);

      if (currentHive?.gate_device_id) {
        try {
          const gateDevice = await Keeper.api.device(currentHive.gate_device_id);
          if (!cancelled) {
            setGateDeviceStatus(gateDevice?.status || "ok");
          }
        } catch (_) {
          if (!cancelled) {
            setGateDeviceStatus(currentHive?.status || "ok");
          }
        }
      }

      if (!cancelled) setLoading(false);
    }

    if (hiveId) loadHive();
    else {
      setHive(null);
      setLoading(false);
    }

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

  if (!hiveId) return null;

  const stateClass = mapHiveStateClass(hive?.status);
  const title = hive?.name || `Улей ${hiveId}`;

  return (
    <div className="detail-panel">
      <div className="detail-head">
        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          <span className={`tri lg ${stateClass}`}></span>
          <div>
            <div style={{ font: "700 18px Inter", color: "var(--fg-strong)" }}>{title}</div>
            <div style={{ fontSize: 12, color: "var(--fg-muted)" }}>
              {hive?.zone_id ? `Зона ${hive.zone_id}` : "Зона —"}
              {hive?.station ? ` · ${hive.station}` : ""}
              {hive?.age_days != null ? ` · колония ${hive.age_days} дн.` : ""}
            </div>
          </div>
        </div>
        <button className="icon-btn" onClick={onClose}><i className="ri-close-line"></i></button>
      </div>

      <div className="detail-body">
        {loading && <div className="gate-history__empty">Загрузка данных улья…</div>}

        {!loading && !hive && (
          <div className="gate-history__empty">Не удалось загрузить данные улья</div>
        )}

        {!loading && !!hive && (
          <>
            <div className="metric-row">
              <div className="metric"><div className="metric-lbl">Активность</div><div className="metric-val">{hive.activity_per_min ?? "—"}<small> /мин</small></div></div>
              <div className="metric"><div className="metric-lbl">Возраст колонии</div><div className="metric-val">{hive.age_days ?? "—"}<small> дн.</small></div></div>
              <div className="metric"><div className="metric-lbl">Статус</div><div className="metric-val" style={{ fontSize: 18 }}>{String(hive.status || "ok").toUpperCase()}</div></div>
            </div>
            {/* [TASK_START:T008] */}
            {hive?.gate_device_id && (
              <HiveGateControl hive={hive} gateDeviceStatus={gateDeviceStatus} />
            )}
            {/* [TASK_COMPLETE:T008] */}
          </>
        )}
      </div>
    </div>
  );
}

window.HiveDetail = HiveDetail;
window.HiveGateControl = HiveGateControl;
