// Reseller/customer-facing Mission Control — the company-scoped mirror of
// admin's mission-control.jsx, styled to the neumorphic flat-UI design the
// customer approved (soft-UI light-grey cards, left icon rail, circular
// gauges) — see the approved reference image discussed with the customer.
// "leave as is current design but implement the changes" was the explicit
// go-ahead to build this real, functional page against that locked look.
//
// Deliberately NOT rendered inside <ResellerShell> — like admin's Mission
// Control, this is its own standalone full-page area with its own top bar
// and left icon rail (a narrow vertical icon-only rail here, matching the
// approved mock, rather than ResellerShell's wide labelled sidebar).
// Reached from ResellerShell's black/white "Mission Control" escape-hatch
// button (see RESELLER_MISSION_CONTROL_ENTRY_ID in reseller-shell.jsx) via
// onNavigate("reseller-mission-control").
//
// Data model per asset (GET /api/portal/mission-control/assets/:id — see
// routes/portal-mission-control.ts):
//   unit       — asset_units row (+ product/company names), company-scoped
//   telemetry  — unit_telemetry demo-data fallback (lib/telemetry.ts):
//                pv_power_w/pv_panel_voltage_v/pv_output_current_a (Solar),
//                mains_connected/mains_charging (Mains Power),
//                power_w/power_current_a/system_voltage_v (System Power
//                Draw), router_* fields (Router & Connectivity fallback).
//   victron    — { installation, devices[] } or null. devices[].device_role
//                shunt gives fields.SOC (battery %) when linked — real
//                vendor data always wins over demo telemetry, same
//                MC_pick() precedent as admin's mission-control.jsx.
//   ajax       — { hub, devices[] } or null. devices[] now carries a
//                `relay_config` (custom_label/schedule_enabled/schedule_json
//                — migrations/0027) for the Relay Control panel.
//   teltonika  — a single teltonika_devices row (router + GPS), or null.
//
// Relay Control: PUT /api/portal/mission-control/relays/:deviceId (label +
// schedule) and .../toggle (on/off) — new endpoints added alongside this
// page, see portal-mission-control.ts.

// ─────────────────────────── Neumorphic design tokens ───────────────────────────
const RMC_BG = "#e9edf3";
const RMC_TEXT = "#222b38";
const RMC_TEXT_DIM = "rgba(34,43,56,0.58)";
const RMC_TEXT_FAINT = "rgba(34,43,56,0.38)";
const RMC_ACCENT = "#3d7bfa";
const RMC_GREEN = "#22b573";
const RMC_AMBER = "#e0a339";
const RMC_SHADOW_RAISED = "8px 8px 18px rgba(163,177,198,0.55), -8px -8px 18px rgba(255,255,255,0.85)";
const RMC_SHADOW_RAISED_SM = "5px 5px 10px rgba(163,177,198,0.5), -5px -5px 10px rgba(255,255,255,0.85)";
const RMC_SHADOW_PRESSED = "inset 4px 4px 8px rgba(163,177,198,0.5), inset -4px -4px 8px rgba(255,255,255,0.75)";

