import { randomUUID } from "node:crypto";

export const HWLAB_AGENT_RUNTIME_SKILL_CLI_VERSION = "hwlab-agent-runtime-skill-cli-v1";
export const HWLAB_M3_IO_API_ROUTE = "/v1/m3/io";
export const HWLAB_M3_STATUS_API_ROUTE = "/v1/m3/status";
export const HWLAB_M3_IO_SKILL_NAME = "hwlab-agent-runtime.m3-io";
export const HWLAB_M3_IO_API_BASE_URL_ENV = "HWLAB_CODE_AGENT_HWLAB_API_BASE_URL";
export const HWLAB_M3_IO_DEV_SERVICE_BASE_URL = "http://hwlab-cloud-api.hwlab-dev.svc.cluster.local:6667";
export const HWLAB_M3_IO_API_BASE_URL_ENVS = Object.freeze([
  HWLAB_M3_IO_API_BASE_URL_ENV,
  "HWLAB_API_BASE_URL",
  "HWLAB_CLOUD_API_BASE_URL"
]);
export const HWLAB_M3_IO_CAPABILITY_LEVELS = Object.freeze({
  blocked: "hwlab-api-control-blocked",
  readonly: "hwlab-api-readonly",
  ready: "hwlab-api-control-with-approval"
});

const allowedActions = new Set(["do.write", "di.read"]);
const defaultTimeoutMs = 30000;
const safeApiBaseEnvNames = Object.freeze([
  "HWLAB_CODE_AGENT_HWLAB_API_BASE_URL",
  "HWLAB_API_BASE_URL",
  "HWLAB_CLOUD_API_BASE_URL"
]);
export async function runM3IoSkillCommand(argv = [], options = {}) {
  const env = options.env ?? process.env;
  const parsed = parseM3IoArgs(argv, env);
  if (parsed.help) {
    return helpPayload();
  }

  const traceId = parsed.traceId || `trc_${randomUUID()}`;
  const requestId = parsed.requestId || `req_${randomUUID()}`;
  const actorId = parsed.actorId || "usr_code_agent";
  const apiTarget = resolveCloudApiTarget(parsed.apiBaseUrl, env, {
    route: parsed.mode === "status" ? HWLAB_M3_STATUS_API_ROUTE : HWLAB_M3_IO_API_ROUTE
  });
  const validation = validateCloudApiTarget(apiTarget);
  if (validation) {
    return blockedPayload({
      traceId,
      requestId,
      actorId,
      apiTarget,
      code: validation.code,
      message: validation.message,
      missingConfig: validation.missingConfig
    });
  }

  if (parsed.mode === "status") {
    return runM3StatusSkillCommand({
      apiTarget,
      parsed,
      traceId,
      requestId,
      actorId,
      requestJson: options.requestJson,
      now: options.now
    });
  }

  const command = normalizeCommand(parsed);
  if (!allowedActions.has(command.action)) {
    return blockedPayload({
      traceId,
      requestId,
      actorId,
      apiTarget,
      code: "invalid_action",
      message: "M3 Skill CLI only allows do.write or di.read."
    });
  }
  if (command.action === "do.write" && typeof command.value !== "boolean") {
    return blockedPayload({
      traceId,
      requestId,
      actorId,
      apiTarget,
      code: "invalid_boolean_value",
      message: "M3 DO1 写入需要 --value true 或 --value false。"
    });
  }
  const approval = approvalForParsed(parsed, command);
  if (approval.blocker) {
    return blockedPayload({
      traceId,
      requestId,
      actorId,
      apiTarget,
      code: approval.blocker.code,
      message: approval.blocker.message,
      approval
    });
  }

  const payload = requestPayload(command, { traceId, requestId, actorId, approval });
  const startedAt = nowIso(options.now);
  const response = await postJson(apiTarget.url, payload, {
    requestJson: options.requestJson,
    timeoutMs: parsed.timeoutMs,
    headers: {
      "x-trace-id": traceId,
      "x-request-id": requestId,
      "x-actor-id": actorId
    }
  });
  const finishedAt = nowIso(options.now);

  return normalizeSkillResponse({
    response,
    command,
    payload,
    apiTarget,
    traceId,
    requestId,
    actorId,
    startedAt,
    finishedAt
  });
}

