import { randomUUID } from "node:crypto";
import { readdirSync, statSync } from "node:fs";
import { mkdir, readFile, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";

import {
  M3_IO_CHAIN,
  M3_IO_CONTROL_CONTRACT_VERSION,
  M3_IO_CONTROL_ROUTE,
  describeM3IoControl
} from "../../internal/cloud/m3-io-control.ts";

export const M3_IO_E2E_CONTRACT_VERSION = "m3-io-control-e2e-v1";
export const defaultFrontendUrl = "http://74.48.78.17:16666/";
export const defaultApiUrl = "http://74.48.78.17:16667/v1/m3/io";
export const controlPathReachablePersistenceBlocked = "control_path_reachable_trusted_persistence_blocked";

const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "../..");
const labels = Object.freeze({
  source: "SOURCE",
  local: "LOCAL",
  dryRun: "DRY-RUN",
  devLive: "DEV-LIVE",
  blocked: "BLOCKED"
});

const forbiddenLiveFlags = Object.freeze([
  "--prod",
  "--production",
  "--real-hardware",
  "--read-secret",
  "--read-token",
  "--deploy",
  "--apply",
  "--restart",
  "--restart-runtime",
  "--restart-unidesk",
  "--restart-code-queue",
  "--restart-backend-core"
]);

const valueFlags = new Set(["--report", "--output", "--url", "--api-url", "--target", "--timeout-ms"]);
const booleanFlags = new Set([
  "--live",
  "--confirm-dev",
  "--confirmed-non-production",
  "--expect-non-prod",
  "--source",
  "--source-static",
  "--dry-run",
  "--pretty",
  ...forbiddenLiveFlags
]);

export function parseM3IoControlE2eArgs(argv = []) {
  const flags = new Set();
  const values = new Map();

  for (let index = 0; index < argv.length; index += 1) {
    const arg = argv[index];
    if (!arg.startsWith("--")) {
      throw new Error(`unexpected positional argument: ${arg}`);
    }

    if (valueFlags.has(arg)) {
      const value = argv[index + 1];
      if (!value || value.startsWith("--")) {
        throw new Error(`${arg} requires a value`);
      }
      values.set(arg.slice(2), value);
      index += 1;
      continue;
    }

    if (!booleanFlags.has(arg)) {
      throw new Error(`unknown flag: ${arg}`);
    }
    flags.add(arg);
  }

  const target = values.get("target") ?? (values.has("api-url") ? "api" : "frontend");
  if (!["frontend", "api"].includes(target)) {
    throw new Error("--target must be frontend or api");
  }

  const timeoutMs = parsePositiveInteger(values.get("timeout-ms"), 8000);
  return {
    flags,
    values,
    live: flags.has("--live"),
    source: flags.has("--source") || flags.has("--source-static"),
    dryRun: flags.has("--dry-run"),
    confirmDev: flags.has("--confirm-dev"),
    confirmedNonProduction: flags.has("--confirmed-non-production") || flags.has("--expect-non-prod"),
    target,
    frontendUrl: values.get("url") ?? defaultFrontendUrl,
    apiUrl: values.get("api-url") ?? defaultApiUrl,
    reportPath: values.get("report") ?? values.get("output") ?? null,
    timeoutMs,
    pretty: flags.has("--pretty")
  };
}

export function requireM3IoControlE2eGates(args) {
  for (const flag of forbiddenLiveFlags) {
    if (args.flags.has(flag)) {
      throw new Error(`${flag} is forbidden for the DEV M3 IO control harness`);
    }
  }

  if (!args.live) {
    return {
      mode: "source-static",
      liveWriteAllowed: false,
      mutationAllowed: false
    };
  }

  if (args.dryRun || args.source) {
    throw new Error("--live cannot be combined with --dry-run, --source, or --source-static");
  }

  if (!args.confirmDev || !args.confirmedNonProduction) {
    throw new Error("live mode requires --live --confirm-dev --confirmed-non-production");
  }

  return {
    mode: "dev-live",
    liveWriteAllowed: true,
    mutationAllowed: true
  };
}

