/*
 * SPEC: PJ2026-010103 HWPOD 服务；PJ2026-010405 云端控制台。
 * 责任: 为 Cloud API 与独立 HWPOD API 提供同一 Python 节点 artifact 合同。
 */
import { createHash } from "node:crypto";
import { readFileSync } from "node:fs";
import path from "node:path";

import { HWPOD_NODE_READINESS_DEFINITIONS } from "../cloud/hwpod-topology-read-model.ts";

type Env = Record<string, string | undefined>;

export function buildHwlabNodeUpdatePayload(url: URL, env: Env = process.env) {
  const currentVersion = cleanText(url.searchParams.get("current") || url.searchParams.get("version"));
  const channel = cleanText(url.searchParams.get("channel")) || "stable";
  const platform = cleanText(url.searchParams.get("platform")) || "unknown";
  const bundled = hwlabNodeBundledArtifact(env);
  const latestVersion = cleanText(env.HWLAB_NODE_PY_LATEST_VERSION) || bundled.version || "0.1.0";
  const releaseNotesUrl = cleanText(env.HWLAB_NODE_PY_RELEASE_NOTES_URL) || null;
  const downloadUrl = hwlabNodeDownloadUrl(env);
  const sha256 = cleanText(env.HWLAB_NODE_PY_SHA256) || bundled.sha256 || null;
  const fileName = nodeArtifactFileName(downloadUrl) || "hwlab-node.py";
  const sizeBytes = positiveInteger(env.HWLAB_NODE_PY_FILE_SIZE_BYTES, bundled.sizeBytes);
  const newer = currentVersion ? compareVersionStrings(latestVersion, currentVersion) > 0 : Boolean(latestVersion);
  const updateAvailable = Boolean(downloadUrl && newer);
  return {
    ok: true,
    contractVersion: "hwlab-node-update-v1",
    serviceId: "hwlab-node",
    route: "/v1/hwlab-node/update",
    channel,
    platform,
    currentVersion: currentVersion || null,
    latestVersion,
    updateAvailable,
    downloadUrl: updateAvailable ? downloadUrl : null,
    sha256: updateAvailable ? sha256 : null,
    artifact: { version: latestVersion, fileName, sizeBytes, sha256, downloadUrl },
    releaseNotes: hwlabNodeReleaseNotes(env),
    releaseNotesUrl,
    installConditions: [
      { id: "windows-python", label: "Windows 交互用户的原生 Python", required: true },
      { id: "tkinter", label: "Python tkinter 图形能力", required: true },
      { id: "yaml-managed-config", label: "owning YAML 声明 nodeId、工作区与凭据引用", required: true },
      { id: "outbound-websocket", label: "可主动出站连接 Cloud API WebSocket", required: true }
    ],
    readinessStages: HWPOD_NODE_READINESS_DEFINITIONS.map((stage) => ({ ...stage, nextAction: { ...stage.nextAction } })),
    manualDefault: true,
    autoApplyDefault: false,
    checkIntervalSeconds: positiveInteger(env.HWLAB_NODE_PY_UPDATE_INTERVAL_SECONDS, 300),
    observedAt: new Date().toISOString()
  };
}

export function hwlabNodeBundledArtifact(env: Env = process.env) {
  const bundlePath = cleanText(env.HWLAB_NODE_PY_BUNDLE_PATH) || path.resolve(process.cwd(), "tools/hwlab-node.py");
  try {
    const content = readFileSync(bundlePath, "utf8");
    const version = cleanText(content.match(/APP_VERSION\s*=\s*["']([^"']+)["']/u)?.[1]);
    const sha256 = createHash("sha256").update(content, "utf8").digest("hex");
    return { path: bundlePath, content, version, sha256, sizeBytes: Buffer.byteLength(content, "utf8") };
  } catch {
    return { path: bundlePath, content: "", version: "", sha256: "", sizeBytes: 0 };
  }
}

function hwlabNodeDownloadUrl(env: Env) {
  const explicit = cleanText(env.HWLAB_NODE_PY_DOWNLOAD_URL);
  if (explicit) return explicit;
  const downloadPath = cleanText(env.HWLAB_NODE_PY_DOWNLOAD_PATH) || "/v1/hwlab-node/download/hwlab-node.py";
  if (/^https?:\/\//iu.test(downloadPath)) return downloadPath;
  const publicEndpoint = cleanText(env.HWPOD_PUBLIC_BASE_URL) || cleanText(env.HWLAB_PUBLIC_ENDPOINT);
  if (!publicEndpoint) return downloadPath.startsWith("/") ? downloadPath : `/${downloadPath}`;
  try {
    return new URL(downloadPath, publicEndpoint.endsWith("/") ? publicEndpoint : `${publicEndpoint}/`).toString();
  } catch {
    return null;
  }
}

function nodeArtifactFileName(downloadUrl: string | null) {
  try { return cleanText(path.posix.basename(new URL(downloadUrl ?? "").pathname)); }
  catch { return ""; }
}

function hwlabNodeReleaseNotes(env: Env) {
  const configured = cleanText(env.HWLAB_NODE_PY_RELEASE_NOTES);
  if (configured) return configured.split(/\r?\n|\|/u).map((item) => item.trim()).filter(Boolean).slice(0, 12);
  return ["单文件 Python/tkinter 节点，提供主动出站 WebSocket、有界诊断和 SHA-256 校验自更新。"];
}

function compareVersionStrings(left: string, right: string) {
  const a = versionParts(left);
  const b = versionParts(right);
  for (let index = 0; index < Math.max(a.length, b.length, 3); index += 1) {
    const delta = (a[index] ?? 0) - (b[index] ?? 0);
    if (delta !== 0) return delta > 0 ? 1 : -1;
  }
  return 0;
}

function versionParts(value: string) {
  return value.trim().replace(/^v/iu, "").split(/[.+-]/u).slice(0, 4)
    .map((part) => Number.parseInt(part, 10))
    .map((part) => (Number.isFinite(part) && part >= 0 ? part : 0));
}

function positiveInteger(value: unknown, fallback: number) {
  const parsed = Number(value);
  return Number.isSafeInteger(parsed) && parsed > 0 ? parsed : fallback;
}

function cleanText(value: unknown) {
  const text = String(value ?? "").trim();
  return text || "";
}