function ResellerMissionControlPage({ onNavigate }) {
  const [state, setState] = useState({ status: "loading", user: null, company: null, fleet: [] });
  const [selectedAssetId, setSelectedAssetId] = useState(null);
  const [asset, setAsset] = useState({ status: "idle", data: null, error: "" });
  const [section, setSection] = useState("power");

  const loadFleet = () => {
    Promise.all([
      fetch("/api/portal/me", { credentials: "same-origin" }).then((r) => (r.ok ? r.json() : Promise.reject())),
      fetch("/api/portal/mission-control/fleet", { credentials: "same-origin" }).then((r) => (r.ok ? r.json() : Promise.reject())),
    ])
      .then(([me, fleetRes]) => {
        const fleet = fleetRes.fleet || [];
        setState({ status: "ready", user: me.user, company: me.company, fleet });
        if (fleet.length > 0) setSelectedAssetId(fleet[0].id);
      })
      .catch(() => onNavigate("reseller-login"));
  };

  useEffect(loadFleet, []); // eslint-disable-line react-hooks/exhaustive-deps

  const loadAsset = () => {
    if (selectedAssetId == null) return;
    setAsset({ status: "loading", data: null, error: "" });
    fetch(`/api/portal/mission-control/assets/${selectedAssetId}`, { credentials: "same-origin" })
      .then(async (r) => {
        const data = await r.json().catch(() => ({}));
        if (!r.ok) throw new Error(data.error || "Couldn't load this asset.");
        return data;
      })
      .then((data) => setAsset({ status: "ready", data, error: "" }))
      .catch((err) => setAsset({ status: "error", data: null, error: err.message }));
  };

  useEffect(loadAsset, [selectedAssetId]); // eslint-disable-line react-hooks/exhaustive-deps

  let body;
  if (state.status === "loading") {
    body = <RMC_EmptyNote>Loading&hellip;</RMC_EmptyNote>;
  } else if (state.fleet.length === 0) {
    body = <RMC_EmptyNote>No assets have been assigned to your company yet.</RMC_EmptyNote>;
  } else if (section !== "power") {
    body = <RMC_ComingSoon section={section} />;
  } else if (asset.status === "loading" || asset.status === "idle") {
    body = <RMC_EmptyNote>Loading tower&hellip;</RMC_EmptyNote>;
  } else if (asset.status === "error") {
    body = <RMC_EmptyNote>{asset.error}</RMC_EmptyNote>;
  } else {
    body = <RMC_Dashboard data={asset.data} onRefresh={loadAsset} />;
  }

  return (
    <RMC_Shell
      user={state.user}
      company={state.company}
      fleet={state.fleet}
      selectedAssetId={selectedAssetId}
      onSelectAsset={setSelectedAssetId}
      section={section}
      onSelectSection={setSection}
      onNavigate={onNavigate}
    >
      {body}
    </RMC_Shell>
  );
}

// ─────────────────────────────────── Shell ───────────────────────────────────

