"use client";

import type { ReactNode } from "react";
import { useEffect, useMemo, useState } from "react";
import { readBackendUnavailableMessage, useResolvedApiBase } from "../lib/api-base";
import { AdminFrame } from "./admin-frame";
import { EmptyPanel, ErrorBanner, NoticeBanner, PageStatus } from "./admin-feedback";
import { ResourceActions, ResourceCard, ResourceCardHeader, ResourceToolbar } from "./admin-resource";
import styles from "./platform-shell.module.css";

type AgentStatus = "enabled" | "disabled";
type AgentPlatform = "linux" | "windows";
type PackageArch = "amd64" | "arm64" | "loong64";

type AgentItem = {
  id: string;
  name: string;
  agentKey: string;
  host: string | null;
  platform: AgentPlatform;
  status: AgentStatus;
  monitoringEnabled: boolean;
  logIngestEnabled: boolean;
  proactivePushEnabled: boolean;
  version: string | null;
  lastHeartbeatAt: string | null;
  lastVerifyAt: string | null;
  lastVerifyStatus: "online" | "offline" | null;
  lastVerifyMessage: string | null;
  availability: {
    state: "online" | "offline";
    message: string;
  };
};

type PackagePayload = {
  agentId: string;
  fileName: string;
  downloadUrl: string;
  readmePreview: string;
};

type AgentForm = {
  name: string;
  agentKey: string;
  host: string;
  platform: AgentPlatform;
};

type PackageForm = {
  targetOs: AgentPlatform;
  targetArch: PackageArch;
};

const defaultForm: AgentForm = {
  name: "测试环境 Linux Agent 节点",
  agentKey: "linux-node-01",
  host: "192.168.1.50",
  platform: "linux",
};

const defaultPackageForm: PackageForm = {
  targetOs: "linux",
  targetArch: "amd64",
};

function downloadJson(fileName: string, payload: unknown) {
  const blob = new Blob([JSON.stringify(payload, null, 2)], {
    type: "application/json;charset=utf-8",
  });
  const url = window.URL.createObjectURL(blob);
  const anchor = document.createElement("a");
  anchor.href = url;
  anchor.download = fileName;
  document.body.appendChild(anchor);
  anchor.click();
  anchor.remove();
  window.URL.revokeObjectURL(url);
}

function formatTime(value?: string | null) {
  return value ? new Date(value).toLocaleString("zh-CN", { hour12: false }) : "暂无";
}

function readErrorMessage(error: unknown, apiBase?: string) {
  if (error instanceof TypeError) return readBackendUnavailableMessage(apiBase);
  if (error instanceof Error) return error.message;
  if (error && typeof error === "object" && "message" in error) {
    const message = (error as { message?: string | string[] }).message;
    return Array.isArray(message) ? message.join("；") : (message ?? "请求失败，请稍后重试。");
  }
  return "请求失败，请稍后重试。";
}

function Field(props: { label: string; hint: string; children: ReactNode }) {
  return (
    <label className={styles.field}>
      <span className={styles.fieldLabel}>{props.label}</span>
      <span className={styles.fieldHint}>{props.hint}</span>
      {props.children}
    </label>
  );
}

