"use client";

import { useEffect, useMemo, useState } from "react";
import { Activity, AlertTriangle, CalendarClock, CirclePause, Play, Plus, RefreshCw, ShieldCheck } from "lucide-react";

import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { toast } from "@/components/ui/sonner";
import { EmptyState, InspectorPanelFrame, KeyValue, OperationsPageLayout, PageHeader, SectionCard, StatCard, StatGrid, StatusBadge } from "@/components/operations/operations-ui";
import type { OperationJob, OperationsSnapshot } from "@/lib/agentos/operations/types";
import type { MissionControlSnapshot } from "@/lib/agentos/contracts";

export function OperationsJobsPageContent({ snapshot, activeWorkspaceId, surfaceTheme }: { snapshot: MissionControlSnapshot; activeWorkspaceId: string | null; surfaceTheme: "dark" | "light" }) {
  const [data, setData] = useState<OperationsSnapshot | null>(null);
  const [selected, setSelected] = useState<string | null>(null);
  const [creating, setCreating] = useState(false);
  const [busy, setBusy] = useState(false);
  const load = async () => { try { const response = await fetch("/api/operations", { cache: "no-store" }); const result = await response.json() as OperationsSnapshot & { error?: string }; if (!response.ok || result.error) throw new Error(result.error || "Unable to load Operations."); setData(result); } catch (error) { toast.error("Operations could not be loaded.", { description: error instanceof Error ? error.message : "Unknown error." }); } };
  useEffect(() => { void load(); }, []);
  const jobs = useMemo(() => (data?.jobs ?? []).filter((job) => !activeWorkspaceId || job.workspaceId === activeWorkspaceId), [activeWorkspaceId, data]);
  const current = jobs.find((job) => job.id === selected) ?? jobs[0] ?? null;
  const perform = async (action: "run" | "pause" | "resume" | "retry" | "disable" | "cancel", job: OperationJob) => { setBusy(true); try { const response = await fetch("/api/operations", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action, jobId: job.id }) }); const result = await response.json() as { error?: string }; if (!response.ok || result.error) throw new Error(result.error || "Operation was rejected."); toast.success(`${job.name}: ${action} accepted by OpenClaw.`); await load(); } catch (error) { toast.error(`${action} was not applied.`, { description: error instanceof Error ? error.message : "Unknown error." }); } finally { setBusy(false); } };
  const counts = { active: jobs.filter((job) => job.status === "active" || job.status === "scheduled").length, running: jobs.filter((job) => job.status === "running").length, failed: jobs.filter((job) => job.status === "failed").length, paused: jobs.filter((job) => job.status === "paused").length };
  return <OperationsPageLayout main={<>
    <PageHeader surfaceTheme={surfaceTheme} title="Operations & Jobs" subtitle="OpenClaw cron is the execution source of truth. AgentOS adds safety checks, health projection, and an immutable operator audit trail." actions={<><Button variant="secondary" size="sm" onClick={() => void load()}><RefreshCw className="mr-1.5 h-3.5 w-3.5" />Refresh</Button><Button size="sm" disabled={data?.scheduler.state !== "available"} title={data?.scheduler.state !== "available" ? "Cron write capability is unavailable." : undefined} onClick={() => setCreating(true)}><Plus className="mr-1.5 h-3.5 w-3.5" />New job</Button></>} />
    <StatGrid columns={4}><StatCard label="Active" value={String(counts.active)} detail="Scheduled in OpenClaw" icon={CalendarClock} tone="info" /><StatCard label="Running" value={String(counts.running)} detail="Live cron runs" icon={Activity} tone="warning" /><StatCard label="Failed" value={String(counts.failed)} detail="Needs recovery" icon={AlertTriangle} tone="danger" /><StatCard label="Paused" value={String(counts.paused)} detail="Disabled jobs" icon={CirclePause} tone="muted" /></StatGrid>
    {data?.notices.map((notice) => <div key={notice.title} className="rounded-lg border border-[hsl(var(--status-warning)/0.25)] bg-[hsl(var(--status-warning)/0.08)] p-3 text-xs text-muted-foreground"><strong className="text-foreground">{notice.title}</strong><span className="ml-2">{notice.detail}</span></div>)}
    <SectionCard title="Jobs"><div className="divide-y divide-border">{jobs.length ? jobs.map((job) => <button key={job.id} type="button" className="flex w-full items-center gap-3 px-4 py-3 text-left hover:bg-accent/50" onClick={() => setSelected(job.id)}><StatusBadge label={job.status} tone={tone(job.status)} /><div className="min-w-0 flex-1"><p className="truncate text-sm font-medium text-foreground">{job.name}</p><p className="truncate text-xs text-muted-foreground">{job.agentId ?? "Unbound agent"} · {schedule(job)}</p></div><span className="hidden text-xs text-muted-foreground sm:block">{job.nextRunAt ? `Next ${new Date(job.nextRunAt).toLocaleString()}` : "No next run"}</span></button>) : <EmptyState title="No OpenClaw jobs" description="Create a cron-backed operation when the Gateway advertises cron write support." />}</div></SectionCard>
    {creating ? <CreateOperationForm snapshot={snapshot} activeWorkspaceId={activeWorkspaceId} onClose={() => setCreating(false)} onCreated={async () => { setCreating(false); await load(); }} /> : null}
  </>} inspector={<InspectorPanelFrame title="Job detail">{current ? <JobDetail job={current} runs={(data?.runs ?? []).filter((run) => run.jobId === current.id)} busy={busy} onAction={perform} /> : <p className="text-xs text-muted-foreground">Select a job to inspect its real runtime state.</p>}</InspectorPanelFrame>} />;
}