function RMC_Shell({ user, company, fleet, selectedAssetId, onSelectAsset, section, onSelectSection, onNavigate, children }) {
  const handleLogout = async () => {
    try { await fetch("/api/portal/logout", { method: "POST", credentials: "same-origin" }); }
    finally { onNavigate("home"); }
  };

  const railItems = [
    { id: "home", icon: IconHome, title: "Back to portal", action: () => onNavigate("portal-dashboard") },
    { id: "power", icon: IconLightningBolt, title: "Power" },
    { id: "map", icon: IconMapPin, title: "Live Location" },
    { id: "cameras", icon: IconCamera, title: "Cameras" },
    { id: "connectivity", icon: IconSignal, title: "Connectivity" },
    { id: "alerts", icon: IconBell, title: "Alerts" },
    { id: "settings", icon: IconSettings, title: "Settings", action: () => onNavigate("portal-settings") },
  ];

  return (
    <section style={{ background: RMC_BG, color: RMC_TEXT, minHeight: "calc(100vh - 88px)", display: "flex" }}>
      {/* Left icon rail */}
      <aside
        data-testid="rmc-icon-rail"
        style={{
          width: 76, flex: "0 0 76px", display: "flex", flexDirection: "column",
          alignItems: "center", gap: 14, padding: "26px 0", background: RMC_BG,
        }}
      >
        {railItems.map((item) => {
          const active = section === item.id;
          return (
            <button
              key={item.id} type="button" title={item.title}
              data-testid={`rmc-rail-${item.id}`}
              onClick={() => (item.action ? item.action() : onSelectSection(item.id))}
              style={{
                width: 44, height: 44, borderRadius: 14, border: "none", cursor: "pointer",
                background: RMC_BG, color: active ? RMC_ACCENT : RMC_TEXT_DIM,
                display: "flex", alignItems: "center", justifyContent: "center",
                boxShadow: active ? RMC_SHADOW_PRESSED : RMC_SHADOW_RAISED_SM,
                transition: "box-shadow 140ms, color 140ms",
              }}
            >
              <item.icon size={19} />
            </button>
          );
        })}
      </aside>

      <div style={{ flex: 1, minWidth: 0, padding: "26px 32px 80px", overflowX: "auto" }}>
        {/* Top header */}
        <div style={{
          display: "flex", justifyContent: "space-between", alignItems: "flex-start",
          flexWrap: "wrap", gap: 16, marginBottom: 24,
        }}>
          <div>
            <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
              <div style={{
                fontFamily: "var(--font-display)", fontWeight: 700, fontSize: 22,
                letterSpacing: "0.03em", textTransform: "uppercase", color: RMC_TEXT,
              }}>Mission Control</div>
              <span style={{
                display: "inline-flex", alignItems: "center", gap: 6,
                background: RMC_BG, boxShadow: RMC_SHADOW_RAISED_SM, borderRadius: 20,
                padding: "5px 12px", fontFamily: "var(--font-body)", fontSize: 10.5,
                fontWeight: 600, letterSpacing: "0.08em", textTransform: "uppercase", color: RMC_GREEN,
              }}>
                <IconPulse size={7} />
                Live
              </span>
            </div>
            {fleet.length > 0 && (
              <div style={{ marginTop: 6, display: "flex", alignItems: "center", gap: 10 }}>
                <select
                  value={selectedAssetId || ""}
                  onChange={(e) => onSelectAsset(Number(e.target.value))}
                  data-testid="rmc-asset-picker"
                  style={{
                    background: "transparent", border: "none", color: RMC_TEXT_DIM,
                    fontFamily: "var(--font-body)", fontSize: 13, cursor: "pointer", outline: "none",
                  }}
                >
                  {fleet.map((a) => (
                    <option key={a.id} value={a.id}>{a.serial_number} — {a.product_name}{a.region ? ` · ${a.region}` : ""}</option>
                  ))}
                </select>
              </div>
            )}
          </div>

          <div style={{ display: "flex", alignItems: "center", gap: 10 }}>
            {user && (
              <div style={{ textAlign: "right", marginRight: 4 }}>
                <div style={{ fontFamily: "var(--font-body)", fontSize: 12.5, color: RMC_TEXT, fontWeight: 600 }}>{user.name}</div>
                <div style={{ fontFamily: "var(--font-body)", fontSize: 11, color: RMC_TEXT_FAINT }}>{company && company.name}</div>
              </div>
            )}
            <button
              type="button" onClick={() => onNavigate("portal-dashboard")} data-testid="rmc-back-to-portal"
              style={{
                background: RMC_BG, border: "none", color: RMC_TEXT_DIM, cursor: "pointer",
                padding: "9px 16px", borderRadius: 12, boxShadow: RMC_SHADOW_RAISED_SM,
                fontFamily: "var(--font-body)", fontSize: 10.5, fontWeight: 600,
                letterSpacing: "0.08em", textTransform: "uppercase",
              }}
            >&larr; Portal</button>
            <button
              type="button" onClick={handleLogout} data-testid="rmc-logout"
              style={{
                background: RMC_BG, border: "none", color: RMC_TEXT_DIM, cursor: "pointer",
                padding: "9px 16px", borderRadius: 12, boxShadow: RMC_SHADOW_RAISED_SM,
                fontFamily: "var(--font-body)", fontSize: 10.5, fontWeight: 600,
                letterSpacing: "0.08em", textTransform: "uppercase",
              }}
            >Sign out</button>
          </div>
        </div>

        {children}
      </div>
    </section>
  );
}

// ────────────────────────────────── Dashboard ──────────────────────────────────