export function parseM3IoArgs(argv = [], env = process.env) {
  const args = [...argv];
  const command = args.shift() ?? "help";
  const subcommand = args.shift() ?? "";
  const parsed = {
    command,
    subcommand,
    mode: command === "m3" && subcommand === "status" ? "status" : "io",
    action: null,
    value: undefined,
    apiBaseUrl: null,
    traceId: null,
    requestId: null,
    actorId: null,
    approved: false,
    approvalReason: null,
    policy: null,
    timeoutMs: defaultTimeoutMs,
    pretty: false,
    help: command === "help" || command === "--help" || command === "-h"
  };

  if (command !== "m3" || !["io", "status"].includes(subcommand)) {
    parsed.help = true;
    return parsed;
  }

  for (let index = 0; index < args.length; index += 1) {
    const arg = args[index];
    if (arg === "--help" || arg === "-h") {
      parsed.help = true;
    } else if (arg === "--pretty") {
      parsed.pretty = true;
    } else if (arg === "--action") {
      parsed.action = readOption(args, ++index, arg);
    } else if (arg === "--value") {
      parsed.value = parseBoolean(readOption(args, ++index, arg));
    } else if (arg === "--api-base-url") {
      parsed.apiBaseUrl = readOption(args, ++index, arg);
    } else if (arg === "--trace-id") {
      parsed.traceId = readOption(args, ++index, arg);
    } else if (arg === "--request-id") {
      parsed.requestId = readOption(args, ++index, arg);
    } else if (arg === "--actor-id") {
      parsed.actorId = readOption(args, ++index, arg);
    } else if (arg === "--approved" || arg === "--confirm-control") {
      parsed.approved = true;
    } else if (arg === "--approval-reason") {
      parsed.approvalReason = readOption(args, ++index, arg);
    } else if (arg === "--policy") {
      parsed.policy = readOption(args, ++index, arg);
    } else if (arg === "--timeout-ms") {
      parsed.timeoutMs = parseTimeout(readOption(args, ++index, arg));
    } else if (subcommand === "io" && arg === "write") {
      parsed.action = "do.write";
    } else if (subcommand === "io" && arg === "read") {
      parsed.action = "di.read";
    } else {
      throw new Error(`unknown argument ${arg}`);
    }
  }

  parsed.apiBaseUrl = parsed.apiBaseUrl || configuredCloudApiBaseUrl(env);
  return parsed;
}

export function resolveCloudApiTarget(apiBaseUrl, env = process.env, options = {}) {
  const route = options.route ?? HWLAB_M3_IO_API_ROUTE;
  const source = cloudApiBaseUrlSource(apiBaseUrl, env);
  const base = firstNonEmpty(apiBaseUrl, configuredCloudApiBaseUrl(env));
  if (!base) {
    return cloudApiTargetEnvelope({
      route,
      source,
      url: null,
      redactedUrl: null,
      baseUrlConfigured: false,
      missingConfig: [...safeApiBaseEnvNames, "contract:hwlab-agent-runtime.m3-io.apiBaseUrl"]
    });
  }

  let url;
  try {
    url = new URL(route, ensureTrailingSlash(base));
  } catch {
    return cloudApiTargetEnvelope({
      route,
      source,
      url: String(base),
      redactedUrl: redactUrl(base),
      baseUrlConfigured: true,
      invalidBaseUrl: true
    });
  }

  return cloudApiTargetEnvelope({
    route,
    source,
    url: url.toString(),
    redactedUrl: redactUrl(url.toString()),
    baseUrlConfigured: true
  });
}

function cloudApiTargetEnvelope({ route = HWLAB_M3_IO_API_ROUTE, source, url, redactedUrl, baseUrlConfigured, invalidBaseUrl = false, missingConfig = [] }) {
  return {
    route,
    url,
    redactedUrl,
    source,
    baseUrlConfigured,
    requiredEnv: [...HWLAB_M3_IO_API_BASE_URL_ENVS],
    recommendedEnv: HWLAB_M3_IO_API_BASE_URL_ENV,
    invalidBaseUrl,
    missingConfig: sanitizeMissingConfig(missingConfig),
    cloudApiOnly: false,
    directGatewayCalls: true,
    directBoxCalls: true,
    directPatchPanelCalls: true
  };
}

export function validateCloudApiTarget(apiTarget) {
  if (!apiTarget?.url || apiTarget.missingConfig?.length > 0) {
    return {
      code: "skill_cli_api_base_missing",
      message: "M3 Skill CLI requires a configured HWLAB API base URL contract.",
      missingConfig: apiTarget?.missingConfig ?? [...safeApiBaseEnvNames, "contract:hwlab-agent-runtime.m3-io.apiBaseUrl"]
    };
  }

  if (apiTarget.invalidBaseUrl === true) {
    return {
      code: "invalid_hwlab_api_url",
      message: "HWLAB API base URL is not a valid URL."
    };
  }

  let parsedUrl;
  try {
    parsedUrl = new URL(apiTarget.url);
  } catch {
    return {
      code: "invalid_hwlab_api_url",
      message: "HWLAB API base URL is not a valid URL."
    };
  }

  if (isDirectHardwareServiceHost(parsedUrl.hostname)) {
    return {
      code: "direct_hardware_target_blocked",
      message: "M3 Skill CLI must call HWLAB cloud-api /v1/m3/io, not a direct hardware service."
    };
  }

  return null;
}

function isDirectHardwareServiceHost(hostname) {
  const host = String(hostname ?? "").toLowerCase();
  return /(^|[.-])(hwlab-patch-panel|patch-panel|boxsimu|box-simu|gateway-simu|gateway-simu-[a-z0-9-]*|hwlab-gateway)([.-]|$)/u.test(host);
}

function normalizeCommand(parsed) {
  const action = String(parsed.action ?? "").trim().toLowerCase();
  if (action === "do.write") {
    return {
      action,
      gatewayId: "gwsimu_1",
      resourceId: "res_boxsimu_1",
      boxId: "boxsimu_1",
      port: "DO1",
      value: parsed.value
    };
  }

  return {
    action,
    gatewayId: "gwsimu_2",
    resourceId: "res_boxsimu_2",
    boxId: "boxsimu_2",
    port: "DI1"
  };
}

function requestPayload(command, meta) {
  return {
    action: command.action,
    gatewayId: command.gatewayId,
    resourceId: command.resourceId,
    boxId: command.boxId,
    port: command.port,
    ...(Object.hasOwn(command, "value") ? { value: command.value } : {}),
    traceId: meta.traceId,
    requestId: meta.requestId,
    actorId: meta.actorId,
    approval: meta.approval
      ? {
          approved: meta.approval.approved,
          policy: meta.approval.policy,
          reason: meta.approval.reason,
          required: meta.approval.required
        }
      : undefined,
    source: HWLAB_M3_IO_SKILL_NAME
  };
}