export function expectedM3IoLiveSequence() {
  return [
    {
      id: "write-do1-true",
      method: "POST",
      path: M3_IO_CONTROL_ROUTE,
      action: "do.write",
      expectedValue: true,
      mutatesDevState: true,
      request: doWriteRequest(true)
    },
    {
      id: "read-di1-true",
      method: "POST",
      path: M3_IO_CONTROL_ROUTE,
      action: "di.read",
      expectedValue: true,
      mutatesDevState: false,
      request: diReadRequest()
    },
    {
      id: "write-do1-false",
      method: "POST",
      path: M3_IO_CONTROL_ROUTE,
      action: "do.write",
      expectedValue: false,
      mutatesDevState: true,
      request: doWriteRequest(false)
    },
    {
      id: "read-di1-false",
      method: "POST",
      path: M3_IO_CONTROL_ROUTE,
      action: "di.read",
      expectedValue: false,
      mutatesDevState: false,
      request: diReadRequest()
    }
  ];
}

export async function buildM3IoControlSourceReport(options = {}) {
  const root = options.repoRoot ?? repoRoot;
  const checks = await runM3IoControlSourceChecks({ repoRoot: root });
  const classification = checks.every((check) => check.status === "pass")
    ? "source_static_contract_checked"
    : "source_contract_failed";
  const status = classification === "source_static_contract_checked" ? "pass" : "blocked";

  return {
    tool: "m3-io-control-e2e",
    contractVersion: M3_IO_E2E_CONTRACT_VERSION,
    mode: "source-static",
    sourceKind: labels.source,
    evidenceLabels: evidenceLabelDescriptions(),
    liveMutation: {
      attempted: false,
      allowed: false,
      reason: "Default SOURCE/static mode never POSTs to DEV and never mutates simulator state."
    },
    endpoints: {
      frontendSameOriginBase: defaultFrontendUrl,
      frontendSameOriginPath: M3_IO_CONTROL_ROUTE,
      cloudApiPath: M3_IO_CONTROL_ROUTE,
      directCloudApiEndpoint: defaultApiUrl,
      gatewayBoxPatchPanelDirectCallsAllowed: false
    },
    dryRunPlan: {
      sourceKind: labels.dryRun,
      liveWriteWillRun: false,
      sequence: expectedM3IoLiveSequence().map((step) => ({
        id: step.id,
        method: step.method,
        path: step.path,
        action: step.action,
        expectedValue: step.expectedValue,
        mutatesDevState: step.mutatesDevState
      }))
    },
    checks,
    summary: {
      status,
      classification,
      trustedGreen: false,
      observedAt: isoNow(),
      result: status === "pass"
        ? "SOURCE/static M3 IO control contract passed; DEV-LIVE was not run."
        : "SOURCE/static M3 IO control contract failed; DEV-LIVE must not run until fixed."
    }
  };
}