function RMC_Dashboard({ data, onRefresh }) {
  const { unit, telemetry, victron, ajax, teltonika } = data;

  const vDevices = (victron && victron.devices) || [];
  const findV = (role) => {
    const row = vDevices.find((d) => d.device_role === role);
    if (!row) return null;
    let fields = {};
    try { fields = JSON.parse(row.cached_fields_json || "{}"); } catch { /* ignore */ }
    return { row, fields };
  };
  const shunt = findV("shunt");
  const mppt1 = findV("mppt_1");
  const mppt2 = findV("mppt_2");

  const fmt = (n, dp) => (n === null || n === undefined ? "\u2014" : Number(n).toFixed(dp));

  // Solar — real Victron MPPT wins over demo PV telemetry.
  const solarW = mppt1 || mppt2
    ? [mppt1, mppt2].filter(Boolean).reduce((sum, m) => sum + (parseFloat(m.fields.ScW) || 0), 0)
    : telemetry.pv_power_w;
  const solarGenerating = mppt1 || mppt2 ? true : telemetry.pv_status === "generating";

  // Battery — Victron shunt SOC wins over the demo fuel-percent proxy.
  const batteryPercent = shunt && shunt.fields.SOC
    ? Math.round(parseFloat(shunt.fields.SOC))
    : Math.round(telemetry.pv_fuel_percent || 0);

  const mainsText = telemetry.mains_connected
    ? (telemetry.mains_charging ? "Connected — Charging" : "Connected — Not Charging")
    : "Disconnected";

  const ajaxDevices = (ajax && ajax.devices) || [];

  return (
    <div>
      {/* Row 1 — stat cards */}
      <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))", gap: 20, marginBottom: 20 }}>
        <RMC_StatCard
          testId="rmc-stat-solar"
          icon={<RMC_SunIcon />}
          label="Solar Power"
          value={`${fmt(solarW, 0)} W`}
          hint={solarGenerating ? "Generating" : "Standby"}
          hintTone={solarGenerating ? "green" : "dim"}
        />
        <RMC_BatteryCard percent={batteryPercent} />
        <RMC_StatCard
          testId="rmc-stat-draw"
          icon={<IconLightningBolt size={20} />}
          label="System Power Draw"
          value={`${fmt(telemetry.system_voltage_v, 1)}V | ${fmt(telemetry.power_current_a, 1)}A`}
          hint="Live draw"
          hintTone="dim"
        />
        <RMC_StatCard
          testId="rmc-stat-mains"
          icon={<RMC_PlugIcon />}
          label="Mains Power"
          value={mainsText}
          hint={telemetry.mains_connected ? "Plugged in" : "Not plugged in"}
          hintTone={telemetry.mains_connected ? "green" : "dim"}
        />
      </div>

      {/* Row 2 — map + router */}
      <div style={{ display: "grid", gridTemplateColumns: "1.2fr 1fr", gap: 20, marginBottom: 20 }}>
        {/* Live Location: real GPS (teltonika.latitude) wins when this
            router has a GPS antenna fitted and a live fix. Most
            fielded RUT241s don't -- verified live against a real
            customer router where RMS itself only ever reports a
            cell-tower-triangulated estimate via cell_tower_latitude/
            longitude (see migrations/0053_teltonika_cell_tower_
            location.sql). Falls back to that estimate with an
            "Approximate" badge + accuracy radius shown, and a link out
            to Google Maps since there's no in-app map widget here --
            never presented with the same confidence as a real fix. */}
        {(() => {
          const hasRealGps = teltonika && teltonika.latitude != null;
          const hasCellTower = teltonika && teltonika.cell_tower_latitude != null;
          const lat = hasRealGps ? teltonika.latitude : hasCellTower ? teltonika.cell_tower_latitude : null;
          const lng = hasRealGps ? teltonika.longitude : hasCellTower ? teltonika.cell_tower_longitude : null;
          return (
            <RMC_Panel
              title="Live Location"
              testId="rmc-panel-map"
              badge={hasRealGps ? { label: "GPS", tone: "green" } : hasCellTower ? { label: "Approximate" } : undefined}
            >
              {lat != null ? (
                <div>
                  <a
                    href={`https://www.google.com/maps/search/?api=1&query=${lat},${lng}`}
                    target="_blank" rel="noopener noreferrer"
                    style={{
                      height: 150, borderRadius: 14, background: RMC_BG, boxShadow: RMC_SHADOW_PRESSED,
                      display: "flex", alignItems: "center", justifyContent: "center", marginBottom: 12,
                      color: RMC_ACCENT, textDecoration: "none",
                    }}
                  >
                    <IconMapPin size={30} />
                  </a>
                  <RMC_Row label="Latitude" value={fmt(lat, 5)} />
                  <RMC_Row label="Longitude" value={fmt(lng, 5)} last={hasRealGps} />
                  {!hasRealGps && teltonika.cell_tower_accuracy != null && (
                    <RMC_Row label="Accuracy" value={`\u00b1${Math.round(teltonika.cell_tower_accuracy / 1000)} km`} last />
                  )}
                </div>
              ) : (
                <RMC_NotLinked hint="Link this asset's Teltonika router to see its live location." />
              )}
            </RMC_Panel>
          );
        })()}

        <RMC_Panel title="Router & Connectivity" testId="rmc-panel-router" badge={teltonika ? { label: teltonika.connection_state || "Live", tone: "green" } : undefined}>
          {teltonika ? (
            <>
              <RMC_Row label="Device" value={teltonika.name || "\u2014"} />
              <RMC_Row label="Operator" value={teltonika.operator || "\u2014"} />
              <RMC_Row label="Signal" value={teltonika.signal != null ? `${teltonika.signal}%` : "\u2014"} />
              <RMC_Row label="Firmware" value={teltonika.firmware || "\u2014"} last />
            </>
          ) : (
            <>
              <RMC_Row label="Operator" value={telemetry.router_operator || "\u2014"} />
              <RMC_Row label="Signal" value={telemetry.router_signal_percent != null ? `${fmt(telemetry.router_signal_percent, 0)}%` : "\u2014"} />
              <RMC_Row label="Firmware" value={telemetry.router_firmware || "\u2014"} last />
            </>
          )}
        </RMC_Panel>
      </div>

      {/* Row 3 — relay control */}
      <RMC_RelayPanel ajaxHub={ajax && ajax.hub} devices={ajaxDevices} onRefresh={onRefresh} />
    </div>
  );
}