async function runM3StatusSkillCommand({ apiTarget, parsed, traceId, requestId, actorId, requestJson, now }) {
  const startedAt = nowIso(now);
  const response = await getJson(apiTarget.url, {
    requestJson,
    timeoutMs: parsed.timeoutMs,
    headers: {
      "x-trace-id": traceId,
      "x-request-id": requestId,
      "x-actor-id": actorId
    }
  });
  const finishedAt = nowIso(now);
  return normalizeStatusResponse({
    response,
    apiTarget,
    traceId,
    requestId,
    actorId,
    startedAt,
    finishedAt
  });
}

async function postJson(url, body, { requestJson, timeoutMs, headers }) {
  if (typeof requestJson === "function") {
    try {
      const result = await requestJson(url, {
        method: "POST",
        headers: {
          accept: "application/json",
          "content-type": "application/json",
          ...headers
        },
        body,
        timeoutMs
      });
      return normalizeJsonResponse(result);
    } catch (error) {
      return {
        ok: false,
        status: 0,
        body: null,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);
  try {
    const response = await fetch(url, {
      method: "POST",
      headers: {
        accept: "application/json",
        "content-type": "application/json",
        ...headers
      },
      body: JSON.stringify(body),
      signal: controller.signal
    });
    const text = await response.text();
    const parsed = parseJsonOrNull(text);
    return {
      ok: response.ok,
      status: response.status,
      body: parsed,
      error: response.ok ? null : parsed?.error?.message ?? parsed?.message ?? response.statusText
    };
  } catch (error) {
    return {
      ok: false,
      status: 0,
      body: null,
      error: error.name === "AbortError" ? `HWLAB API request timed out after ${timeoutMs}ms` : error.message
    };
  } finally {
    clearTimeout(timer);
  }
}

async function getJson(url, { requestJson, timeoutMs, headers }) {
  if (typeof requestJson === "function") {
    try {
      const result = await requestJson(url, {
        method: "GET",
        headers: {
          accept: "application/json",
          ...headers
        },
        timeoutMs
      });
      return normalizeJsonResponse(result);
    } catch (error) {
      return {
        ok: false,
        status: 0,
        body: null,
        error: error instanceof Error ? error.message : String(error)
      };
    }
  }

  const controller = new AbortController();
  const timer = setTimeout(() => controller.abort(), timeoutMs);
  try {
    const response = await fetch(url, {
      method: "GET",
      headers: {
        accept: "application/json",
        ...headers
      },
      signal: controller.signal
    });
    const text = await response.text();
    const parsed = parseJsonOrNull(text);
    return {
      ok: response.ok,
      status: response.status,
      body: parsed,
      error: response.ok ? null : parsed?.error?.message ?? parsed?.message ?? response.statusText
    };
  } catch (error) {
    return {
      ok: false,
      status: 0,
      body: null,
      error: error.name === "AbortError" ? `HWLAB API request timed out after ${timeoutMs}ms` : error.message
    };
  } finally {
    clearTimeout(timer);
  }
}

function normalizeJsonResponse(result = {}) {
  if (Object.hasOwn(result, "ok") || Object.hasOwn(result, "body")) {
    return {
      ok: result.ok ?? (Number(result.status ?? 200) >= 200 && Number(result.status ?? 200) < 300),
      status: result.status ?? 200,
      body: result.body ?? result.json ?? null,
      error: result.error ?? result.body?.error?.message ?? null
    };
  }
  const status = result.status ?? 200;
  return {
    ok: status >= 200 && status < 300,
    status,
    body: result.json ?? result,
    error: result.error ?? null
  };
}

function normalizeSkillResponse({ response, command, payload, apiTarget, traceId, requestId, actorId, startedAt, finishedAt }) {
  const body = response.body ?? {};
  const blocker = normalizeBlocker(body, response);
  const accepted = body.accepted === true;
  const status = body.status ?? (response.ok && accepted ? "succeeded" : "blocked");
  const durable = durableSummary(body);
  const controlReady = response.ok && accepted && status !== "blocked" && body.controlPath?.cloudApi !== false && body.controlPath?.frontendBypass !== true;
  const capabilityLevel = controlReady
    ? HWLAB_M3_IO_CAPABILITY_LEVELS.ready
    : HWLAB_M3_IO_CAPABILITY_LEVELS.blocked;
  const capabilityBlocker = controlReady ? null : normalizeCapabilityBlocker(blocker, response);
  const trustBlocker = normalizeTrustBlocker(body, HWLAB_M3_IO_API_ROUTE);
  const blockers = dedupeBlockers([capabilityBlocker, trustBlocker]);

  return {
    ok: response.ok && accepted && status !== "blocked",
    service: HWLAB_M3_IO_SKILL_NAME,
    contractVersion: HWLAB_AGENT_RUNTIME_SKILL_CLI_VERSION,
    route: HWLAB_M3_IO_API_ROUTE,
    method: "POST",
    hwlabApi: publicCloudApiTarget(apiTarget),
    capabilityLevel,
    controlReady,
    action: command.action,
    accepted,
    status,
    traceId: body.traceId ?? traceId,
    requestId,
    actorId,
    approval: payload.approval ?? approvalForAction(command.action),
    operationId: body.operationId ?? null,
    auditId: body.auditId ?? body.auditState?.auditId ?? null,
    evidenceId: body.evidenceId ?? body.evidenceState?.evidenceId ?? null,
    audit: {
      auditId: body.auditId ?? body.auditState?.auditId ?? null,
      status: body.auditState?.status ?? null,
      durableStatus: body.auditState?.durableStatus?.status ?? body.durableStatus?.status ?? null,
      summary: auditSummary(body)
    },
    evidence: {
      evidenceId: body.evidenceId ?? body.evidenceState?.evidenceId ?? null,
      status: body.evidenceState?.status ?? null,
      sourceKind: body.evidenceState?.sourceKind ?? null,
      blocker: body.evidenceState?.blocker ?? null,
      writeStatus: body.evidenceState?.writeStatus ?? null,
      summary: evidenceSummary(body)
    },
    durable,
    blocker,
    capabilityBlocker,
    trustBlocker,
    blockers,
    readiness: {
      status: controlReady ? "ready" : "blocked",
      controlReady,
      capabilityLevel,
      route: HWLAB_M3_IO_API_ROUTE,
      blocker: capabilityBlocker,
      trustBlocker
    },
    command,
    result: {
      value: body.result?.value ?? body.value ?? null,
      targetReadback: body.result?.targetReadback ?? null
    },
    readback: normalizeReadback(body, command),
    controlPath: body.controlPath ?? {
      cloudApi: true,
      gatewaySimu: false,
      boxSimu: false,
      patchPanel: false,
      frontendBypass: false
    },
    safety: {
      cloudApiRouteOnly: false,
      allowedRoute: HWLAB_M3_IO_API_ROUTE,
      directGatewayCalls: true,
      directBoxCalls: true,
      directPatchPanelCalls: true,
      fallbackUsed: false,
      openAiFallbackUsed: false
    },
    httpStatus: response.status,
    error: response.ok ? body.error ?? null : {
      code: "hwlab_api_unavailable",
      layer: "hwlab-api",
      blocker: capabilityBlocker,
      retryable: true,
      userMessage: "HWLAB API 当前不可达，M3 控制未执行，可稍后重试。",
      message: response.error ?? "HWLAB API request failed",
      traceId,
      route: HWLAB_M3_IO_API_ROUTE,
      toolName: HWLAB_M3_IO_SKILL_NAME
    },
    rawStatus: body.status ?? null,
    startedAt,
    finishedAt,
    responseSummary: responseSummary(body)
  };
}

function normalizeStatusResponse({ response, apiTarget, traceId, requestId, actorId, startedAt, finishedAt }) {
  const body = response.body ?? {};
  const blocker = response.ok
    ? normalizeStatusBlocker(body, response)
    : normalizeBlocker(body, response, {
        route: HWLAB_M3_STATUS_API_ROUTE,
        unavailableUserMessage: "HWLAB API 当前不可达，M3 状态未读取，可稍后重试。",
        defaultMessage: "M3 status request was blocked."
      });
  const ready = response.ok && !blocker && !["blocked", "error", "failed"].includes(String(body.status ?? "").toLowerCase());
  const trustBlocker = normalizeTrustBlocker(body, HWLAB_M3_STATUS_API_ROUTE);
  const blockers = dedupeBlockers([blocker, trustBlocker]);
  return {
    ok: response.ok && !blocker,
    service: HWLAB_M3_IO_SKILL_NAME,
    contractVersion: HWLAB_AGENT_RUNTIME_SKILL_CLI_VERSION,
    route: HWLAB_M3_STATUS_API_ROUTE,
    method: "GET",
    hwlabApi: publicCloudApiTarget(apiTarget),
    capabilityLevel: ready ? HWLAB_M3_IO_CAPABILITY_LEVELS.readonly : HWLAB_M3_IO_CAPABILITY_LEVELS.blocked,
    controlReady: ready,
    readonly: true,
    accepted: response.ok && !blocker,
    status: body.status ?? (response.ok ? "succeeded" : "blocked"),
    traceId: body.traceId ?? body.trust?.traceId ?? traceId,
    requestId,
    actorId,
    operationId: body.trust?.operationId ?? body.operationId ?? null,
    auditId: body.trust?.auditId ?? body.auditId ?? null,
    evidenceId: body.trust?.evidenceId ?? body.evidenceId ?? null,
    audit: {
      auditId: body.trust?.auditId ?? body.auditId ?? null,
      status: body.trust?.readStatus?.audit ?? null,
      durableStatus: body.trust?.durableStatus ?? null,
      summary: body.trust?.auditId ? `${body.trust.auditId}; status=${body.trust.readStatus?.audit ?? "unknown"}` : "audit not reported"
    },
    evidence: {
      evidenceId: body.trust?.evidenceId ?? body.evidenceId ?? null,
      status: body.trust?.readStatus?.evidence ?? null,
      sourceKind: body.sourceKind ?? null,
      blocker: body.trust?.blocker ?? null,
      writeStatus: null,
      summary: body.trust?.evidenceId ? `${body.trust.evidenceId}; status=${body.trust.readStatus?.evidence ?? "unknown"}` : "evidence not reported"
    },
    durable: {
      status: body.trust?.durableStatus ?? body.trust?.runtime?.status ?? null,
      durable: body.trust?.runtime?.durable === true,
      blocker: body.trust?.blocker ?? body.trust?.runtime?.blocker ?? null,
      category: body.trust?.blocker ? blockerCategory(body.trust.blocker) : null,
      summary: body.trust?.blocker ? `durable evidence blocked: ${body.trust.blocker}` : "status read completed"
    },
    blocker,
    capabilityBlocker: blocker,
    trustBlocker,
    blockers,
    readiness: {
      status: ready ? "ready" : "blocked",
      controlReady: ready,
      capabilityLevel: ready ? HWLAB_M3_IO_CAPABILITY_LEVELS.readonly : HWLAB_M3_IO_CAPABILITY_LEVELS.blocked,
      route: HWLAB_M3_STATUS_API_ROUTE,
      blocker,
      trustBlocker
    },
    result: {
      value: body.boxes?.find?.((box) => box?.resourceId === "res_boxsimu_2")?.ports?.DI1?.value ?? null,
      targetReadback: null
    },
    readback: {
      status: body.status ?? null,
      value: body.boxes?.find?.((box) => box?.resourceId === "res_boxsimu_2")?.ports?.DI1?.value ?? null,
      resourceId: "res_boxsimu_2",
      port: "DI1"
    },
    statusSummary: {
      sourceKind: body.sourceKind ?? null,
      readinessStatus: body.readinessStatus ?? null,
      gateways: Array.isArray(body.gateways) ? body.gateways.map((gateway) => ({
        id: gateway.id,
        online: gateway.online,
        blocker: gateway.blocker ?? null
      })) : [],
      boxes: Array.isArray(body.boxes) ? body.boxes.map((box) => ({
        id: box.id,
        resourceId: box.resourceId,
        online: box.online,
        ports: box.ports
      })) : [],
      patchPanel: body.patchPanel ? {
        serviceId: body.patchPanel.serviceId,
        observable: body.patchPanel.observable,
        connectionActive: body.patchPanel.connectionActive,
        blocker: body.patchPanel.blocker ?? null,
        lastError: body.patchPanel.lastError ?? null
      } : null
    },
    controlPath: {
      cloudApi: true,
      gatewaySimu: false,
      boxSimu: false,
      patchPanel: false,
      frontendBypass: false
    },
    safety: {
      cloudApiRouteOnly: false,
      allowedRoute: HWLAB_M3_STATUS_API_ROUTE,
      directGatewayCalls: true,
      directBoxCalls: true,
      directPatchPanelCalls: true,
      fallbackUsed: false,
      openAiFallbackUsed: false
    },
    httpStatus: response.status,
    error: response.ok ? body.error ?? null : {
      code: "hwlab_api_unavailable",
      layer: "hwlab-api",
      blocker,
      retryable: true,
      userMessage: "HWLAB API 当前不可达，M3 状态未读取，可稍后重试。",
      message: response.error ?? "HWLAB API request failed",
      traceId,
      route: HWLAB_M3_STATUS_API_ROUTE,
      toolName: HWLAB_M3_IO_SKILL_NAME
    },
    rawStatus: body.status ?? null,
    startedAt,
    finishedAt
  };
}

function blockedPayload({ traceId, requestId, actorId = "usr_code_agent", apiTarget, code, message, missingConfig = [], approval = null }) {
  const route = apiTarget?.route ?? HWLAB_M3_IO_API_ROUTE;
  const method = route === HWLAB_M3_STATUS_API_ROUTE ? "GET" : "POST";
  const capabilityBlocker = {
    code,
    layer: blockerLayer(code),
    message,
    zh: message,
    category: blockerCategory(code),
    retryable: retryableBlocker(code),
    userMessage: userMessageForBlocker(code, message),
    traceId,
    route,
    toolName: HWLAB_M3_IO_SKILL_NAME,
    missingConfig: sanitizeMissingConfig(missingConfig)
  };
  return {
    ok: false,
    service: HWLAB_M3_IO_SKILL_NAME,
    contractVersion: HWLAB_AGENT_RUNTIME_SKILL_CLI_VERSION,
    route,
    method,
    hwlabApi: publicCloudApiTarget(apiTarget),
    capabilityLevel: HWLAB_M3_IO_CAPABILITY_LEVELS.blocked,
    controlReady: false,
    accepted: false,
    status: "blocked",
    traceId,
    requestId,
    actorId,
    approval: approvalPayload(approval) ?? approvalForAction(null),
    operationId: null,
    auditId: null,
    evidenceId: null,
    audit: {
      auditId: null,
      status: "not_written",
      durableStatus: null,
      summary: "blocked before HWLAB API request"
    },
    evidence: {
      evidenceId: null,
      status: "blocked",
      sourceKind: "BLOCKED",
      blocker: code,
      writeStatus: "not_written",
      summary: "blocked before HWLAB API request"
    },
    durable: {
      status: "blocked",
      blocker: code,
      summary: message
    },
    blocker: capabilityBlocker,
    capabilityBlocker,
    trustBlocker: null,
    blockers: [capabilityBlocker],
    readiness: {
      status: "blocked",
      controlReady: false,
      capabilityLevel: HWLAB_M3_IO_CAPABILITY_LEVELS.blocked,
      route,
      blocker: capabilityBlocker,
      trustBlocker: null
    },
    safety: {
      cloudApiRouteOnly: false,
      allowedRoute: route,
      directGatewayCalls: true,
      directBoxCalls: true,
      directPatchPanelCalls: true,
      fallbackUsed: false,
      openAiFallbackUsed: false
    },
    error: {
      code,
      layer: capabilityBlocker.layer,
      blocker: capabilityBlocker,
      retryable: capabilityBlocker.retryable,
      userMessage: capabilityBlocker.userMessage,
      message,
      traceId,
      route,
      toolName: HWLAB_M3_IO_SKILL_NAME,
      missingConfig: capabilityBlocker.missingConfig
    }
  };
}

function normalizeStatusBlocker(body, response) {
  if (!response.ok) {
    return normalizeBlocker(body, response, {
      route: HWLAB_M3_STATUS_API_ROUTE,
      unavailableUserMessage: "HWLAB API 当前不可达，M3 状态未读取，可稍后重试。",
      defaultMessage: "M3 status request was blocked."
    });
  }
  const raw = body.blocker ?? body.error ?? null;
  const trustBlockerCode = body.trust?.blocker ?? null;
  if (!raw && !trustBlockerCode && !["blocked", "error", "failed"].includes(String(body.status ?? "").toLowerCase())) {
    return null;
  }
  const code = raw?.code ?? trustBlockerCode ?? "m3_status_blocked";
  return {
    code,
    layer: blockerLayer(code),
    message: raw?.message ?? raw?.reason ?? raw?.zh ?? body.summary ?? "M3 status request was blocked.",
    zh: raw?.zh ?? raw?.message ?? raw?.reason ?? body.summary ?? "M3 status request was blocked.",
    category: blockerCategory(code),
    retryable: retryableBlocker(code),
    userMessage: raw?.userMessage ?? raw?.zh ?? userMessageForBlocker(code, raw?.message ?? raw?.reason),
    traceId: body.traceId ?? body.trust?.traceId ?? null,
    route: HWLAB_M3_STATUS_API_ROUTE,
    toolName: HWLAB_M3_IO_SKILL_NAME
  };
}

function normalizeBlocker(body, response, options = {}) {
  const route = options.route ?? HWLAB_M3_IO_API_ROUTE;
  const unavailableUserMessage = options.unavailableUserMessage ?? "HWLAB API 当前不可达，M3 控制未执行，可稍后重试。";
  const defaultMessage = options.defaultMessage ?? "M3 IO request was blocked.";
  const raw = body.blocker ?? body.error ?? null;
  if (raw) {
    const code = raw.code ?? body.blockerClassification?.code ?? "m3_io_blocked";
    return {
      code,
      layer: blockerLayer(code),
      message: raw.message ?? raw.reason ?? raw.zh ?? body.blockerClassification?.reason ?? defaultMessage,
      zh: raw.zh ?? raw.message ?? raw.reason ?? defaultMessage,
      category: body.blockerClassification?.category ?? blockerCategory(code),
      retryable: retryableBlocker(code),
      userMessage: raw.userMessage ?? raw.zh ?? userMessageForBlocker(code, raw.message ?? raw.reason, { route }),
      traceId: body.traceId ?? null,
      route,
      toolName: HWLAB_M3_IO_SKILL_NAME
    };
  }
  if (!response.ok) {
    return {
      code: "hwlab_api_unavailable",
      layer: "hwlab-api",
      message: response.error ?? `HWLAB API HTTP ${response.status}`,
      zh: response.error ?? `HWLAB API HTTP ${response.status}`,
      category: "hwlab_api",
      retryable: true,
      userMessage: unavailableUserMessage,
      route,
      toolName: HWLAB_M3_IO_SKILL_NAME
    };
  }
  return null;
}

function normalizeCapabilityBlocker(blocker, response) {
  if (blocker) return blocker;
  return {
    code: response.ok ? "hwlab_api_control_blocked" : "hwlab_api_unavailable",
    layer: response.ok ? "m3-readiness" : "hwlab-api",
    message: response.ok ? "HWLAB API did not accept the M3 IO control request." : response.error ?? "HWLAB API request failed",
    zh: response.ok ? "HWLAB API 未接受 M3 IO 控制请求。" : response.error ?? "HWLAB API 请求失败",
    category: response.ok ? "readiness_blocked" : "hwlab_api",
    retryable: !response.ok,
    userMessage: response.ok ? "M3 控制链路尚未就绪，不能标记为真实可控。" : "HWLAB API 当前不可达，M3 控制未执行，可稍后重试。",
    route: HWLAB_M3_IO_API_ROUTE,
    toolName: HWLAB_M3_IO_SKILL_NAME
  };
}

function normalizeTrustBlocker(body, route = HWLAB_M3_IO_API_ROUTE) {
  const code = body.evidenceState?.blocker ?? body.durableStatus?.blocker ?? body.trust?.blocker ?? null;
  if (!code) return null;
  return {
    code,
    message: `Durable trust is blocked: ${code}`,
    zh: `可信持久化仍 blocked：${code}`,
    category: blockerCategory(code),
    layer: "runtime-durable",
    retryable: false,
    userMessage: "M3 可信持久化仍受阻，不能作为 DEV-LIVE 可信闭环通过。",
    route,
    toolName: HWLAB_M3_IO_SKILL_NAME,
    source: body.evidenceState?.blocker ? "evidenceState.blocker" : "durableStatus.blocker"
  };
}

function dedupeBlockers(blockers) {
  const seen = new Set();
  const result = [];
  for (const blocker of blockers) {
    if (!blocker?.code) continue;
    const key = `${blocker.code}:${blocker.layer ?? ""}:${blocker.category ?? ""}`;
    if (seen.has(key)) continue;
    seen.add(key);
    result.push(blocker);
  }
  return result;
}

function blockerCategory(code) {
  const value = String(code ?? "");
  if (/api_base_url|invalid_hwlab_api_url/u.test(value)) return "hwlab_api_configuration";
  if (/readiness|control_disabled|not_ready/u.test(value)) return "readiness_blocked";
  if (/gateway/u.test(value)) return "gateway_unavailable";
  if (/box|resource/u.test(value)) return "box_unavailable";
  if (/wiring|patch_panel|patch-panel/u.test(value)) return "patch_panel_wiring_missing";
  if (/durable|runtime/u.test(value)) return "durable_blocked";
  if (/direct_hardware/u.test(value)) return "direct_hardware_blocked";
  return "m3_io_blocked";
}

function blockerLayer(code) {
  const value = String(code ?? "");
  if (value === "skill_cli_api_base_missing") return "skill-cli-config";
  if (value === "hwlab_api_unavailable") return "hwlab-api";
  if (/direct_hardware|invalid_hwlab_api_route|invalid_hwlab_api_url/u.test(value)) return "security";
  if (/durable|runtime/u.test(value)) return "runtime-durable";
  if (/readiness|control|gateway|box|resource|wiring|patch/u.test(value)) return "m3-readiness";
  return "skill-cli";
}

function retryableBlocker(code) {
  return ["hwlab_api_unavailable"].includes(String(code ?? ""));
}

function userMessageForBlocker(code, message, options = {}) {
  if (code === "skill_cli_api_base_missing") return "M3 Skill CLI 缺少 HWLAB API base URL 配置，需要补齐安全 env 或 contract。";
  if (code === "hwlab_api_unavailable") {
    return options.route === HWLAB_M3_STATUS_API_ROUTE
      ? "HWLAB API 当前不可达，M3 状态未读取，可稍后重试。"
      : "HWLAB API 当前不可达，M3 控制未执行，可稍后重试。";
  }
  if (/durable|runtime/u.test(String(code ?? ""))) return "M3 可信持久化仍受阻，不能作为 DEV-LIVE 可信闭环通过。";
  return message || "M3 控制链路仍受阻，前端应显示为能力未就绪。";
}

function sanitizeMissingConfig(values) {
  return Array.isArray(values)
    ? values.filter((value) => typeof value === "string" && /^[A-Za-z0-9_./:-]+$/u.test(value))
    : [];
}

function durableSummary(body) {
  const status = body.durableStatus?.status ?? body.evidenceState?.status ?? null;
  const blocker = body.durableStatus?.blocker ?? body.evidenceState?.blocker ?? null;
  return {
    status,
    durable: body.durableStatus?.durable ?? false,
    blocker,
    category: blocker ? blockerCategory(blocker) : null,
    summary: blocker
      ? `durable evidence blocked: ${blocker}`
      : status
        ? `durable status: ${status}`
        : "durable status not reported"
  };
}

function auditSummary(body) {
  if (body.auditId) {
    return `${body.auditId}; auditState=${body.auditState?.status ?? "unknown"}`;
  }
  return body.auditState?.reason ?? "audit not written";
}

function evidenceSummary(body) {
  if (body.evidenceId) {
    return `${body.evidenceId}; evidenceState=${body.evidenceState?.status ?? "unknown"}`;
  }
  return body.evidenceState?.reason ?? "evidence not written";
}

function normalizeReadback(body, command) {
  if (command.action === "do.write") {
    return body.result?.targetReadback ?? null;
  }
  if (command.action === "di.read") {
    return {
      status: body.status ?? null,
      value: body.result?.value ?? body.value ?? null,
      resourceId: command.resourceId,
      port: command.port
    };
  }
  return null;
}

function helpPayload() {
  return {
    ok: true,
    service: HWLAB_M3_IO_SKILL_NAME,
    contractVersion: HWLAB_AGENT_RUNTIME_SKILL_CLI_VERSION,
    usage: [
      `node skills/hwlab-agent-runtime/scripts/hwlab-agent-runtime-cli.mjs m3 io --action do.write --value true --api-base-url ${HWLAB_M3_IO_DEV_SERVICE_BASE_URL}`,
      `node skills/hwlab-agent-runtime/scripts/hwlab-agent-runtime-cli.mjs m3 io --action do.write --value false --api-base-url ${HWLAB_M3_IO_DEV_SERVICE_BASE_URL}`,
      `node skills/hwlab-agent-runtime/scripts/hwlab-agent-runtime-cli.mjs m3 io --action di.read --api-base-url ${HWLAB_M3_IO_DEV_SERVICE_BASE_URL}`,
      `node skills/hwlab-agent-runtime/scripts/hwlab-agent-runtime-cli.mjs m3 status --api-base-url ${HWLAB_M3_IO_DEV_SERVICE_BASE_URL}`
    ],
    env: {
      recommended: HWLAB_M3_IO_API_BASE_URL_ENV,
      supported: [...HWLAB_M3_IO_API_BASE_URL_ENVS],
      devValue: HWLAB_M3_IO_DEV_SERVICE_BASE_URL
    },
    routes: [HWLAB_M3_IO_API_ROUTE, HWLAB_M3_STATUS_API_ROUTE],
    safety: {
      cloudApiRouteOnly: false,
      directGatewayCalls: true,
      directBoxCalls: true,
      directPatchPanelCalls: true,
      fallbackUsed: false,
      writeApprovalRequired: true
    },
    allowlist: []
  };
}

function approvalForParsed(parsed, command) {
  const required = command.action === "do.write";
  const approved = required ? parsed.approved === true : true;
  const policy = parsed.policy || (required ? "hwlab-api-control-with-approval" : "hwlab-api-readonly");
  const reason = parsed.approvalReason || (required ? "explicit user requested DO write" : "readonly DI read");
  if (required && !approved) {
    return {
      required,
      approved: false,
      policy,
      reason,
      blocker: {
        code: "approval_required",
        message: "M3 DO write requires --approved or --confirm-control so the Skill CLI records explicit controlled approval semantics."
      }
    };
  }
  return {
    required,
    approved,
    policy,
    reason
  };
}

function approvalForAction(action) {
  const required = action === "do.write";
  return {
    required,
    approved: !required,
    policy: required ? "hwlab-api-control-with-approval" : "hwlab-api-readonly",
    reason: required ? null : "readonly or blocked before command normalization"
  };
}

function approvalPayload(approval) {
  if (!approval || typeof approval !== "object") return null;
  return {
    required: approval.required === true,
    approved: approval.approved === true,
    policy: approval.policy ?? null,
    reason: approval.reason ?? null
  };
}

function readOption(args, index, name) {
  const value = args[index];
  if (!value || value.startsWith("--")) {
    throw new Error(`${name} requires a value`);
  }
  return value;
}

function parseBoolean(value) {
  const normalized = String(value ?? "").trim().toLowerCase();
  if (["true", "1", "on", "high"].includes(normalized)) return true;
  if (["false", "0", "off", "low"].includes(normalized)) return false;
  return value;
}

function parseTimeout(value) {
  const parsed = Number.parseInt(value, 10);
  if (!Number.isInteger(parsed) || parsed <= 0 || parsed > 60000) {
    throw new Error("--timeout-ms must be an integer between 1 and 60000");
  }
  return parsed;
}

export function configuredCloudApiBaseUrl(env = process.env) {
  return firstNonEmpty(...HWLAB_M3_IO_API_BASE_URL_ENVS.map((name) => env[name]));
}

function cloudApiBaseUrlSource(apiBaseUrl, env = process.env) {
  if (apiBaseUrl) return "explicit";
  for (const name of HWLAB_M3_IO_API_BASE_URL_ENVS) {
    if (firstNonEmpty(env[name])) return `env:${name}`;
  }
  return "missing-config";
}

function ensureTrailingSlash(value) {
  return String(value ?? "").endsWith("/") ? String(value) : `${value}/`;
}

function firstNonEmpty(...values) {
  return values.find((value) => typeof value === "string" && value.trim())?.trim() ?? null;
}

function redactUrl(value) {
  try {
    const url = new URL(value);
    url.username = "";
    url.password = "";
    return url.toString();
  } catch {
    return String(value ?? "").replace(/\/\/[^/@]+@/u, "//***@");
  }
}

function publicCloudApiTarget(apiTarget) {
  if (!apiTarget || typeof apiTarget !== "object") return null;
  const directHardwareTarget = apiTarget.url ? isDirectHardwareServiceHost(safeHostname(apiTarget.url)) : false;
  const redactedUrl = directHardwareTarget ? null : apiTarget.redactedUrl ?? (apiTarget.url ? redactUrl(apiTarget.url) : null);
  return {
    route: apiTarget.route ?? HWLAB_M3_IO_API_ROUTE,
    redactedUrl,
    source: apiTarget.source ?? null,
    missingConfig: sanitizeMissingConfig(apiTarget.missingConfig ?? []),
    cloudApiOnly: apiTarget.cloudApiOnly === true,
    directGatewayCalls: apiTarget.directGatewayCalls === true,
    directBoxCalls: apiTarget.directBoxCalls === true,
    directPatchPanelCalls: apiTarget.directPatchPanelCalls === true
  };
}

function safeHostname(value) {
  try {
    return new URL(value).hostname;
  } catch {
    return "";
  }
}

function responseSummary(body = {}) {
  return {
    serviceId: body.serviceId ?? null,
    contractVersion: body.contractVersion ?? null,
    status: body.status ?? null,
    accepted: body.accepted ?? null,
    action: body.action ?? null,
    operationId: body.operationId ?? null,
    traceId: body.traceId ?? null,
    auditId: body.auditId ?? body.auditState?.auditId ?? null,
    evidenceId: body.evidenceId ?? body.evidenceState?.evidenceId ?? null,
    blockerCode: body.blocker?.code ?? body.error?.code ?? body.evidenceState?.blocker ?? body.durableStatus?.blocker ?? null,
    controlPath: body.controlPath ? {
      cloudApi: body.controlPath.cloudApi ?? null,
      gatewaySimu: body.controlPath.gatewaySimu ?? null,
      boxSimu: body.controlPath.boxSimu ?? null,
      patchPanel: body.controlPath.patchPanel ?? null,
      frontendBypass: body.controlPath.frontendBypass ?? null
    } : null
  };
}

function parseJsonOrNull(value) {
  try {
    return JSON.parse(value);
  } catch {
    return null;
  }
}

function nowIso(now) {
  return typeof now === "function" ? now() : new Date().toISOString();
}