export async function runM3IoControlSourceChecks({ repoRoot: root = repoRoot } = {}) {
  const [serverSource, jsonRpcSource, m3Source, appSource, htmlSource, artifactPublisherSource, cloudWebRouteSource] = await Promise.all([
    readRepoText(root, "internal/cloud/server.ts"),
    readRepoText(root, "internal/cloud/json-rpc.ts"),
    readRepoText(root, "internal/cloud/m3-io-control.ts"),
    readCloudWebReactSource(root),
    readRepoText(root, "web/hwlab-cloud-web/index.html"),
    readRepoText(root, "scripts/artifact-publish.mjs"),
    readRepoText(root, "internal/dev-entrypoint/cloud-web-routes.mjs")
  ]);

  const contract = describeM3IoControl({
    env: {
      HWLAB_M3_IO_CONTROL_ENABLED: "true"
    }
  });
  const frontendGuardrails = checkFrontendNoDirectRuntimeCalls({
    appSource,
    htmlSource,
    artifactPublisherSource,
    cloudWebRouteSource
  });
  const requestSchema = validateExpectedRequestSchemas(expectedM3IoLiveSequence());
  const responseSchema = validateM3IoSourceResponseContract(m3Source);

  return [
    checkResult(
      "route-name-contract",
      contract.route === M3_IO_CONTROL_ROUTE &&
        M3_IO_CONTROL_ROUTE === "/v1/m3/io" &&
        contract.contractVersion === M3_IO_CONTROL_CONTRACT_VERSION,
      "cloud-api route is /v1/m3/io with the m3-io-control-v1 contract.",
      {
        route: contract.route,
        contractVersion: contract.contractVersion,
        evidenceLevel: labels.source
      }
    ),
    checkResult(
      "m3-chain-contract",
      routeChainMatches(contract.chain),
      "M3 chain is box-simu-1 DO1 -> hwlab-patch-panel -> box-simu-2 DI1.",
      {
        chain: contract.chain,
        evidenceLevel: labels.source
      }
    ),
    checkResult(
      "cloud-api-rest-route-contract",
      serverSource.includes("url.pathname === M3_IO_CONTROL_ROUTE") &&
        serverSource.includes("handleM3IoControlHttp") &&
        serverSource.includes("m3IoControl: describeM3IoControl"),
      "cloud-api exposes GET/POST /v1/m3/io and advertises it from /v1.",
      {
        route: M3_IO_CONTROL_ROUTE,
        evidenceLevel: labels.source
      }
    ),
    checkResult(
      "cloud-api-json-rpc-method-contract",
      jsonRpcSource.includes("M3_IO_RPC_METHODS.doWrite") &&
        jsonRpcSource.includes("M3_IO_RPC_METHODS.diRead") &&
        jsonRpcSource.includes('handleM3IoRpc("do.write"') &&
        jsonRpcSource.includes('handleM3IoRpc("di.read"'),
      "cloud-api JSON-RPC exposes M3 do.write and di.read through the same controlled handler.",
      {
        methods: ["m3.io.do.write", "m3.io.di.read"],
        evidenceLevel: labels.source
      }
    ),
    checkResult(
      "request-schema-contract",
      requestSchema.status === "pass",
      "Expected DEV live sequence uses only do.write on DO1 and di.read on DI1.",
      {
        issues: requestSchema.issues,
        sequence: requestSchema.sequence,
        evidenceLevel: labels.dryRun
      }
    ),
    checkResult(
      "response-schema-contract",
      responseSchema.status === "pass",
      "M3 IO responses carry operationId, traceId, auditId, evidenceId, evidenceState, and frontendBypass=false.",
      {
        issues: responseSchema.issues,
        evidenceLevel: labels.source
      }
    ),
    checkResult(
      "frontend-same-origin-guardrail",
      frontendGuardrails.status === "pass",
      "Cloud Web only calls same-origin /v1/m3/io for the user control path and has no direct gateway/box/patch-panel fetches.",
      {
        fetchTargets: frontendGuardrails.fetchTargets,
        issues: frontendGuardrails.issues,
        evidenceLevel: labels.source
      }
    )
  ];
}

async function readCloudWebReactSource(root) {
  const sourceRoot = path.join(root, "web/hwlab-cloud-web/src");
  const files = listCloudWebSourceFiles(sourceRoot);
  const parts = await Promise.all(files.map((file) => readFile(file, "utf8")));
  return parts.join("\n");
}

function listCloudWebSourceFiles(dir) {
  const files = [];
  for (const entry of readdirSync(dir)) {
    const full = path.join(dir, entry);
    const stat = statSync(full);
    if (stat.isDirectory()) files.push(...listCloudWebSourceFiles(full));
    else if (/\.(ts|tsx|css)$/u.test(full)) files.push(full);
  }
  return files.sort();
}