// ─────────────────────────────── Stat cards ───────────────────────────────

function RMC_StatCard({ icon, label, value, hint, hintTone, testId }) {
  const tone = hintTone === "green" ? RMC_GREEN : RMC_TEXT_FAINT;
  return (
    <div data-testid={testId} style={{ background: RMC_BG, borderRadius: 20, boxShadow: RMC_SHADOW_RAISED, padding: "20px 20px 18px" }}>
      <div style={{
        width: 42, height: 42, borderRadius: 12, background: RMC_BG, boxShadow: RMC_SHADOW_PRESSED,
        display: "flex", alignItems: "center", justifyContent: "center", color: RMC_ACCENT, marginBottom: 14,
      }}>{icon}</div>
      <div style={{ fontFamily: "var(--font-body)", fontSize: 10.5, letterSpacing: "0.1em", textTransform: "uppercase", color: RMC_TEXT_FAINT, marginBottom: 6 }}>{label}</div>
      <div style={{ fontFamily: "var(--font-display)", fontWeight: 700, fontSize: 21, color: RMC_TEXT, marginBottom: 4 }}>{value}</div>
      <div style={{ fontFamily: "var(--font-body)", fontSize: 11.5, color: tone, fontWeight: 600 }}>{hint}</div>
    </div>
  );
}

function RMC_BatteryCard({ percent }) {
  const r = 26;
  const circumference = 2 * Math.PI * r;
  const offset = circumference * (1 - Math.min(Math.max(percent, 0), 100) / 100);
  return (
    <div data-testid="rmc-stat-battery" style={{ background: RMC_BG, borderRadius: 20, boxShadow: RMC_SHADOW_RAISED, padding: "20px 20px 18px", display: "flex", alignItems: "center", gap: 16 }}>
      <svg width={68} height={68} viewBox="0 0 68 68" style={{ flexShrink: 0 }}>
        <circle cx="34" cy="34" r={r} fill="none" stroke="rgba(163,177,198,0.35)" strokeWidth="6" />
        <circle
          cx="34" cy="34" r={r} fill="none" stroke={RMC_ACCENT} strokeWidth="6"
          strokeDasharray={circumference} strokeDashoffset={offset} strokeLinecap="round"
          transform="rotate(-90 34 34)"
        />
        <text x="34" y="38" textAnchor="middle" fontSize="14" fontWeight="700" fill={RMC_TEXT} fontFamily="var(--font-body)">{percent}%</text>
      </svg>
      <div>
        <div style={{ fontFamily: "var(--font-body)", fontSize: 10.5, letterSpacing: "0.1em", textTransform: "uppercase", color: RMC_TEXT_FAINT, marginBottom: 6 }}>Battery Level</div>
        <div style={{ fontFamily: "var(--font-display)", fontWeight: 700, fontSize: 21, color: RMC_TEXT }}>{percent}%</div>
      </div>
    </div>
  );
}