function JobDetail({ job, runs, busy, onAction }: { job: OperationJob; runs: OperationsSnapshot["runs"]; busy: boolean; onAction: (action: "run" | "pause" | "resume" | "retry" | "disable" | "cancel", job: OperationJob) => Promise<void> }) { return <div className="space-y-4"><div><p className="text-sm font-semibold text-foreground">{job.name}</p><p className="mt-1 text-xs text-muted-foreground">{job.description ?? "No description"}</p></div><div className="space-y-2"><KeyValue label="Owner" value={job.agentId ?? "Unknown"} /><KeyValue label="Schedule" value={schedule(job)} /><KeyValue label="Next run" value={job.nextRunAt ? new Date(job.nextRunAt).toLocaleString() : "Not scheduled"} /><KeyValue label="Health" value={job.health.degraded ? "Degraded" : job.health.successRate === null ? "No completed runs" : `${Math.round(job.health.successRate * 100)}% success`} /><KeyValue label="Concurrency" value={job.safety?.concurrency ?? "Not managed by AgentOS"} /><KeyValue label="Transport" value={job.capabilities.mutable ? "Native Gateway" : job.capabilities.reason ?? "Read-only"} /></div><div className="grid grid-cols-2 gap-2"><Button size="sm" disabled={busy || !job.capabilities.mutable} onClick={() => void onAction("run", job)}><Play className="mr-1 h-3.5 w-3.5" />Run now</Button><Button size="sm" variant="secondary" disabled={busy || !job.capabilities.mutable} onClick={() => void onAction(job.enabled ? "pause" : "resume", job)}>{job.enabled ? "Pause" : "Resume"}</Button></div><SectionCard title="Run history"><div className="divide-y divide-border">{runs.length ? runs.slice(0, 12).map((run) => <div key={run.id} className="px-3 py-2"><div className="flex justify-between gap-2"><StatusBadge label={run.status} tone={tone(run.status)} /><span className="text-[0.65rem] text-muted-foreground">{run.startedAt ? new Date(run.startedAt).toLocaleString() : "Unknown start"}</span></div>{run.error ? <p className="mt-1 text-xs text-destructive">{run.error}</p> : run.output ? <p className="mt-1 line-clamp-2 text-xs text-muted-foreground">{run.output}</p> : null}</div>) : <p className="p-3 text-xs text-muted-foreground">No Gateway run history is available.</p>}</div></SectionCard><p className="text-[0.67rem] leading-4 text-muted-foreground">Cancellation of an already-queued cron run is unavailable because OpenClaw does not expose a documented cron cancel RPC. AgentOS does not simulate it.</p></div>; }
function CreateOperationForm({ snapshot, activeWorkspaceId, onClose, onCreated }: { snapshot: MissionControlSnapshot; activeWorkspaceId: string | null; onClose: () => void; onCreated: () => Promise<void> }) { const agents = snapshot.agents.filter((agent) => !activeWorkspaceId || agent.workspaceId === activeWorkspaceId); const [name, setName] = useState(""); const [prompt, setPrompt] = useState(""); const [agentId, setAgentId] = useState(agents[0]?.id ?? ""); const [expression, setExpression] = useState("0 9 * * 1-5"); const [timezone, setTimezone] = useState(Intl.DateTimeFormat().resolvedOptions().timeZone || "UTC"); const [saving, setSaving] = useState(false); const submit = async (event: React.FormEvent) => { event.preventDefault(); const agent = agents.find((entry) => entry.id === agentId); if (!agent) return; setSaving(true); try { const response = await fetch("/api/operations", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ action: "create", name, prompt, agentId, workspaceId: agent.workspaceId, trigger: { kind: "cron", expression, timezone }, safety: { concurrency: "forbid" } }) }); const result = await response.json() as { error?: string }; if (!response.ok || result.error) throw new Error(result.error || "OpenClaw rejected this job."); toast.success("Job created in OpenClaw."); await onCreated(); } catch (error) { toast.error("Job was not created.", { description: error instanceof Error ? error.message : "Unknown error." }); } finally { setSaving(false); } }; return <div className="fixed inset-0 z-50 grid place-items-center bg-background/70 p-4 backdrop-blur-sm"><form onSubmit={submit} className="w-full max-w-xl space-y-3 rounded-xl border border-border bg-card p-5 shadow-xl"><div className="flex items-center justify-between"><h2 className="text-base font-semibold">New scheduled operation</h2><Button type="button" variant="ghost" size="sm" onClick={onClose}>Close</Button></div><Input value={name} onChange={(event) => setName(event.target.value)} placeholder="Morning operations brief" required /><textarea value={prompt} onChange={(event) => setPrompt(event.target.value)} placeholder="What should the agent do?" required className="min-h-28 w-full rounded-lg border border-input bg-background px-3 py-2 text-sm" /><select value={agentId} onChange={(event) => setAgentId(event.target.value)} className="h-10 w-full rounded-lg border border-input bg-background px-3 text-sm" required>{agents.map((agent) => <option key={agent.id} value={agent.id}>{agent.name}</option>)}</select><div className="grid grid-cols-2 gap-3"><Input value={expression} onChange={(event) => setExpression(event.target.value)} aria-label="Cron expression" required /><Input value={timezone} onChange={(event) => setTimezone(event.target.value)} aria-label="IANA timezone" required /></div><p className="text-xs text-muted-foreground">Cron uses the selected IANA timezone. Preview and DST resolution remain authoritative in OpenClaw.</p><div className="flex justify-end gap-2"><Button type="button" variant="secondary" onClick={onClose}>Cancel</Button><Button type="submit" disabled={saving || !agents.length}><ShieldCheck className="mr-1.5 h-3.5 w-3.5" />Create safely</Button></div></form></div>; }
function schedule(job: OperationJob) { if (!job.trigger) return "Unknown schedule"; return job.trigger.kind === "cron" ? `${job.trigger.expression} · ${job.trigger.timezone ?? "Gateway local time"}` : job.trigger.kind === "every" ? `Every ${Math.round(job.trigger.everyMs / 60000)} min` : `Once at ${new Date(job.trigger.at).toLocaleString()}`; }
function tone(status: string) { return status === "failed" || status === "error" ? "danger" : status === "running" || status === "queued" ? "warning" : status === "completed" || status === "ok" || status === "active" ? "success" : "muted" as const; }
