(() => {
  const { useState, useEffect, apiFetch, fmtDate, SC, runKey } = window.DC;
  const { IncidentPlaybook } = window.DCComponents;

  const OPS_TONE = {
    ok: SC.ok,
    ready: SC.ok,
    needs_configuration: "#fbbf24",
    error: SC.error,
    running: SC.running,
    idle: "#64748b",
  };

  const AUDIT_STATUS_TONE = {
    ok: SC.ok,
    denied: "#f43f5e",
    error: "#f43f5e",
    skipped: "#fbbf24",
  };

  const fmtBytes = (bytes) => {
    if (!Number.isFinite(bytes)) return "—";
    const units = ["B", "KB", "MB", "GB"];
    let value = bytes;
    let unitIndex = 0;

    while (value >= 1024 && unitIndex < units.length - 1) {
      value /= 1024;
      unitIndex += 1;
    }

    const decimals = value >= 10 || unitIndex === 0 ? 0 : 1;
    return `${value.toFixed(decimals)} ${units[unitIndex]}`;
  };

  const fmtAgo = (value) => {
    if (!value) return "—";
    const diffMs = Math.max(0, Date.now() - new Date(value).getTime());
    const diffMinutes = Math.floor(diffMs / 60000);

    if (diffMinutes < 1) return "hace <1 min";
    if (diffMinutes < 60) return `hace ${diffMinutes} min`;

    const diffHours = Math.floor(diffMinutes / 60);
    if (diffHours < 24) return `hace ${diffHours} h`;

    const diffDays = Math.floor(diffHours / 24);
    return `hace ${diffDays} d`;
  };

  const fmtDeletedSummary = (deleted) => {
    if (!deleted || typeof deleted !== "object") return "Sin datos";
    return Object.entries(deleted)
      .map(([key, value]) => `${key}: ${value}`)
      .join(" • ");
  };

  function StatusPill({ children, tone = "#64748b" }) {
    return (
      <span
        className="tag"
        style={{
          borderColor: `${tone}55`,
          color: tone,
          background: `${tone}15`,
        }}
      >
        {children}
      </span>
    );
  }

  function OpsMetricCard({ label, value, tone = "#e2e8f0", meta }) {
    return (
      <div className="ops-panel" style={{ minHeight: 92 }}>
        <div style={{ color: "#64748b", fontSize: 11, marginBottom: 8, letterSpacing: "1px", textTransform: "uppercase", fontWeight: 700 }}>
          {label}
        </div>
        <div style={{ fontFamily: "Syne,sans-serif", fontWeight: 800, fontSize: 22, color: tone, marginBottom: 6 }}>
          {value}
        </div>
        {meta && <div style={{ fontSize: 11, color: "#94a3b8", lineHeight: 1.5 }}>{meta}</div>}
      </div>
    );
  }

  function OpsTabs({ tabs, activeTab, onChange }) {
    return (
      <div className="card" style={{ marginBottom: 14 }}>
        <div className="card-body" style={{ padding: 12 }}>
          <div className="nav-tabs-wrap settings-tabs-wrap internal-tabs-wrap">
            <div className="nav-tabs settings-tabs internal-tabs">
              {tabs.map((tab) => (
                <button
                  key={tab.key}
                  type="button"
                  onClick={() => onChange(tab.key)}
                  className={`nav-tab${activeTab === tab.key ? " active" : ""}`}
                  title={tab.label}
                >
                  <span className="nav-tab-icon" aria-hidden="true">{tab.icon}</span>
                  <span className="nav-tab-text">{tab.label}</span>
                </button>
              ))}
            </div>
          </div>
        </div>
      </div>
    );
  }

  function OperationsCard({ toast }) {
    const [overview, setOverview] = useState(null);
    const [loading, setLoading] = useState(false);
    const [runningAction, setRunningAction] = useState("");
    const [selectedServerId, setSelectedServerId] = useState("");

    const loadOverview = async (silent = false) => {
      if (!silent) setLoading(true);
      try {
        const response = await apiFetch("/ops/overview");
        if (response?.error) {
          toast(response.error || "No se pudo cargar el centro operativo", "err");
        } else if (response) {
          setOverview(response);
        }
      } catch (error) {
        toast(`No se pudo cargar el centro operativo: ${error?.message || error}`, "err");
      } finally {
        if (!silent) setLoading(false);
      }
    };

    useEffect(() => {
      loadOverview();
      const intervalId = setInterval(() => loadOverview(true), 30000);
      return () => clearInterval(intervalId);
    }, []);

    useEffect(() => {
      if (!selectedServerId && overview?.servers?.length) {
        setSelectedServerId(String(overview.servers[0]?.id));
      }
    }, [overview, selectedServerId]);

    const runSchedulerAction = async (actionKey, path, successMessage) => {
      setRunningAction(runKey.scheduler(actionKey));
      try {
        const response = await apiFetch(path, { method: "POST" });
        if (response?.error) {
          toast(response.error, "err");
        } else if (response?.result?.skipped) {
          toast(response.result.reason === "scheduler_disabled" ? "El scheduler está desactivado" : "Ya hay una ejecución en curso", "err");
        } else {
          toast(successMessage);
        }
        await loadOverview(true);
      } catch (error) {
        toast(`Error: ${error?.message || error}`, "err");
      } finally {
        setRunningAction("");
      }
    };

    const runBackup = async () => {
      setRunningAction(runKey.simple("backup"));
      try {
        const response = await apiFetch("/ops/backup", { method: "POST" });
        if (response?.error) toast(response.error, "err");
        else toast("Backup generado");
        await loadOverview(true);
      } catch (error) {
        toast(`Error: ${error?.message || error}`, "err");
      } finally {
        setRunningAction("");
      }
    };

    const runBackupVerification = async (backupName = "") => {
      setRunningAction(runKey.simple("backup-verify"));
      try {
        const response = await apiFetch("/ops/backup/verify", {
          method: "POST",
          body: backupName ? { name: backupName } : {},
        });
        if (response?.error) toast(response.error, "err");
        else toast(`Backup verificado: ${response?.result?.name || "último backup"}`);
        await loadOverview(true);
      } catch (error) {
        toast(`Error: ${error?.message || error}`, "err");
      } finally {
        setRunningAction("");
      }
    };

    const runMaintenance = async () => {
      setRunningAction(runKey.simple("maintenance"));
      try {
        const response = await apiFetch("/ops/maintenance/run", { method: "POST" });
        if (response?.error) toast(response.error, "err");
        else toast("Mantenimiento ejecutado");
        await loadOverview(true);
      } catch (error) {
        toast(`Error: ${error?.message || error}`, "err");
      } finally {
        setRunningAction("");
      }
    };

    const runIncidentAction = async (incidentId, actionKey, successMessage) => {
      setRunningAction(runKey.incident(actionKey, incidentId));
      try {
        const response = await apiFetch(`/incidents/${incidentId}/${actionKey}`, {
          method: "POST",
          body: actionKey === "resolve" ? { reason: "resolved_from_ops" } : {},
        });
        if (response?.error) toast(response.error, "err");
        else toast(successMessage);
        await loadOverview(true);
      } catch (error) {
        toast(`Error al ejecutar ${actionKey}: ${error?.message || error}`, "err");
      } finally {
        setRunningAction("");
      }
    };

    const runRunbook = async (actionKey, incidentId = null, serverIdOverride = null) => {
      const targetServerId = serverIdOverride || selectedServerId;
      if (!targetServerId) {
        toast("Selecciona un servidor para ejecutar el runbook", "err");
        return;
      }

      setRunningAction(runKey.runbook(actionKey, targetServerId));
      try {
        const response = await apiFetch(`/ops/runbooks/${actionKey}`, {
          method: "POST",
          body: {
            server_id: Number(targetServerId),
            ...(incidentId ? { incident_id: incidentId } : {}),
          },
        });
        if (response?.error) toast(response.error, "err");
        else toast(`Runbook ejecutado: ${actionKey}`);
        await loadOverview(true);
      } catch (error) {
        toast(`Error al ejecutar runbook ${actionKey}: ${error?.message || error}`, "err");
      } finally {
        setRunningAction("");
      }
    };

    const health = overview?.health;
    const scheduler = health?.scheduler || {};
    const incidents = overview?.incidents || health?.incidents || { recent: [] };
    const jobs = overview?.jobs || health?.jobs || {};
    const backups = overview?.backups || {};
    const maintenance = overview?.maintenance || health?.maintenance || {};
    const maintenanceRuns = overview?.maintenance_runs || [];
    const remediationRuns = overview?.remediation_runs || health?.remediations || [];
    const runbooks = overview?.runbooks || [];
    const opsServers = overview?.servers || [];
    const warnings = health?.warnings || [];
    const latestBackup = backups.items?.[0];
    const backupVerification = backups.verification || {};
    const latestBackupVerification = backupVerification.latest_run || null;
    const lastMaintenance = maintenance.last_successful_run || maintenance.last_run;
    const counts = health?.counts || {};
    const alertChannels = health?.alert_channels || { configured_channels: [] };
    const automation = overview?.automation || health?.automation || {};
    const busy = Boolean(runningAction);

    return (
      <div className="card">
        <div className="card-head">
          <span>🛟 Centro operativo</span>
          <div className="ops-toolbar">
            <StatusPill tone={automation.enabled ? OPS_TONE.ok : "#fbbf24"}>
              Auto-remediación: {automation.enabled ? "activa" : "desactivada"}
            </StatusPill>
            <button onClick={() => loadOverview()} disabled={loading || busy} className="btn btn-ghost btn-sm">
              {loading ? "Cargando..." : "Actualizar"}
            </button>
          </div>
        </div>
        <div className="card-body">
          <div className="alert alert-info" style={{ marginBottom: 14 }}>
            Resumen operativo, runbooks y actividad del sistema para reaccionar rápido sin depender siempre de SSH.
          </div>

          {!overview && loading && <div style={{ color: "#94a3b8", fontSize: 12 }}>Cargando estado operativo...</div>}

          {overview && (
            <>
              <div className="ops-metrics-grid">
                <OpsMetricCard
                  label="Aplicación"
                  value={health.status === "ok" ? "OK" : "ERROR"}
                  tone={OPS_TONE[health.status] || "#e2e8f0"}
                  meta={`Setup: ${health.setup_status === "ready" ? "listo" : "requiere revisión"}`}
                />
                <OpsMetricCard
                  label="Scheduler"
                  value={scheduler.started ? "Activo" : "Pausado"}
                  tone={scheduler.started ? OPS_TONE.running : OPS_TONE.idle}
                  meta={scheduler.last_metrics_run_at ? `Último barrido: ${fmtAgo(scheduler.last_metrics_run_at)}` : "Aún sin barridos"}
                />
                <OpsMetricCard
                  label="Backups"
                  value={String(backups.total_count || 0)}
                  tone={latestBackup ? OPS_TONE.ok : "#fbbf24"}
                  meta={latestBackupVerification ? `Verificado: ${fmtAgo(latestBackupVerification.finished_at || latestBackupVerification.started_at)}` : latestBackup ? `Último: ${fmtAgo(latestBackup.updated_at)}` : "Sin backups todavía"}
                />
                <OpsMetricCard
                  label="Incidentes"
                  value={`${incidents.active_total || 0}`}
                  tone={incidents.critical_total ? SC.error : incidents.active_total ? "#fbbf24" : OPS_TONE.ok}
                  meta={`${incidents.critical_total || 0} críticos · ${incidents.acknowledged_total || 0} reconocidos`}
                />
                <OpsMetricCard
                  label="Jobs"
                  value={`${jobs.running || 0}`}
                  tone={jobs.running ? OPS_TONE.running : jobs.failed_24h ? SC.error : OPS_TONE.ok}
                  meta={`${jobs.failed_24h || 0} con error en 24h`}
                />
                <OpsMetricCard
                  label="Auto-remediación"
                  value={automation.enabled ? "Activa" : "Manual"}
                  tone={automation.enabled ? OPS_TONE.ok : "#fbbf24"}
                  meta={`${automation.active_critical_incidents || 0} incidentes críticos a vigilar`}
                />
                <OpsMetricCard
                  label="Mantenimiento"
                  value={lastMaintenance ? fmtAgo(lastMaintenance.finished_at || lastMaintenance.started_at) : "Nunca"}
                  tone={maintenance.running ? OPS_TONE.running : lastMaintenance?.status === "error" ? SC.error : "#e2e8f0"}
                  meta={maintenance.running ? "Limpieza en curso" : `Último estado: ${lastMaintenance?.status || "sin ejecuciones"}`}
                />
              </div>

              <div className="ops-pill-row">
                <StatusPill tone={OPS_TONE[health.status] || "#64748b"}>Estado: {health.status}</StatusPill>
                <StatusPill tone={OPS_TONE[health.setup_status] || "#64748b"}>Setup: {health.setup_status}</StatusPill>
                <StatusPill tone={scheduler.enabled ? OPS_TONE.running : "#64748b"}>Scheduler: {scheduler.enabled ? "habilitado" : "deshabilitado"}</StatusPill>
                <StatusPill tone={backups.running ? OPS_TONE.running : "#64748b"}>Backup: {backups.running ? "en progreso" : "idle"}</StatusPill>
                <StatusPill tone={alertChannels.configured_channels?.length ? OPS_TONE.ok : "#fbbf24"}>
                  Alertas: {alertChannels.configured_channels?.length ? alertChannels.configured_channels.join(", ") : "sin canales"}
                </StatusPill>
                <StatusPill tone={maintenance.running ? OPS_TONE.running : "#64748b"}>Mantenimiento: {maintenance.running ? "en progreso" : "idle"}</StatusPill>
              </div>

              {warnings.length > 0 ? (
                <div className="alert alert-warn" style={{ marginBottom: 14 }}>
                  <div style={{ fontWeight: 700, marginBottom: 6 }}>Advertencias operativas</div>
                  <div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
                    {warnings.slice(0, 6).map((warning, index) => (
                      <div key={`${warning}-${index}`}>• {warning}</div>
                    ))}
                  </div>
                </div>
              ) : (
                <div className="alert alert-success" style={{ marginBottom: 14 }}>
                  Sin advertencias operativas críticas en este momento.
                </div>
              )}

              <div className="ops-action-row" style={{ marginBottom: 14 }}>
                <button onClick={() => runSchedulerAction("metrics", "/monitor/scheduler/metrics", "Barrido de métricas ejecutado")} disabled={busy} className="btn btn-primary">
                  {runningAction === runKey.scheduler("metrics") ? "Ejecutando métricas..." : "Barrer métricas"}
                </button>
                <button onClick={() => runSchedulerAction("sites", "/monitor/scheduler/sites", "Verificación de sitios ejecutada")} disabled={busy} className="btn btn-secondary">
                  {runningAction === runKey.scheduler("sites") ? "Verificando sitios..." : "Verificar sitios"}
                </button>
                <button onClick={runBackup} disabled={busy} className="btn btn-green">
                  {runningAction === runKey.simple("backup") ? "Creando backup..." : "Crear backup ahora"}
                </button>
                <button onClick={() => runBackupVerification()} disabled={busy || !latestBackup} className="btn btn-ghost">
                  {runningAction === runKey.simple("backup-verify") ? "Verificando backup..." : "Verificar backup"}
                </button>
                <button onClick={runMaintenance} disabled={busy} className="btn btn-ghost">
                  {runningAction === runKey.simple("maintenance") ? "Limpiando..." : "Ejecutar limpieza"}
                </button>
              </div>

              <div className="ops-duo-grid">
                <div className="ops-panel">
                  <div className="ops-section-title">Scheduler</div>
                  <div className="ops-meta-stack">
                    <div>Próximo barrido de métricas: <strong>{scheduler.next_metrics_run_at ? fmtDate(scheduler.next_metrics_run_at) : "—"}</strong></div>
                    <div>Próxima verificación de sitios: <strong>{scheduler.next_sites_run_at ? fmtDate(scheduler.next_sites_run_at) : "—"}</strong></div>
                    <div>Último resultado métricas: <strong>{scheduler.last_metrics_summary ? `${scheduler.last_metrics_summary.ok || 0} ok / ${scheduler.last_metrics_summary.errors || 0} errores` : "—"}</strong></div>
                    <div>Último resultado sitios: <strong>{scheduler.last_sites_summary ? `${scheduler.last_sites_summary.checked_sites || 0} sitios / ${scheduler.last_sites_summary.degraded_sites || 0} degradados` : "—"}</strong></div>
                  </div>
                </div>

                <div className="ops-panel">
                  <div className="ops-section-title">Backups recientes</div>
                  <div style={{ fontSize: 11, color: "#94a3b8", marginBottom: 10 }}>
                    Restauración verificada: <strong style={{ color: latestBackupVerification?.status === "error" ? SC.error : "#e2e8f0" }}>
                      {latestBackupVerification ? `${latestBackupVerification.status} · ${fmtAgo(latestBackupVerification.finished_at || latestBackupVerification.started_at)}` : "sin verificación"}
                    </strong>
                  </div>
                  {backups.items?.length ? (
                    <div className="ops-list">
                      {backups.items.slice(0, 5).map((item) => (
                        <div key={item.name} className="ops-row-item">
                          <div style={{ minWidth: 0 }}>
                            <div style={{ fontSize: 12, fontWeight: 700, color: "#e2e8f0", wordBreak: "break-all" }}>{item.name}</div>
                            <div style={{ fontSize: 11, color: "#64748b" }}>{fmtDate(item.updated_at)} • {fmtAgo(item.updated_at)}</div>
                          </div>
                          <div className="ops-inline-actions">
                            <div style={{ fontSize: 11, color: "#94a3b8", whiteSpace: "nowrap" }}>{fmtBytes(item.size_bytes)}</div>
                            <button onClick={() => runBackupVerification(item.name)} disabled={busy} className="btn btn-ghost btn-xs">
                              {runningAction === runKey.simple("backup-verify") ? "..." : "verificar"}
                            </button>
                          </div>
                        </div>
                      ))}
                    </div>
                  ) : (
                    <div style={{ fontSize: 12, color: "#94a3b8" }}>Aún no hay backups disponibles.</div>
                  )}
                </div>
              </div>

              <div className="ops-duo-grid">
                <div className="ops-panel">
                  <div className="ops-section-title">Mantenimiento</div>
                  <div className="ops-meta-stack">
                    <div>Última ejecución: <strong>{lastMaintenance ? fmtDate(lastMaintenance.finished_at || lastMaintenance.started_at) : "—"}</strong></div>
                    <div>Estado: <strong>{lastMaintenance?.status || "sin datos"}</strong></div>
                    <div>Registros limpiados: <strong>{lastMaintenance?.summary?.total_deleted ?? "—"}</strong></div>
                    <div style={{ color: "#94a3b8" }}>{lastMaintenance?.summary ? fmtDeletedSummary(lastMaintenance.summary.deleted) : "Todavía no hay limpiezas registradas."}</div>
                  </div>
                </div>

                <div className="ops-panel">
                  <div className="ops-section-title">Retención</div>
                  <div className="ops-meta-stack">
                    <div>Auditoría: <strong>{maintenance.retention?.audit_logs_days ?? "—"} días</strong></div>
                    <div>Alertas monitor: <strong>{maintenance.retention?.monitor_alerts_days ?? "—"} días</strong></div>
                    <div>Snapshots monitor: <strong>{maintenance.retention?.monitor_snapshots_days ?? "—"} días</strong></div>
                    <div>Checks de sitios: <strong>{maintenance.retention?.monitor_site_checks_days ?? "—"} días</strong></div>
                  </div>
                </div>
              </div>

              {maintenanceRuns.length > 0 && (
                <div className="ops-panel" style={{ marginTop: 12 }}>
                  <div className="ops-section-title">Historial de mantenimiento</div>
                  <div className="ops-list">
                    {maintenanceRuns.slice(0, 4).map((run) => (
                      <div key={run.id} className="ops-row-item">
                        <div>
                          <div style={{ fontSize: 12, fontWeight: 700, color: "#e2e8f0" }}>#{run.id} • {run.trigger}</div>
                          <div style={{ fontSize: 11, color: "#94a3b8" }}>{fmtDate(run.started_at)} • {fmtDeletedSummary(run.summary?.deleted)}</div>
                        </div>
                        <StatusPill tone={AUDIT_STATUS_TONE[run.status] || "#64748b"}>{run.status}</StatusPill>
                      </div>
                    ))}
                  </div>
                </div>
              )}

              <div className="ops-split-grid">
                <div className="ops-panel">
                  <div className="ops-section-title">Incidentes activos</div>
                  {incidents.recent?.length ? (
                    <div className="ops-list">
                      {incidents.recent.slice(0, 6).map((incident) => (
                        <div key={incident.id} className="ops-mini-panel">
                          <div className="ops-row-head">
                            <div style={{ fontSize: 13, fontWeight: 700, color: "#e2e8f0" }}>{incident.title}</div>
                            <div className="ops-inline-actions">
                              <StatusPill tone={incident.severity === "critical" ? SC.error : "#fbbf24"}>{incident.severity}</StatusPill>
                              <StatusPill tone={incident.status === "acknowledged" ? "#fbbf24" : incident.status === "in_progress" ? SC.running : "#64748b"}>{incident.status}</StatusPill>
                            </div>
                          </div>
                          <div style={{ fontSize: 12, color: "#cbd5e1", marginBottom: 6 }}>{incident.summary || "Sin resumen"}</div>
                          <div style={{ display: "flex", gap: 10, flexWrap: "wrap", fontSize: 11, color: "#94a3b8" }}>
                            <span>Servidor: <strong style={{ color: "#e2e8f0" }}>{incident.server_label || "global"}</strong></span>
                            <span>Última vez: <strong style={{ color: "#e2e8f0" }}>{fmtAgo(incident.last_seen_at)}</strong></span>
                          </div>
                          <IncidentPlaybook
                            incident={incident}
                            runningAction={runningAction}
                            busy={busy}
                            onRunIncidentAction={runIncidentAction}
                            onRunRunbook={(serverId, actionKey, incidentId) => {
                              if (serverId) setSelectedServerId(String(serverId));
                              runRunbook(actionKey, incidentId, serverId ? String(serverId) : null);
                            }}
                          />
                        </div>
                      ))}
                    </div>
                  ) : (
                    <div style={{ fontSize: 12, color: "#94a3b8" }}>Sin incidentes activos en este momento.</div>
                  )}
                </div>

                <div className="ops-stack">
                  <div className="ops-panel">
                    <div className="ops-section-title">Runbooks remotos</div>
                    <div className="field" style={{ marginBottom: 10 }}>
                      <label>Servidor objetivo</label>
                      <select value={selectedServerId} onChange={(event) => setSelectedServerId(event.target.value)} className="input">
                        <option value="">Selecciona un servidor</option>
                        {opsServers.map((server) => (
                          <option key={server.id} value={server.id}>
                            {server.label} · {server.host}
                          </option>
                        ))}
                      </select>
                    </div>
                    <div className="ops-stack">
                      {runbooks.map((runbook) => (
                        <button
                          key={runbook.key}
                          onClick={() => runRunbook(runbook.key)}
                          disabled={busy || !selectedServerId}
                          className="btn btn-ghost"
                          style={{ justifyContent: "space-between", textAlign: "left" }}
                        >
                          <span>{runbook.label}</span>
                          <span style={{ fontSize: 10, color: "#94a3b8" }}>{runningAction === runKey.runbook(runbook.key, selectedServerId) ? "ejecutando..." : "run"}</span>
                        </button>
                      ))}
                    </div>
                  </div>

                  <div className="ops-panel">
                    <div className="ops-section-title">Jobs y remediaciones</div>
                    <div className="ops-list">
                      {(overview?.recent_jobs || []).slice(0, 4).map((job) => (
                        <div key={`job-${job.id}`} className="ops-row-item">
                          <div>
                            <div style={{ fontSize: 12, fontWeight: 700, color: "#e2e8f0" }}>{job.job_type}</div>
                            <div style={{ fontSize: 11, color: "#94a3b8" }}>{job.trigger} • {fmtDate(job.started_at)}</div>
                          </div>
                          <StatusPill tone={job.status === "error" ? SC.error : job.status === "running" ? SC.running : SC.ok}>{job.status}</StatusPill>
                        </div>
                      ))}
                      {remediationRuns.slice(0, 4).map((run) => (
                        <div key={`rem-${run.id}`} className="ops-row-item">
                          <div>
                            <div style={{ fontSize: 12, fontWeight: 700, color: "#e2e8f0" }}>{run.action_key}</div>
                            <div style={{ fontSize: 11, color: "#94a3b8" }}>{run.server_label || run.target_label || "—"} • {fmtDate(run.started_at)}</div>
                          </div>
                          <StatusPill tone={run.status === "error" ? SC.error : run.status === "running" ? SC.running : SC.ok}>{run.status}</StatusPill>
                        </div>
                      ))}
                      {(overview?.recent_jobs || []).length === 0 && remediationRuns.length === 0 && (
                        <div style={{ fontSize: 12, color: "#94a3b8" }}>Aún no hay jobs ni remediaciones registradas.</div>
                      )}
                    </div>
                  </div>
                </div>
              </div>
            </>
          )}
        </div>
      </div>
    );
  }

  function AutomationCard({ toast }) {
    const [data, setData] = useState(null);
    const [loading, setLoading] = useState(false);
    const [saving, setSaving] = useState(false);
    const [running, setRunning] = useState(false);
    const [form, setForm] = useState({
      enabled: false,
      service_restart_enabled: true,
      site_reload_enabled: true,
      verify_after_action: true,
      cooldown_sec: 900,
      max_actions_per_sweep: 3,
    });

    const load = async (silent = false) => {
      if (!silent) setLoading(true);
      const response = await apiFetch("/ops/automation");
      if (response.error) {
        toast(response.error || "No se pudo cargar la automatización", "err");
      } else {
        setData(response);
        // Solo hidratamos el formulario en la carga inicial / tras guardar. En el
        // poll silencioso (cada 30s) NO lo tocamos: antes pisaba las ediciones sin
        // guardar mientras el usuario configuraba la auto-remediación.
        if (!silent) {
          setForm({
            enabled: Boolean(response.enabled),
            service_restart_enabled: Boolean(response.service_restart_enabled),
            site_reload_enabled: Boolean(response.site_reload_enabled),
            verify_after_action: Boolean(response.verify_after_action),
            cooldown_sec: response.cooldown_sec || 900,
            max_actions_per_sweep: response.max_actions_per_sweep || 3,
          });
        }
      }
      if (!silent) setLoading(false);
    };

    useEffect(() => {
      load();
      const intervalId = setInterval(() => load(true), 30000);
      return () => clearInterval(intervalId);
    }, []);

    const save = async () => {
      setSaving(true);
      const response = await apiFetch("/ops/automation", {
        method: "PUT",
        body: form,
      });
      if (response.error) {
        toast(response.error, "err");
      } else {
        toast("Auto-remediación actualizada");
        setData(response.settings || response);
      }
      setSaving(false);
      await load(true);
    };

    const runNow = async () => {
      setRunning(true);
      const response = await apiFetch("/ops/automation/run", { method: "POST" });
      if (response.error) {
        toast(response.error, "err");
      } else if (response.result?.skipped) {
        toast(response.result.reason === "disabled" ? "La auto-remediación está desactivada" : "Ya hay una ejecución automática en curso", "err");
      } else {
        toast(`Evaluación automática completada: ${response.result?.attempted || 0} intento(s)`);
      }
      setRunning(false);
      await load(true);
    };

    const latestJob = data?.latest_job;
    const recentRuns = data?.recent_runs || [];

    return (
      <div className="card">
        <div className="card-head">
          <span>🤖 Auto-remediación</span>
          <div className="ops-toolbar">
            <StatusPill tone={form.enabled ? SC.ok : "#fbbf24"}>
              {form.enabled ? "activa" : "manual"}
            </StatusPill>
            <button onClick={() => load()} disabled={loading || saving || running} className="btn btn-ghost btn-sm">
              {loading ? "Cargando..." : "Actualizar"}
            </button>
          </div>
        </div>
        <div className="card-body">
          <div className="alert alert-info" style={{ marginBottom: 14 }}>
            Ejecuta acciones seguras ante incidentes críticos compatibles, con cooldown, verificación posterior y registro completo en auditoría.
          </div>

          <div className="ops-duo-grid">
            <div className="ops-panel">
              <div className="ops-section-title">Política automática</div>
              <div className="ops-toggle-list">
                {[
                  ["enabled", "Activar auto-remediación", "Permite que el scheduler ejecute acciones seguras sin intervención manual."],
                  ["service_restart_enabled", "Reiniciar servicios", "Apache, PHP-FPM y MariaDB cuando el monitor los detecte inactivos."],
                  ["site_reload_enabled", "Recargar stack web", "Aplica recarga web para caídas críticas de sitios con DNS disponible."],
                  ["verify_after_action", "Verificar después de actuar", "Vuelve a medir métricas o sitios para confirmar si mejoró."],
                ].map(([key, title, description]) => (
                  <label key={key} className="ops-toggle-item">
                    <div>
                      <div style={{ color: "#e2e8f0", fontSize: 12, fontWeight: 700 }}>{title}</div>
                      <div style={{ color: "#94a3b8", fontSize: 11, lineHeight: 1.5 }}>{description}</div>
                    </div>
                    <input
                      type="checkbox"
                      checked={Boolean(form[key])}
                      onChange={(event) => setForm((prev) => ({ ...prev, [key]: event.target.checked }))}
                    />
                  </label>
                ))}
              </div>
            </div>

            <div className="ops-panel">
              <div className="ops-section-title">Límites y control</div>
              <div className="grid-2" style={{ marginBottom: 14 }}>
                <div className="field">
                  <label>Cooldown entre acciones (seg)</label>
                  <input
                    type="number"
                    value={form.cooldown_sec}
                    onChange={(event) => setForm((prev) => ({ ...prev, cooldown_sec: event.target.value }))}
                    className="input"
                    min="60"
                    max="86400"
                  />
                </div>
                <div className="field">
                  <label>Máximo por barrido</label>
                  <input
                    type="number"
                    value={form.max_actions_per_sweep}
                    onChange={(event) => setForm((prev) => ({ ...prev, max_actions_per_sweep: event.target.value }))}
                    className="input"
                    min="1"
                    max="20"
                  />
                </div>
              </div>
              <div className="ops-meta-stack" style={{ marginBottom: 14 }}>
                <div>Incidentes críticos activos: <strong>{data?.active_critical_incidents ?? "—"}</strong></div>
                <div>Última corrida: <strong>{latestJob ? `${latestJob.status} · ${fmtAgo(latestJob.finished_at || latestJob.started_at)}` : "sin ejecuciones"}</strong></div>
              </div>
              <div className="ops-action-row">
                <button onClick={save} disabled={saving || running} className="btn btn-primary">
                  {saving ? "Guardando..." : "Guardar política"}
                </button>
                <button onClick={runNow} disabled={saving || running} className="btn btn-secondary">
                  {running ? "Ejecutando..." : "Ejecutar ahora"}
                </button>
              </div>
            </div>
          </div>

          <div className="ops-triptych">
            <div className="ops-panel">
              <div className="ops-section-title">Último job automático</div>
              {latestJob ? (
                <div className="ops-meta-stack">
                  <div>Estado: <strong>{latestJob.status}</strong></div>
                  <div>Trigger: <strong>{latestJob.trigger}</strong></div>
                  <div>Inicio: <strong>{fmtDate(latestJob.started_at)}</strong></div>
                  <div>Intentos: <strong>{latestJob.summary?.attempted ?? 0}</strong></div>
                  <div>Resueltos: <strong>{latestJob.summary?.resolved ?? 0}</strong></div>
                </div>
              ) : (
                <div style={{ color: "#94a3b8", fontSize: 12 }}>Aún no hay corridas automáticas.</div>
              )}
            </div>

            <div className="ops-panel" style={{ gridColumn: "span 2" }}>
              <div className="ops-section-title">Acciones automáticas recientes</div>
              {recentRuns.length === 0 ? (
                <div style={{ color: "#94a3b8", fontSize: 12 }}>No hay remediaciones automáticas registradas todavía.</div>
              ) : (
                <div className="ops-list">
                  {recentRuns.slice(0, 6).map((run) => (
                    <div key={run.id} className="ops-row-item">
                      <div>
                        <div style={{ fontSize: 12, fontWeight: 700, color: "#e2e8f0" }}>{run.action_key}</div>
                        <div style={{ fontSize: 11, color: "#94a3b8" }}>{run.server_label || run.target_label || "—"} • {fmtDate(run.started_at)}</div>
                      </div>
                      <StatusPill tone={run.status === "error" ? SC.error : run.status === "running" ? SC.running : SC.ok}>{run.status}</StatusPill>
                    </div>
                  ))}
                </div>
              )}
            </div>
          </div>
        </div>
      </div>
    );
  }

  function AuditActivityCard({ toast }) {
    const [logs, setLogs] = useState([]);
    const [loading, setLoading] = useState(false);

    const loadLogs = async () => {
      setLoading(true);
      const response = await apiFetch("/audit/logs?limit=20");
      if (response.error) {
        toast(response.error || "No se pudo cargar la auditoría", "err");
      } else {
        setLogs(Array.isArray(response) ? response : []);
      }
      setLoading(false);
    };

    useEffect(() => {
      loadLogs();
    }, []);

    const describeLog = (entry) => {
      if (entry.details?.error) return entry.details.error;
      if (Array.isArray(entry.details?.changed_keys) && entry.details.changed_keys.length) {
        return `Claves: ${entry.details.changed_keys.join(", ")}`;
      }
      if (entry.details?.username) return `Usuario: ${entry.details.username}`;
      if (entry.details?.label) return `Servidor: ${entry.details.label}`;
      if (entry.target_type && entry.target_id) return `${entry.target_type}: ${entry.target_id}`;
      return "Sin detalle adicional";
    };

    return (
      <div className="card">
        <div className="card-head">
          <span>🧾 Auditoría reciente</span>
          <button onClick={loadLogs} disabled={loading} className="btn btn-ghost btn-sm">
            {loading ? "Cargando..." : "Actualizar"}
          </button>
        </div>
        <div className="card-body">
          <div className="alert alert-info" style={{ marginBottom: 14 }}>
            Registro de acciones sensibles para saber quién intervino el sistema, desde qué IP y con qué resultado.
          </div>

          {logs.length === 0 ? (
            <div style={{ color: "#94a3b8", fontSize: 12 }}>
              {loading ? "Cargando actividad..." : "Todavía no hay eventos de auditoría registrados."}
            </div>
          ) : (
            <div className="ops-list">
              {logs.map((entry) => (
                <div key={entry.id} className="ops-panel">
                  <div className="ops-row-head" style={{ marginBottom: 6 }}>
                    <div style={{ fontWeight: 700, color: "#e2e8f0", fontSize: 13 }}>{entry.action}</div>
                    <StatusPill tone={AUDIT_STATUS_TONE[entry.status] || "#64748b"}>{entry.status}</StatusPill>
                  </div>
                  <div style={{ display: "flex", flexWrap: "wrap", gap: 10, fontSize: 11, color: "#94a3b8", marginBottom: 6 }}>
                    <span>Actor: <strong style={{ color: "#e2e8f0" }}>{entry.actor_username || "anónimo"}</strong></span>
                    <span>IP: <strong style={{ color: "#e2e8f0" }}>{entry.ip_address || "—"}</strong></span>
                    <span>Fecha: <strong style={{ color: "#e2e8f0" }}>{fmtDate(entry.created_at)}</strong></span>
                  </div>
                  <div style={{ fontSize: 12, color: "#cbd5e1" }}>{describeLog(entry)}</div>
                </div>
              ))}
            </div>
          )}
        </div>
      </div>
    );
  }

  const OPS_TABS = [
    { key: "operations", label: "Centro operativo", icon: "🛟" },
    { key: "automation", label: "Auto-remediación", icon: "🤖" },
    { key: "audit", label: "Auditoría", icon: "🧾" },
  ];
  const OPS_TAB_KEYS = new Set(OPS_TABS.map((tab) => tab.key));

  function OpsView({ toast }) {
    const [activeTab, setActiveTab] = useState(() => {
      try {
        return window.localStorage.getItem("dc:tabs:ops") || "operations";
      } catch (_error) {
        return "operations";
      }
    });

    useEffect(() => {
      if (!OPS_TAB_KEYS.has(activeTab)) {
        setActiveTab("operations");
      }
    }, [activeTab]);

    useEffect(() => {
      try {
        window.localStorage.setItem("dc:tabs:ops", activeTab);
      } catch (_error) {}
    }, [activeTab]);

    return (
      <div className="ops-layout">
        <div style={{ fontFamily: "Syne,sans-serif", fontWeight: 800, fontSize: 20, marginBottom: 4 }}>Operación</div>
        <OpsTabs tabs={OPS_TABS} activeTab={activeTab} onChange={setActiveTab} />
        {activeTab === "operations" && <OperationsCard toast={toast} />}
        {activeTab === "automation" && <AutomationCard toast={toast} />}
        {activeTab === "audit" && <AuditActivityCard toast={toast} />}
      </div>
    );
  }

  window.DCViews = window.DCViews || {};
  window.DCViews.OpsView = OpsView;
})();