function RMC_SunIcon() {
  return (
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
      <circle cx="12" cy="12" r="4.2" />
      <path d="M12 2.5 v3 M12 18.5 v3 M2.5 12 h3 M18.5 12 h3 M5 5 l2.1 2.1 M16.9 16.9 L19 19 M19 5 l-2.1 2.1 M7.1 16.9 L5 19" />
    </svg>
  );
}

function RMC_PlugIcon() {
  return (
    <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round">
      <path d="M9 2.5 v5 M15 2.5 v5" />
      <path d="M6.5 7.5 h11 v4.5 a5.5 5.5 0 01-11 0 z" />
      <path d="M12 16.5 v5" />
    </svg>
  );
}

// ────────────────────────────────── Panels ──────────────────────────────────

function RMC_Panel({ title, badge, children, testId }) {
  return (
    <div data-testid={testId} style={{ background: RMC_BG, borderRadius: 20, boxShadow: RMC_SHADOW_RAISED, padding: "20px 22px 18px" }}>
      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 14 }}>
        <div style={{ fontFamily: "var(--font-body)", fontSize: 12, fontWeight: 700, letterSpacing: "0.05em", textTransform: "uppercase", color: RMC_TEXT }}>{title}</div>
        {badge && <RMC_Badge label={badge.label} tone={badge.tone} />}
      </div>
      {children}
    </div>
  );
}

function RMC_Badge({ label, tone }) {
  const color = tone === "green" ? RMC_GREEN : RMC_TEXT_FAINT;
  return (
    <span style={{
      fontFamily: "var(--font-body)", fontSize: 9.5, fontWeight: 700, letterSpacing: "0.06em",
      textTransform: "uppercase", color, background: RMC_BG, boxShadow: RMC_SHADOW_PRESSED,
      borderRadius: 10, padding: "3px 9px",
    }}>{label}</span>
  );
}

function RMC_Row({ label, value, last }) {
  return (
    <div style={{
      display: "flex", justifyContent: "space-between", gap: 12, padding: "7px 0",
      borderBottom: last ? "none" : "1px solid rgba(163,177,198,0.3)",
      fontFamily: "var(--font-body)", fontSize: 12.5,
    }}>
      <span style={{ color: RMC_TEXT_FAINT }}>{label}</span>
      <span style={{ color: RMC_TEXT, fontWeight: 600 }}>{value}</span>
    </div>
  );
}

function RMC_NotLinked({ hint }) {
  return <div style={{ fontFamily: "var(--font-body)", fontSize: 12, color: RMC_TEXT_FAINT, lineHeight: 1.5 }}>{hint}</div>;
}

function RMC_EmptyNote({ children }) {
  return <div style={{ fontFamily: "var(--font-body)", fontSize: 14, color: RMC_TEXT_DIM, padding: "40px 0" }}>{children}</div>;
}

function RMC_ComingSoon({ section }) {
  const labels = { map: "Live Location", cameras: "Cameras", connectivity: "Connectivity", alerts: "Alerts" };
  return (
    <div data-testid="rmc-coming-soon" style={{ background: RMC_BG, borderRadius: 20, boxShadow: RMC_SHADOW_RAISED, padding: "60px 32px", textAlign: "center" }}>
      <div style={{ fontFamily: "var(--font-body)", fontSize: 9.5, letterSpacing: "0.2em", textTransform: "uppercase", color: RMC_TEXT_FAINT, marginBottom: 12, fontWeight: 600 }}>Coming soon</div>
      <div style={{ fontFamily: "var(--font-display)", fontWeight: 700, fontSize: 19, textTransform: "uppercase", color: RMC_TEXT, marginBottom: 8 }}>{labels[section] || section}</div>
      <div style={{ fontFamily: "var(--font-body)", fontSize: 13, color: RMC_TEXT_DIM }}>This part of Mission Control hasn't been built yet — see the Power view for live tower data.</div>
    </div>
  );
}