export function checkFrontendNoDirectRuntimeCalls({ appSource, htmlSource = "", artifactPublisherSource = "", cloudWebRouteSource = "" }) {
  const source = `${appSource}\n${htmlSource}`;
  const fetchTargets = literalFetchTargets(appSource);
  const issues = [];
  const allowedSameOriginTargets = new Set([
    "/help.md",
    "/health/live",
    "/v1",
    "/v1/diagnostics/gate",
    "/v1/live-builds",
    "/v1/agent/chat",
    "/v1/agent/chat/cancel",
    "/v1/m3/io",
    "/v1/m3/status",
    "/json-rpc"
  ]);

  for (const target of fetchTargets) {
    if (!target.startsWith("/")) {
      issues.push(`frontend fetch target is not same-origin relative: ${target}`);
    }
    if (target.startsWith("/") && !allowedSameOriginTargets.has(target)) {
      issues.push(`frontend fetch target is not in the allowed same-origin set: ${target}`);
    }
  }

  const directRuntimePatterns = [
    /\bfetch(?:Json)?\(\s*["'`][^"'`]*(?:gateway-simu|box-simu|patch-panel|:7101|:7201|:7301)/iu,
    /\bfetch(?:Json)?\(\s*["'`]https?:\/\//iu,
    /https?:\/\/[^"'`\s]*(?:gateway-simu|box-simu|patch-panel|:7101|:7201|:7301)/iu,
    /(?:\/invoke|\/sync\/tick)/iu
  ];
  for (const pattern of directRuntimePatterns) {
    if (pattern.test(source)) {
      issues.push(`frontend source matches forbidden direct runtime pattern: ${pattern.source}`);
    }
  }

  const actionBody = functionBody(appSource, "runM3IoAction");
  if (!/fetchJson\("\/v1\/m3\/io"/u.test(actionBody)) {
    issues.push("runM3IoAction must POST through same-origin /v1/m3/io");
  }
  if (/fetchJson\(["'`](?!\/v1\/m3\/(?:io|status))/u.test(actionBody) || /\bfetch\(/u.test(actionBody)) {
    issues.push("runM3IoAction must not call any path other than fetchJson(\"/v1/m3/io\") or fetchJson(\"/v1/m3/status\")");
  }
  if (!/if \(!m3ControlCanOperate\(\)\)/u.test(actionBody)) {
    issues.push("runM3IoAction must fail closed before POST when M3 readiness is blocked");
  }
  const readinessBody = functionBody(appSource, "m3ControlCanOperate");
  for (const [pattern, label] of [
    [/readiness\?\.status === "ready"/u, "readiness.status=ready"],
    [/readiness\?\.controlReady === true/u, "readiness.controlReady=true"],
    [/readiness\?\.sourceKind === "DEV-LIVE"/u, "readiness.sourceKind=DEV-LIVE"],
    [/readiness\?\.evidenceLevel === "DEV-LIVE"/u, "readiness.evidenceLevel=DEV-LIVE"]
  ]) {
    if (!pattern.test(readinessBody)) {
      issues.push(`m3ControlCanOperate must require ${label}`);
    }
  }
  const artifactUsesCloudWebRoutePolicy = /cloudWebProxyRoutePolicy\(request\.method,\s*url\.pathname\)/u.test(artifactPublisherSource);
  const routePolicyProxiesM3Io = artifactUsesCloudWebRoutePolicy &&
    new RegExp(`"${escapeRegExp(M3_IO_CONTROL_ROUTE)}"`, "u").test(cloudWebRouteSource);
  const routePolicyProxiesV1Status = artifactUsesCloudWebRoutePolicy &&
    /const GET_PROXY_PREFIXES = Object\.freeze\(\["\/v1\/"\]\)/u.test(cloudWebRouteSource);
  if (!routePolicyProxiesM3Io && !/url\.pathname === "\/v1\/m3\/io"/u.test(artifactPublisherSource)) {
    issues.push("cloud-web artifact server must proxy same-origin /v1/m3/io to cloud-api");
  }
  if (!routePolicyProxiesV1Status && !/\/v1\/m3\/status/u.test(artifactPublisherSource)) {
    issues.push("cloud-web artifact server must proxy same-origin /v1/m3/status to cloud-api");
  }

  return {
    status: issues.length === 0 ? "pass" : "fail",
    fetchTargets,
    issues
  };
}

export function validateExpectedRequestSchemas(sequence) {
  const issues = [];
  for (const step of sequence) {
    if (step.path !== M3_IO_CONTROL_ROUTE || step.method !== "POST") {
      issues.push(`${step.id} must POST ${M3_IO_CONTROL_ROUTE}`);
    }
    if (!["do.write", "di.read"].includes(step.request.action)) {
      issues.push(`${step.id} action is invalid`);
    }
    if (step.request.action === "do.write") {
      if (
        step.request.gatewayId !== M3_IO_CHAIN.sourceGatewayId ||
        step.request.resourceId !== M3_IO_CHAIN.sourceResourceId ||
        step.request.boxId !== M3_IO_CHAIN.sourceBoxId ||
        step.request.port !== M3_IO_CHAIN.sourcePort ||
        typeof step.request.value !== "boolean"
      ) {
        issues.push(`${step.id} must write ${M3_IO_CHAIN.sourceResourceId}:${M3_IO_CHAIN.sourcePort} with a boolean value`);
      }
    }
    if (step.request.action === "di.read") {
      if (
        step.request.gatewayId !== M3_IO_CHAIN.targetGatewayId ||
        step.request.resourceId !== M3_IO_CHAIN.targetResourceId ||
        step.request.boxId !== M3_IO_CHAIN.targetBoxId ||
        step.request.port !== M3_IO_CHAIN.targetPort ||
        Object.hasOwn(step.request, "value")
      ) {
        issues.push(`${step.id} must read ${M3_IO_CHAIN.targetResourceId}:${M3_IO_CHAIN.targetPort} without a value`);
      }
    }
  }

  return {
    status: issues.length === 0 ? "pass" : "fail",
    issues,
    sequence: sequence.map((step) => ({
      id: step.id,
      action: step.request.action,
      gatewayId: step.request.gatewayId,
      resourceId: step.request.resourceId,
      boxId: step.request.boxId,
      port: step.request.port,
      value: Object.hasOwn(step.request, "value") ? step.request.value : undefined
    }))
  };
}

export function validateM3IoSourceResponseContract(m3Source) {
  const requiredPatterns = [
    /operationId:\s*input\.operation\.operationId/u,
    /traceId:\s*input\.meta\.traceId/u,
    /auditId:\s*records\.auditEvent\.auditId/u,
    /evidenceId:\s*records\.evidenceRecord\.evidenceId/u,
    /gatewaySessionId:\s*target\.gatewaySessionId/u,
    /resourceId:\s*target\.resourceId/u,
    /port:\s*target\.port/u,
    /value:\s*target\.value/u,
    /const\s+audit\s*=\s*auditState\(/u,
    /const\s+evidence\s*=\s*evidenceState\(/u,
    /auditState:\s*audit/u,
    /evidenceState:\s*evidence/u,
    /durableStatus:\s*durableStatus\(/u,
    /blockerClassification:\s*redactedBlockerClassification\(/u,
    /persistence:\s*persistenceSummary\(/u,
    /describeM3IoControlLive/u,
    /buildM3IoReadiness/u,
    /controlReady:\s*false/u,
    /frontendBypass:\s*false/u,
    /patchPanelOnlyPropagation:\s*true/u,
    /sourceKind:\s*"DEV-LIVE"/u,
    /sourceKind:\s*"BLOCKED"/u
  ];
  const issues = requiredPatterns
    .filter((pattern) => !pattern.test(m3Source))
    .map((pattern) => `missing response contract pattern: ${pattern.source}`);

  return {
    status: issues.length === 0 ? "pass" : "fail",
    issues
  };
}

export function validateM3IoLiveResponse(payload, step) {
  const issues = [];
  if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
    return {
      status: "fail",
      issues: ["response body must be a JSON object"]
    };
  }
  for (const field of ["status", "accepted", "action", "chain", "controlPath", "traceId", "evidenceState"]) {
    if (!Object.hasOwn(payload, field)) {
      issues.push(`missing ${field}`);
    }
  }
  for (const field of ["operationId", "auditId", "evidenceId"]) {
    if (payload.status === "succeeded" && !stringValue(payload[field])) {
      issues.push(`missing ${field} on succeeded response`);
    }
  }
  if (payload.action !== step.action) {
    issues.push(`expected action ${step.action}, got ${payload.action}`);
  }
  if (payload.controlPath?.frontendBypass !== false) {
    issues.push("controlPath.frontendBypass must be false");
  }
  if (payload.controlPath?.cloudApi !== true || payload.controlPath?.gatewaySimu !== true || payload.controlPath?.boxSimu !== true) {
    issues.push("controlPath must prove cloudApi, gatewaySimu, and boxSimu were used");
  }
  if (step.action === "do.write" && payload.controlPath?.patchPanel !== true) {
    issues.push("do.write must prove patchPanel=true");
  }
  if (payload.chain && !routeChainMatches(payload.chain)) {
    issues.push("response chain does not match the required M3 DO1->DI1 route");
  }
  if (payload.status === "succeeded") {
    const actualValue = payload.result?.value;
    if (actualValue !== step.expectedValue) {
      issues.push(`expected result.value ${String(step.expectedValue)}, got ${String(actualValue)}`);
    }
  }

  return {
    status: issues.length === 0 ? "pass" : "fail",
    issues
  };
}

export function classifyM3IoControlReport(report) {
  const sourceChecks = report.checks ?? [];
  const operations = report.liveOperations ?? [];
  if (operations.length === 0) {
    if (sourceChecks.some((check) => check.status !== "pass")) {
      return {
        status: "blocked",
        classification: "source_contract_failed",
        trustedGreen: false
      };
    }
    return {
      status: "pass",
      classification: "source_static_contract_checked",
      trustedGreen: false
    };
  }

  if (operations.some((operation) => operation.status === "unreachable" || operation.status === "http_error")) {
    return {
      status: "blocked",
      classification: "control_path_unreachable",
      trustedGreen: false
    };
  }

  if (operations.some((operation) => operation.status !== "succeeded" || operation.schema?.status === "fail")) {
    return {
      status: "blocked",
      classification: "control_path_blocked",
      trustedGreen: false
    };
  }

  const expectedSequence = expectedM3IoLiveSequence();
  if (operations.length !== expectedSequence.length) {
    return {
      status: "blocked",
      classification: "m3_live_sequence_incomplete",
      trustedGreen: false
    };
  }

  const allTrusted = expectedSequence.every((step, index) => {
    const operation = operations[index] ?? {};
    return operation.id === step.id &&
    operation.action === step.action &&
    operation.sourceKind === labels.devLive &&
    operation.resultValue === step.expectedValue &&
    stringValue(operation.operationId) &&
    stringValue(operation.traceId) &&
    stringValue(operation.auditId) &&
    stringValue(operation.evidenceId) &&
    operation.evidenceState?.status === "green" &&
    operation.evidenceState?.sourceKind === labels.devLive &&
    operation.evidenceState?.durable === true &&
    operation.evidenceState?.writeStatus === "persisted";
  });

  if (!allTrusted) {
    return {
      status: "blocked",
      classification: controlPathReachablePersistenceBlocked,
      trustedGreen: false
    };
  }

  return {
    status: "pass",
    classification: "trusted_green",
    trustedGreen: true
  };
}

export async function runM3IoControlLiveReport(args, sourceReport) {
  const endpoint = resolveM3IoEndpoint(args);
  const contractProbe = await requestJson(endpoint.href, {
    method: "GET",
    timeoutMs: args.timeoutMs
  });
  const operations = [];
  const sourceChecks = sourceReport.checks ?? [];

  if (!contractProbe.ok) {
    operations.push({
      id: "contract-probe",
      status: "unreachable",
      sourceKind: labels.devLive,
      endpoint: endpoint.href,
      httpStatus: contractProbe.status,
      error: contractProbe.error
    });
  } else if (contractProbe.body?.route !== M3_IO_CONTROL_ROUTE || !routeChainMatches(contractProbe.body?.chain)) {
    operations.push({
      id: "contract-probe",
      status: "blocked",
      sourceKind: labels.devLive,
      endpoint: endpoint.href,
      httpStatus: contractProbe.status,
      error: "live /v1/m3/io contract did not match the source M3 route"
    });
  } else {
    for (const step of expectedM3IoLiveSequence()) {
      const operation = await postM3IoLiveStep(endpoint.href, step, args.timeoutMs);
      operations.push(operation);
      if (operation.status !== "succeeded") {
        break;
      }
    }
  }

  const report = {
    ...sourceReport,
    mode: "dev-live",
    sourceKind: labels.devLive,
    liveMutation: {
      attempted: true,
      allowed: true,
      reason: "DEV live mode was explicitly gated by --live --confirm-dev --confirmed-non-production."
    },
    endpoints: {
      ...sourceReport.endpoints,
      selectedTarget: args.target,
      selectedEndpoint: endpoint.href,
      selectedEndpointKind: endpoint.kind
    },
    contractProbe: {
      ok: contractProbe.ok,
      status: contractProbe.status,
      route: contractProbe.body?.route ?? null,
      chain: contractProbe.body?.chain ?? null,
      error: contractProbe.error ?? null
    },
    liveOperations: operations,
    summary: {
      ...sourceReport.summary,
      observedAt: isoNow()
    }
  };
  report.summary = {
    ...report.summary,
    ...classifyM3IoControlReport({ checks: sourceChecks, liveOperations: operations })
  };
  report.summary.result = resultTextForClassification(report.summary.classification);
  return report;
}

export function resolveM3IoEndpoint(args) {
  const endpoint = args.target === "api"
    ? new URL(args.apiUrl)
    : new URL(M3_IO_CONTROL_ROUTE, args.frontendUrl);

  const port = endpoint.port || (endpoint.protocol === "http:" ? "80" : "443");
  const allowed =
    endpoint.protocol === "http:" &&
    endpoint.hostname === "74.48.78.17" &&
    endpoint.pathname === M3_IO_CONTROL_ROUTE &&
    ((args.target === "frontend" && port === "16666") || (args.target === "api" && port === "16667"));

  if (!allowed) {
    throw new Error("live endpoint must match target: frontend uses DEV http://74.48.78.17:16666/v1/m3/io; api uses DEV http://74.48.78.17:16667/v1/m3/io");
  }

  return {
    href: endpoint.href,
    kind: port === "16666" ? "cloud-web-same-origin" : "cloud-api-direct",
    port: Number(port)
  };
}

export async function runM3IoControlE2eCli(argv = []) {
  const args = parseM3IoControlE2eArgs(argv);
  const gates = requireM3IoControlE2eGates(args);
  const sourceReport = await buildM3IoControlSourceReport();
  const report = gates.mode === "dev-live"
    ? await runM3IoControlLiveReport(args, sourceReport)
    : sourceReport;

  if (args.reportPath) {
    await writeReport(args.reportPath, report);
  }

  process.stdout.write(`${JSON.stringify(report, null, args.pretty ? 2 : 0)}\n`);
  return report.summary.status === "pass" ? 0 : 1;
}

export function formatM3IoControlE2eFailure(error) {
  return {
    tool: "m3-io-control-e2e",
    contractVersion: M3_IO_E2E_CONTRACT_VERSION,
    status: "error",
    sourceKind: labels.blocked,
    error: {
      message: error instanceof Error ? error.message : String(error)
    }
  };
}

async function postM3IoLiveStep(endpoint, step, timeoutMs) {
  const traceId = `trc_m3_io_e2e_${step.id.replaceAll("-", "_")}_${randomUUID()}`;
  const requestId = `req_m3_io_e2e_${step.id.replaceAll("-", "_")}_${randomUUID()}`;
  const body = {
    ...step.request,
    projectId: M3_IO_CHAIN.projectId,
    traceId,
    requestId,
    actorId: "usr_hwlab_m3_io_e2e"
  };
  const response = await requestJson(endpoint, {
    method: "POST",
    body,
    timeoutMs,
    headers: {
      "x-trace-id": traceId,
      "x-request-id": requestId,
      "x-actor-id": "usr_hwlab_m3_io_e2e"
    }
  });

  if (!response.ok) {
    return {
      id: step.id,
      action: step.action,
      status: response.status === 0 ? "unreachable" : "http_error",
      sourceKind: labels.devLive,
      endpoint,
      httpStatus: response.status,
      error: response.error,
      request: redactLiveRequest(body)
    };
  }

  const schema = validateM3IoLiveResponse(response.body, step);
  return {
    id: step.id,
    action: step.action,
    status: response.body?.status === "succeeded" && schema.status === "pass" ? "succeeded" : "blocked",
    sourceKind: labels.devLive,
    endpoint,
    httpStatus: response.status,
    request: redactLiveRequest(body),
    schema,
    operationId: response.body?.operationId ?? null,
    traceId: response.body?.traceId ?? traceId,
    auditId: response.body?.auditId ?? null,
    evidenceId: response.body?.evidenceId ?? null,
    evidenceState: response.body?.evidenceState ?? null,
    accepted: response.body?.accepted ?? null,
    resultValue: response.body?.result?.value,
    blocker: response.body?.blocker ?? null,
    controlPath: response.body?.controlPath ?? null
  };
}

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

function doWriteRequest(value) {
  return {
    action: "do.write",
    gatewayId: M3_IO_CHAIN.sourceGatewayId,
    resourceId: M3_IO_CHAIN.sourceResourceId,
    boxId: M3_IO_CHAIN.sourceBoxId,
    port: M3_IO_CHAIN.sourcePort,
    value
  };
}

function diReadRequest() {
  return {
    action: "di.read",
    gatewayId: M3_IO_CHAIN.targetGatewayId,
    resourceId: M3_IO_CHAIN.targetResourceId,
    boxId: M3_IO_CHAIN.targetBoxId,
    port: M3_IO_CHAIN.targetPort
  };
}

function routeChainMatches(chain) {
  return chain?.sourceGatewayId === M3_IO_CHAIN.sourceGatewayId &&
    chain?.sourceResourceId === M3_IO_CHAIN.sourceResourceId &&
    chain?.sourceBoxId === M3_IO_CHAIN.sourceBoxId &&
    chain?.sourcePort === M3_IO_CHAIN.sourcePort &&
    chain?.targetGatewayId === M3_IO_CHAIN.targetGatewayId &&
    chain?.targetResourceId === M3_IO_CHAIN.targetResourceId &&
    chain?.targetBoxId === M3_IO_CHAIN.targetBoxId &&
    chain?.targetPort === M3_IO_CHAIN.targetPort &&
    chain?.patchPanelServiceId === M3_IO_CHAIN.patchPanelServiceId;
}

function checkResult(id, ok, summary, details = {}) {
  return {
    id,
    status: ok ? "pass" : "fail",
    sourceKind: details.evidenceLevel ?? labels.source,
    summary,
    ...details
  };
}

function literalFetchTargets(source) {
  return [...source.matchAll(/\b(?:fetch|fetchJson)\(\s*(["'`])([^"'`]+)\1/gu)]
    .map((match) => match[2])
    .filter((target) => !target.includes("${"));
}

function functionBody(source, functionName) {
  const match = source.match(new RegExp(`function\\s+${escapeRegExp(functionName)}\\s*\\([^)]*\\)\\s*\\{`, "u"));
  if (!match) return "";
  let depth = 0;
  for (let index = match.index + match[0].length - 1; index < source.length; index += 1) {
    const char = source[index];
    if (char === "{") depth += 1;
    if (char === "}") {
      depth -= 1;
      if (depth === 0) return source.slice(match.index, index + 1);
    }
  }
  return "";
}

function resultTextForClassification(classification) {
  if (classification === "trusted_green") {
    return "DEV-LIVE M3 IO control path and durable trusted records are green.";
  }
  if (classification === controlPathReachablePersistenceBlocked) {
    return "DEV-LIVE control path was reachable, but runtime durable/trusted persistence was blocked; not trusted green.";
  }
  if (classification === "control_path_blocked") {
    return "DEV-LIVE M3 IO control path returned a blocked or schema-invalid operation.";
  }
  if (classification === "control_path_unreachable") {
    return "DEV-LIVE M3 IO control endpoint was unreachable or non-2xx.";
  }
  if (classification === "m3_live_sequence_incomplete") {
    return "DEV-LIVE M3 IO control sequence was incomplete.";
  }
  if (classification === "source_contract_failed") {
    return "SOURCE/static contract failed.";
  }
  return "SOURCE/static M3 IO control contract passed; DEV-LIVE was not run.";
}

function evidenceLabelDescriptions() {
  return [
    {
      label: labels.source,
      meaning: "Checked-in source or static contract; no runtime mutation."
    },
    {
      label: labels.local,
      meaning: "Local/in-process fixture evidence only; not a live DEV claim."
    },
    {
      label: labels.dryRun,
      meaning: "Planned sequence or schema validation; no live DEV POST."
    },
    {
      label: labels.devLive,
      meaning: "Explicitly gated DEV HTTP execution through cloud-web/cloud-api only."
    },
    {
      label: labels.blocked,
      meaning: "Cannot promote to trusted green."
    }
  ];
}

function redactLiveRequest(body) {
  return {
    action: body.action,
    gatewayId: body.gatewayId,
    resourceId: body.resourceId,
    boxId: body.boxId,
    port: body.port,
    value: Object.hasOwn(body, "value") ? body.value : undefined,
    projectId: body.projectId,
    traceId: body.traceId,
    requestId: body.requestId,
    actorId: body.actorId
  };
}

function stringValue(value) {
  return typeof value === "string" && value.trim().length > 0;
}

function parsePositiveInteger(value, fallback) {
  if (value === undefined) return fallback;
  const parsed = Number.parseInt(value, 10);
  if (!Number.isInteger(parsed) || parsed <= 0) {
    throw new Error("numeric value must be a positive integer");
  }
  return parsed;
}

async function readRepoText(root, relativePath) {
  return readFile(path.join(root, relativePath), "utf8");
}

async function writeReport(reportPath, report) {
  const absolute = path.resolve(repoRoot, reportPath);
  if (!absolute.startsWith(`${repoRoot}${path.sep}`)) {
    throw new Error("report path must stay inside the repository");
  }
  await mkdir(path.dirname(absolute), { recursive: true });
  await writeFile(absolute, `${JSON.stringify(report, null, 2)}\n`);
}

function isoNow() {
  return new Date().toISOString();
}

function escapeRegExp(value) {
  return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
}