export function AgentConsole() {
  const apiBase = useResolvedApiBase();
  const [token, setToken] = useState("");
  const [agents, setAgents] = useState<AgentItem[]>([]);
  const [loading, setLoading] = useState(true);
  const [form, setForm] = useState<AgentForm>(defaultForm);
  const [packageForm, setPackageForm] = useState<PackageForm>(defaultPackageForm);
  const [editingId, setEditingId] = useState<string | null>(null);
  const [infoMessage, setInfoMessage] = useState("");
  const [errorMessage, setErrorMessage] = useState("");
  const [submitting, setSubmitting] = useState(false);
  const [busyAgentId, setBusyAgentId] = useState<string | null>(null);
  const [packagePayload, setPackagePayload] = useState<PackagePayload | null>(null);
  const [keyword, setKeyword] = useState("");
  const [statusFilter, setStatusFilter] = useState<"all" | AgentStatus>("all");
  const [platformFilter, setPlatformFilter] = useState<"all" | AgentPlatform>("all");

  useEffect(() => {
    const savedToken = window.localStorage.getItem("sentai.token");
    if (savedToken) setToken(savedToken);
  }, []);

  useEffect(() => {
    if (!infoMessage) return;
    const timer = window.setTimeout(() => setInfoMessage(""), 4000);
    return () => window.clearTimeout(timer);
  }, [infoMessage]);

  async function request<T>(path: string, init?: RequestInit) {
    const headers = new Headers(init?.headers);
    headers.set("Content-Type", "application/json");
    if (token) headers.set("Authorization", `Bearer ${token}`);
    try {
      const response = await fetch(`${apiBase}${path}`, {
        ...init,
        headers,
        cache: "no-store",
      });
      if (!response.ok) {
        let payload: unknown = null;
        try {
          payload = await response.json();
        } catch {
          payload = null;
        }
        throw new Error(readErrorMessage(payload, apiBase));
      }
      return (await response.json()) as T;
    } catch (error) {
      throw new Error(readErrorMessage(error, apiBase));
    }
  }

  async function refreshData() {
    if (!token) return;
    setLoading(true);
    setErrorMessage("");
    try {
      const payload = await request<{ list: AgentItem[] }>("/api/monitoring/agents");
      setAgents(payload.list);
    } catch (error) {
      setErrorMessage(readErrorMessage(error, apiBase));
    } finally {
      setLoading(false);
    }
  }

  useEffect(() => {
    if (token) void refreshData();
  }, [token]);

  const summary = useMemo(
    () => ({
      total: agents.length,
      enabled: agents.filter((item) => item.status === "enabled").length,
      online: agents.filter((item) => item.availability.state === "online").length,
      monitoringOn: agents.filter((item) => item.monitoringEnabled).length,
    }),
    [agents],
  );

  const filteredAgents = useMemo(() => {
    const normalizedKeyword = keyword.trim().toLowerCase();
    return agents.filter((agent) => {
      const matchesKeyword =
        !normalizedKeyword ||
        agent.name.toLowerCase().includes(normalizedKeyword) ||
        agent.agentKey.toLowerCase().includes(normalizedKeyword) ||
        (agent.host ?? "").toLowerCase().includes(normalizedKeyword);
      const matchesStatus = statusFilter === "all" || agent.status === statusFilter;
      const matchesPlatform = platformFilter === "all" || agent.platform === platformFilter;
      return matchesKeyword && matchesStatus && matchesPlatform;
    });
  }, [agents, keyword, platformFilter, statusFilter]);

  const currentAgentKey =
    (editingId ? agents.find((item) => item.id === editingId)?.agentKey : null) ?? form.agentKey;

  const deploymentPreview = useMemo(() => {
    const lines = [
      `MONITORING_API_BASE_URL=${apiBase}`,
      `MONITORING_AGENT_KEY=${currentAgentKey}`,
      "MONITORING_AGENT_TOKEN=<下载包内 agent-config.env 已自动生成>",
    ];
    if (packageForm.targetOs === "linux") {
      lines.push(`部署包架构=linux-${packageForm.targetArch}`);
    } else {
      lines.push("当前 Windows 包仍作为兼容模式，正式部署优先使用 Linux 原生包。");
    }
    return lines.join("\n");
  }, [apiBase, currentAgentKey, packageForm]);

  function resetForm() {
    setEditingId(null);
    setForm(defaultForm);
    setPackageForm(defaultPackageForm);
  }

  function startEdit(agent: AgentItem) {
    setEditingId(agent.id);
    setForm({
      name: agent.name,
      agentKey: agent.agentKey,
      host: agent.host ?? "",
      platform: agent.platform,
    });
    setPackageForm((current) => ({ ...current, targetOs: agent.platform }));
    setInfoMessage("已载入节点配置，可以继续修改。");
  }

  async function handleSubmit(event: React.FormEvent<HTMLFormElement>) {
    event.preventDefault();
    setSubmitting(true);
    setErrorMessage("");
    try {
      await request(editingId ? `/api/monitoring/agents/${editingId}` : "/api/monitoring/agents", {
        method: editingId ? "PUT" : "POST",
        body: JSON.stringify(form),
      });
      setInfoMessage(editingId ? "Agent 节点已更新。" : "Agent 节点已创建。");
      resetForm();
      await refreshData();
    } catch (error) {
      setErrorMessage(readErrorMessage(error, apiBase));
    } finally {
      setSubmitting(false);
    }
  }

  async function handleToggleStatus(agent: AgentItem) {
    setBusyAgentId(agent.id);
    try {
      await request(`/api/monitoring/agents/${agent.id}/status`, {
        method: "PATCH",
        body: JSON.stringify({
          status: agent.status === "enabled" ? "disabled" : "enabled",
        }),
      });
      setInfoMessage(agent.status === "enabled" ? "节点已停用。" : "节点已启用。");
      await refreshData();
    } catch (error) {
      setErrorMessage(readErrorMessage(error, apiBase));
    } finally {
      setBusyAgentId(null);
    }
  }

  async function handleToggleFeature(
    agent: AgentItem,
    feature: "monitoringEnabled" | "logIngestEnabled" | "proactivePushEnabled",
  ) {
    setBusyAgentId(agent.id);
    try {
      await request(`/api/monitoring/agents/${agent.id}/features`, {
        method: "PATCH",
        body: JSON.stringify({
          monitoringEnabled:
            feature === "monitoringEnabled" ? !agent.monitoringEnabled : agent.monitoringEnabled,
          logIngestEnabled:
            feature === "logIngestEnabled" ? !agent.logIngestEnabled : agent.logIngestEnabled,
          proactivePushEnabled:
            feature === "proactivePushEnabled"
              ? !agent.proactivePushEnabled
              : agent.proactivePushEnabled,
        }),
      });
      setInfoMessage("节点能力开关已更新。");
      await refreshData();
    } catch (error) {
      setErrorMessage(readErrorMessage(error, apiBase));
    } finally {
      setBusyAgentId(null);
    }
  }

  async function handleVerify(agent: AgentItem) {
    setBusyAgentId(agent.id);
    try {
      await request(`/api/monitoring/agents/${agent.id}/verify`, { method: "POST" });
      setInfoMessage("可用性验证已完成。");
      await refreshData();
    } catch (error) {
      setErrorMessage(readErrorMessage(error, apiBase));
    } finally {
      setBusyAgentId(null);
    }
  }

  async function handleBuildPackage(agent: AgentItem) {
    setBusyAgentId(agent.id);
    try {
      const payload = await request<PackagePayload>(`/api/monitoring/agents/${agent.id}/package`, {
        method: "POST",
        body: JSON.stringify(packageForm),
      });
      setPackagePayload(payload);
      setInfoMessage("部署包已生成，可以直接下载。");
    } catch (error) {
      setErrorMessage(readErrorMessage(error, apiBase));
    } finally {
      setBusyAgentId(null);
    }
  }

  function exportAgents() {
    downloadJson("monitor-agents.json", filteredAgents);
    setInfoMessage(`已导出 ${filteredAgents.length} 个 Agent 节点。`);
  }

  return (
    <AdminFrame
      section="agents"
      title="Agent 节点"
      description="先登记宿主机节点，再生成部署包并控制节点能力。监测什么、日志路径是什么，仍然在环境监测页配置。"
      actions={
        <button className={styles.secondaryButton} onClick={() => void refreshData()} type="button">
          刷新节点
        </button>
      }
    >
      <NoticeBanner message={infoMessage} />
      <ErrorBanner message={errorMessage} />

      <section className={styles.panel}>
        <div className={styles.statsGrid}>
          <article className={styles.statCard}>
            <span>Agent 总数</span>
            <strong>{summary.total}</strong>
          </article>
          <article className={styles.statCard}>
            <span>已启用节点</span>
            <strong>{summary.enabled}</strong>
          </article>
          <article className={styles.statCard} data-tone="success">
            <span>在线节点</span>
            <strong>{summary.online}</strong>
          </article>
          <article className={styles.statCard} data-tone="warning">
            <span>已开启监测执行</span>
            <strong>{summary.monitoringOn}</strong>
          </article>
        </div>
      </section>

      <section className={styles.panel}>
        <div className={styles.pageHeader}>
          <div>
            <p className={styles.pageKicker}>节点表单</p>
            <h2>{editingId ? "编辑 Agent 节点" : "新建 Agent 节点"}</h2>
            <p>
              创建节点只是把宿主机纳入平台。真正的 Redis、MQ、ES、Java、HTTP 监测目标，需要到环境监测页绑定到这个节点。
            </p>
          </div>
          <PageStatus busy={submitting} busyLabel="保存中" idleLabel="可编辑" />
        </div>

        <div className={styles.taskComposer}>
          <form className={styles.form} onSubmit={handleSubmit}>
            <div className={styles.formSection}>
              <div className={styles.sectionHeader}>
                <div>
                  <h3>基础信息</h3>
                  <p>统一维护节点名称、Agent Key 和宿主机标识。</p>
                </div>
              </div>

              <div className={styles.formGrid}>
                <Field label="节点名称" hint="建议写清环境、服务器角色与用途。">
                  <input
                    value={form.name}
                    onChange={(event) =>
                      setForm((current) => ({ ...current, name: event.target.value }))
                    }
                  />
                </Field>
                <Field label="Agent Key" hint="Agent 启动后用它向平台注册、发心跳并领取任务。">
                  <input
                    value={form.agentKey}
                    onChange={(event) =>
                      setForm((current) => ({ ...current, agentKey: event.target.value }))
                    }
                  />
                </Field>
                <Field label="目标主机" hint="填写宿主机名或 IP，便于后续定位。">
                  <input
                    value={form.host}
                    onChange={(event) =>
                      setForm((current) => ({ ...current, host: event.target.value }))
                    }
                  />
                </Field>
                <Field label="默认平台类型" hint="正式部署优先建议 Linux。">
                  <select
                    value={form.platform}
                    onChange={(event) =>
                      setForm((current) => ({
                        ...current,
                        platform: event.target.value as AgentPlatform,
                      }))
                    }
                  >
                    <option value="linux">Linux</option>
                    <option value="windows">Windows</option>
                  </select>
                </Field>
              </div>

              <div className={styles.buttonRow}>
                <button disabled={submitting} type="submit">
                  {submitting ? "保存中..." : editingId ? "保存修改" : "创建节点"}
                </button>
                <button className={styles.secondaryButton} onClick={resetForm} type="button">
                  重置
                </button>
              </div>
            </div>
          </form>

          <aside className={styles.stack}>
            <article className={styles.strategyCard}>
              <div className={styles.sectionHeader}>
                <div>
                  <h3>部署包选项</h3>
                  <p>按目标系统和架构生成对应部署包，不要求服务器额外安装 Node.js 等运行时。</p>
                </div>
                <span className={styles.strategyTag}>原生离线包</span>
              </div>

              <div className={styles.formGrid}>
                <Field label="目标系统" hint="当前正式原生包优先支持 Linux。">
                  <select
                    value={packageForm.targetOs}
                    onChange={(event) =>
                      setPackageForm((current) => ({
                        ...current,
                        targetOs: event.target.value as AgentPlatform,
                      }))
                    }
                  >
                    <option value="linux">Linux</option>
                    <option value="windows">Windows</option>
                  </select>
                </Field>
                <Field label="目标架构" hint="常规 x86 服务器用 amd64，ARM 用 arm64，龙芯可选 loong64。">
                  <select
                    value={packageForm.targetArch}
                    onChange={(event) =>
                      setPackageForm((current) => ({
                        ...current,
                        targetArch: event.target.value as PackageArch,
                      }))
                    }
                  >
                    <option value="amd64">amd64</option>
                    <option value="arm64">arm64</option>
                    <option value="loong64">loong64</option>
                  </select>
                </Field>
              </div>

              <pre className={styles.codeBlock}>{deploymentPreview}</pre>
            </article>

            <article className={styles.guideCard}>
              <div className={styles.sectionHeader}>
                <div>
                  <h3>使用顺序</h3>
                  <p>先让 Agent 在线，再去环境监测页创建 Redis、MQ、ES、Java 等目标。</p>
                </div>
              </div>
              <ul className={styles.guideList}>
                <li>先在这里创建节点并生成部署包。</li>
                <li>把部署包上传到目标服务器，按 README 安装运行。</li>
                <li>节点在线后，在本页启用节点并打开“监测执行”。</li>
                <li>最后去环境监测页创建并绑定监测目标。</li>
              </ul>
            </article>

            <article className={styles.tipPanel}>
              <strong>Token 在哪里？</strong>
              <p>
                下载部署包后，直接打开 <code>agent-config.env</code>，其中的{" "}
                <code>MONITORING_AGENT_TOKEN</code> 就是当前节点与平台通信所用的 Token。
              </p>
            </article>

            {packagePayload ? (
              <article className={styles.guideCard}>
                <div className={styles.sectionHeader}>
                  <div>
                    <h3>最近生成的部署包</h3>
                    <p>{packagePayload.fileName}</p>
                  </div>
                  <a
                    className={styles.linkButton}
                    href={`${apiBase}${packagePayload.downloadUrl}`}
                    rel="noreferrer"
                    target="_blank"
                  >
                    下载部署包
                  </a>
                </div>
                <pre className={styles.codeBlock}>{packagePayload.readmePreview}</pre>
              </article>
            ) : null}
          </aside>
        </div>
      </section>

      <section className={styles.panel}>
        <ResourceToolbar
          title="节点列表"
          description="节点在线不代表自动开始监测。只有节点启用且“监测执行”打开后，平台才会派发监测任务。"
        >
          <label className={styles.inlineField}>
            <span>搜索</span>
            <input
              placeholder="按名称、Agent Key 或主机筛选"
              value={keyword}
              onChange={(event) => setKeyword(event.target.value)}
            />
          </label>
          <label className={styles.inlineField}>
            <span>状态</span>
            <select
              value={statusFilter}
              onChange={(event) => setStatusFilter(event.target.value as "all" | AgentStatus)}
            >
              <option value="all">全部状态</option>
              <option value="enabled">启用</option>
              <option value="disabled">停用</option>
            </select>
          </label>
          <label className={styles.inlineField}>
            <span>平台</span>
            <select
              value={platformFilter}
              onChange={(event) =>
                setPlatformFilter(event.target.value as "all" | AgentPlatform)
              }
            >
              <option value="all">全部平台</option>
              <option value="linux">Linux</option>
              <option value="windows">Windows</option>
            </select>
          </label>
          <ResourceActions>
            <button className={styles.secondaryButton} onClick={exportAgents} type="button">
              导出
            </button>
            <button className={styles.secondaryButton} onClick={resetForm} type="button">
              新建节点
            </button>
          </ResourceActions>
        </ResourceToolbar>

        {loading ? (
          <EmptyPanel message="正在加载 Agent 节点..." />
        ) : agents.length === 0 ? (
          <EmptyPanel message="当前还没有 Agent 节点，先创建一个再生成部署包。" />
        ) : filteredAgents.length === 0 ? (
          <EmptyPanel message="当前筛选条件下没有匹配的 Agent 节点。" />
        ) : (
          <div className={styles.taskList}>
            {filteredAgents.map((agent) => (
              <ResourceCard key={agent.id}>
                <ResourceCardHeader
                  title={agent.name}
                  subtitle={`${agent.host || "未填写宿主机"} / ${agent.agentKey}`}
                  badges={
                    <>
                      <span className={styles.typeBadge}>{agent.platform.toUpperCase()}</span>
                      <span className={styles.badge} data-status={agent.status}>
                        {agent.status === "enabled" ? "启用" : "停用"}
                      </span>
                      <span
                        className={styles.badge}
                        data-status={agent.availability.state === "online" ? "success" : "failed"}
                      >
                        {agent.availability.state === "online" ? "在线" : "离线"}
                      </span>
                    </>
                  }
                  actions={
                    <ResourceActions>
                      <button className={styles.secondaryButton} onClick={() => startEdit(agent)} type="button">
                        编辑
                      </button>
                      <button
                        className={styles.secondaryButton}
                        disabled={busyAgentId === agent.id}
                        onClick={() => void handleBuildPackage(agent)}
                        type="button"
                      >
                        生成部署包
                      </button>
                      <button
                        className={styles.secondaryButton}
                        disabled={busyAgentId === agent.id}
                        onClick={() => void handleVerify(agent)}
                        type="button"
                      >
                        可用性验证
                      </button>
                      <button
                        disabled={busyAgentId === agent.id}
                        onClick={() => void handleToggleStatus(agent)}
                        type="button"
                      >
                        {agent.status === "enabled" ? "停用节点" : "启用节点"}
                      </button>
                    </ResourceActions>
                  }
                >
                  <div className={styles.metaChipList}>
                    <span className={styles.metaChip}>
                      <strong>最后心跳</strong>
                      {formatTime(agent.lastHeartbeatAt)}
                    </span>
                    <span className={styles.metaChip}>
                      <strong>版本</strong>
                      {agent.version ?? "暂无"}
                    </span>
                    <span className={styles.metaChip}>
                      <strong>最近验证</strong>
                      {agent.lastVerifyMessage ?? agent.availability.message}
                    </span>
                  </div>
                </ResourceCardHeader>

                <div className={styles.actionRow}>
                  <button
                    className={agent.monitoringEnabled ? styles.secondaryButton : styles.ghostDangerButton}
                    disabled={busyAgentId === agent.id}
                    onClick={() => void handleToggleFeature(agent, "monitoringEnabled")}
                    type="button"
                  >
                    {agent.monitoringEnabled ? "关闭监测执行" : "开启监测执行"}
                  </button>
                  <button
                    className={agent.logIngestEnabled ? styles.secondaryButton : styles.ghostDangerButton}
                    disabled={busyAgentId === agent.id}
                    onClick={() => void handleToggleFeature(agent, "logIngestEnabled")}
                    type="button"
                  >
                    {agent.logIngestEnabled ? "关闭日志接入" : "开启日志接入"}
                  </button>
                  <button
                    className={agent.proactivePushEnabled ? styles.secondaryButton : styles.ghostDangerButton}
                    disabled={busyAgentId === agent.id}
                    onClick={() => void handleToggleFeature(agent, "proactivePushEnabled")}
                    type="button"
                  >
                    {agent.proactivePushEnabled ? "关闭主动上报" : "开启主动上报"}
                  </button>
                </div>
              </ResourceCard>
            ))}
          </div>
        )}
      </section>
    </AdminFrame>
  );
}