// ────────────────────────────────── Relay panel ──────────────────────────────────

const RMC_DAYS = [
  { id: "mon", label: "Mon" }, { id: "tue", label: "Tue" }, { id: "wed", label: "Wed" },
  { id: "thu", label: "Thu" }, { id: "fri", label: "Fri" }, { id: "sat", label: "Sat" }, { id: "sun", label: "Sun" },
];

function RMC_RelayPanel({ ajaxHub, devices, onRefresh }) {
  if (!ajaxHub || devices.length === 0) {
    return (
      <RMC_Panel title="Relay Control" testId="rmc-panel-relays">
        <RMC_NotLinked hint="Link this asset's Ajax hub to control its relays (LEDs, reboot switches, etc.)." />
      </RMC_Panel>
    );
  }

  return (
    <RMC_Panel title="Relay Control" testId="rmc-panel-relays">
      <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
        {devices.map((d) => <RMC_RelayRow key={d.id} device={d} onRefresh={onRefresh} />)}
      </div>
    </RMC_Panel>
  );
}

function RMC_RelayRow({ device, onRefresh }) {
  const cfg = device.relay_config || {};
  let initialSchedule = [];
  try { initialSchedule = cfg.schedule_json ? JSON.parse(cfg.schedule_json) : []; } catch { initialSchedule = []; }

  let initialState = {};
  try { initialState = device.state_json ? JSON.parse(device.state_json) : {}; } catch { initialState = {}; }

  const [label, setLabel] = useState(cfg.custom_label || device.name || `Relay ${device.id}`);
  const [on, setOn] = useState(!!initialState.on);
  const [expanded, setExpanded] = useState(false);
  const [scheduleEnabled, setScheduleEnabled] = useState(!!cfg.schedule_enabled);
  const [schedule, setSchedule] = useState(initialSchedule);
  const [saving, setSaving] = useState(false);

  const saveConfig = (patch) => {
    setSaving(true);
    fetch(`/api/portal/mission-control/relays/${device.id}`, {
      method: "PUT", credentials: "same-origin",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({
        customLabel: label,
        scheduleEnabled,
        schedule,
        ...patch,
      }),
    })
      .then(() => setSaving(false))
      .catch(() => setSaving(false));
  };

  const handleToggle = () => {
    const next = !on;
    setOn(next);
    fetch(`/api/portal/mission-control/relays/${device.id}/toggle`, { method: "PUT", credentials: "same-origin" })
      .catch(() => setOn(!next));
  };

  const dayEntry = (dayId) => schedule.find((s) => s.day === dayId);
  const toggleDay = (dayId) => {
    const exists = dayEntry(dayId);
    const next = exists ? schedule.filter((s) => s.day !== dayId) : [...schedule, { day: dayId, on: "18:00", off: "06:00" }];
    setSchedule(next);
  };
  const updateDayTime = (dayId, field, value) => {
    setSchedule(schedule.map((s) => (s.day === dayId ? { ...s, [field]: value } : s)));
  };

  return (
    <div data-testid={`rmc-relay-row-${device.id}`} style={{ background: RMC_BG, borderRadius: 16, boxShadow: RMC_SHADOW_PRESSED, padding: "12px 16px" }}>
      <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
        <input
          value={label}
          onChange={(e) => setLabel(e.target.value)}
          onBlur={() => saveConfig({})}
          data-testid={`rmc-relay-label-${device.id}`}
          style={{
            flex: 1, minWidth: 0, background: "transparent", border: "none", outline: "none",
            fontFamily: "var(--font-body)", fontSize: 13.5, fontWeight: 600, color: RMC_TEXT,
          }}
        />
        <button
          type="button" title="Schedule" onClick={() => setExpanded(!expanded)}
          data-testid={`rmc-relay-schedule-btn-${device.id}`}
          style={{
            width: 32, height: 32, borderRadius: 10, border: "none", cursor: "pointer",
            background: RMC_BG, boxShadow: scheduleEnabled ? RMC_SHADOW_PRESSED : RMC_SHADOW_RAISED_SM,
            color: scheduleEnabled ? RMC_ACCENT : RMC_TEXT_FAINT,
            display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
          }}
        >
          <IconClock size={15} />
        </button>
        <RMC_Toggle checked={on} onChange={handleToggle} testId={`rmc-relay-toggle-${device.id}`} />
      </div>

      {expanded && (
        <div style={{ marginTop: 14, paddingTop: 14, borderTop: "1px solid rgba(163,177,198,0.3)" }}>
          <label style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 12, fontFamily: "var(--font-body)", fontSize: 12, color: RMC_TEXT_DIM, cursor: "pointer" }}>
            <input type="checkbox" checked={scheduleEnabled} onChange={(e) => setScheduleEnabled(e.target.checked)} />
            Enable schedule for this relay
          </label>
          <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
            {RMC_DAYS.map((day) => {
              const entry = dayEntry(day.id);
              return (
                <div key={day.id} style={{ display: "flex", alignItems: "center", gap: 10 }}>
                  <label style={{ display: "flex", alignItems: "center", gap: 6, width: 52, fontFamily: "var(--font-body)", fontSize: 12, color: RMC_TEXT_DIM, cursor: "pointer" }}>
                    <input type="checkbox" checked={!!entry} onChange={() => toggleDay(day.id)} />
                    {day.label}
                  </label>
                  {entry && (
                    <>
                      <input
                        type="time" value={entry.on}
                        onChange={(e) => updateDayTime(day.id, "on", e.target.value)}
                        style={{ background: RMC_BG, border: "none", boxShadow: RMC_SHADOW_PRESSED, borderRadius: 8, padding: "4px 8px", fontFamily: "var(--font-body)", fontSize: 11.5, color: RMC_TEXT }}
                      />
                      <span style={{ fontSize: 11, color: RMC_TEXT_FAINT }}>to</span>
                      <input
                        type="time" value={entry.off}
                        onChange={(e) => updateDayTime(day.id, "off", e.target.value)}
                        style={{ background: RMC_BG, border: "none", boxShadow: RMC_SHADOW_PRESSED, borderRadius: 8, padding: "4px 8px", fontFamily: "var(--font-body)", fontSize: 11.5, color: RMC_TEXT }}
                      />
                    </>
                  )}
                </div>
              );
            })}
          </div>
          <button
            type="button" onClick={() => saveConfig({})} disabled={saving}
            data-testid={`rmc-relay-save-schedule-${device.id}`}
            style={{
              marginTop: 14, background: RMC_ACCENT, border: "none", color: "#fff", cursor: "pointer",
              padding: "8px 16px", borderRadius: 10, fontFamily: "var(--font-body)", fontSize: 11.5,
              fontWeight: 600, letterSpacing: "0.05em", textTransform: "uppercase", opacity: saving ? 0.6 : 1,
            }}
          >{saving ? "Saving\u2026" : "Save schedule"}</button>
        </div>
      )}
    </div>
  );
}

function RMC_Toggle({ checked, onChange, testId }) {
  return (
    <button
      type="button" role="switch" aria-checked={checked} onClick={onChange} data-testid={testId}
      style={{
        width: 44, height: 24, borderRadius: 12, border: "none", cursor: "pointer", flexShrink: 0,
        background: checked ? RMC_ACCENT : RMC_BG,
        boxShadow: checked ? "none" : RMC_SHADOW_PRESSED,
        position: "relative", transition: "background 160ms",
      }}
    >
      <span style={{
        position: "absolute", top: 3, left: checked ? 23 : 3, width: 18, height: 18,
        borderRadius: "50%", background: "#fff", boxShadow: "0 1px 3px rgba(0,0,0,0.3)",
        transition: "left 160ms",
      }} />
    </button>
  );
}

Object.assign(window, { ResellerMissionControlPage });
