// SPEC: PJ2026-010205 HWLAB接入 draft-2026-06-17-r0; PJ2026-0104010803 Workbench唯一投影 draft-2026-06-19-p1-agentrun-incremental-cursor.
// Responsibility: AgentRun backend profile, internal repo source authority, provider identity, and trace metadata.

import { truthyFlag } from "./server-http-utils.ts";

export const DEFAULT_AGENTRUN_REPO_URL = "http://git-mirror-http.devops-infra.svc.cluster.local/pikasTech/HWLAB.git";
export const GITEA_AGENTRUN_REPO_URL = "http://gitea-http.devops-infra.svc.cluster.local:3000/mirrors/pikasTech-HWLAB.git";

const ADAPTER_ID = "agentrun-v01";
const AGENTRUN_BACKEND_PREFIX = ADAPTER_ID;
const AGENTRUN_RUNNER_KIND = "agentrun-v01-shared-runner";
const AGENTRUN_SESSION_MODE = "agentrun-v01-durable-session";
const AGENTRUN_IMPLEMENTATION_TYPE = "agentrun-v01-shared-execution-infra";
const AGENTRUN_PROVIDER_TRACE_PROTOCOL = "agentrun-v01-jsonrpc";
const AGENTRUN_BACKEND_ALIASES = Object.freeze({ "codex-api": "codex", codex: "codex", "gpt.pika": "gpt-pika" });
const AGENTRUN_BACKEND_PROFILE_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,63}$/u;

export function resolveAgentRunBackendProfile(env = process.env, params = {}) {
  const requested = String(params.providerProfile ?? params.codeAgentProviderProfile ?? env.HWLAB_CODE_AGENT_AGENTRUN_BACKEND_PROFILE ?? env.HWLAB_CODE_AGENT_DEFAULT_PROVIDER_PROFILE ?? "deepseek").trim().toLowerCase();
  const fallback = String(env.HWLAB_CODE_AGENT_AGENTRUN_DEFAULT_BACKEND_PROFILE ?? "deepseek").trim().toLowerCase() || "deepseek";
  const resolved = requested === "runtime-default" ? fallback : requested;
  if (!resolved || resolved === "runtime-default") return "deepseek";
  const mapped = AGENTRUN_BACKEND_ALIASES[resolved] ?? resolved;
  return AGENTRUN_BACKEND_PROFILE_ID_PATTERN.test(mapped) ? mapped : "deepseek";
}

export function agentRunTraceMeta(env = process.env) {
  return {
    runnerKind: AGENTRUN_RUNNER_KIND,
    workspace: resolveAgentRunRepoUrl(env),
    sandbox: firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_SANDBOX, env.HWLAB_CODE_AGENT_CODEX_SANDBOX, "danger-full-access"),
    protocol: AGENTRUN_PROVIDER_TRACE_PROTOCOL,
    sessionMode: AGENTRUN_SESSION_MODE,
    implementationType: AGENTRUN_IMPLEMENTATION_TYPE
  };
}

export function backendForBackendProfile(profile) {
  return `${AGENTRUN_BACKEND_PREFIX}/${resolveAgentRunBackendProfile({}, { providerProfile: profile })}`;
}

export function resolveAgentRunRepoUrl(env = process.env) {
  const raw = firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_REPO_URL, env.HWLAB_BOOT_READ_URL, DEFAULT_AGENTRUN_REPO_URL);
  const url = new URL(raw);
  const host = url.hostname.toLowerCase();
  const allowedByTest = truthyFlag(env.HWLAB_CODE_AGENT_AGENTRUN_ALLOW_NON_K3S_URL) && ["127.0.0.1", "localhost"].includes(host);
  url.pathname = url.pathname.replace(/\/+$/u, "");
  url.search = "";
  url.hash = "";
  const normalized = url.toString().replace(/\/+$/u, "");
  if (url.protocol !== "http:" || (!isAllowedAgentRunRepoUrl(normalized) && !allowedByTest)) {
    throw Object.assign(new Error(`HWLAB_CODE_AGENT_AGENTRUN_REPO_URL must use an approved internal k3s git mirror (${DEFAULT_AGENTRUN_REPO_URL} or ${GITEA_AGENTRUN_REPO_URL}); got ${redactUrl(raw)}`), {
      code: "agentrun_internal_repo_url_required",
      statusCode: 500
    });
  }
  return normalized;
}

function isAllowedAgentRunRepoUrl(repoUrl) {
  return repoUrl === DEFAULT_AGENTRUN_REPO_URL || repoUrl === GITEA_AGENTRUN_REPO_URL;
}

export function requireAgentRunSourceCommit(env) {
  const text = String(env.HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT ?? "").trim().toLowerCase();
  if (/^[0-9a-f]{40}$/u.test(text)) return text;
  throw Object.assign(new Error("HWLAB_CODE_AGENT_AGENTRUN_SOURCE_COMMIT must be a full 40-character source commit before AgentRun dispatch"), {
    code: "agentrun_bundle_source_commit_invalid",
    statusCode: 500
  });
}

export function resolveAgentRunProviderId(env = process.env) {
  const providerId = firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID, env.AGENTRUN_PROVIDER_ID);
  if (!providerId) {
    throw Object.assign(new Error("HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID must be configured from the runtime lane node id before AgentRun dispatch"), {
      code: "agentrun_provider_id_required",
      statusCode: 500
    });
  }
  if (!/^[A-Za-z0-9._-]+$/u.test(providerId)) {
    throw Object.assign(new Error("HWLAB_CODE_AGENT_AGENTRUN_PROVIDER_ID must be a simple node id"), {
      code: "agentrun_provider_id_invalid",
      statusCode: 500
    });
  }
  return providerId;
}

export function agentRunProviderIdOrNull(env = process.env) {
  try {
    return resolveAgentRunProviderId(env);
  } catch {
    return null;
  }
}

export function modelForBackendProfile(profile, env = process.env) {
  const resolved = resolveAgentRunBackendProfile({}, { providerProfile: profile });
  if (resolved === "codex") return firstNonEmpty(env.HWLAB_CODE_AGENT_CODEX_API_MODEL, env.HWLAB_CODE_AGENT_MODEL, "gpt-5.5");
  if (resolved === "minimax-m3") return firstNonEmpty(env.HWLAB_CODE_AGENT_MINIMAX_M3_MODEL, "MiniMax-M3");
  if (resolved === "deepseek") return firstNonEmpty(env.HWLAB_CODE_AGENT_DEEPSEEK_MODEL, "deepseek-chat");
  if (resolved === "dsflash-go") return firstNonEmpty(env.HWLAB_CODE_AGENT_AGENTRUN_DSFLASH_GO_MODEL, env.HWLAB_CODE_AGENT_DSFLASH_GO_MODEL, "deepseek-v4-flash");
  const profileEnvKey = dynamicBackendProfileEnvKey(resolved);
  return firstNonEmpty(env[`HWLAB_CODE_AGENT_AGENTRUN_${profileEnvKey}_MODEL`], env[`HWLAB_CODE_AGENT_${profileEnvKey}_MODEL`], resolved);
}

export function providerForBackendProfile(profile) {
  const resolved = resolveAgentRunBackendProfile({}, { providerProfile: profile });
  if (resolved === "codex") return "codex-api";
  if (resolved === "gpt-pika") return "gpt.pika";
  return resolved;
}

export function agentRunAvailabilityBlocker(error, scope) {
  return {
    code: error?.code ?? `agentrun_${String(scope).replace(/[^a-z0-9]+/giu, "_")}_blocked`,
    type: "agent_blocker",
    scope: `agentrun-${scope}`,
    status: "open",
    sourceIssue: "pikasTech/HWLAB#879",
    summary: error?.message ?? `AgentRun ${scope} is not configured correctly.` ,
    secretMaterialRead: false,
    valuesRedacted: true
  };
}

function dynamicBackendProfileEnvKey(profile) {
  return String(profile ?? "")
    .trim()
    .toUpperCase()
    .replace(/[^A-Z0-9]+/gu, "_")
    .replace(/^_+|_+$/gu, "") || "PROFILE";
}

function firstNonEmpty(...values) {
  for (const value of values) {
    const text = String(value ?? "").trim();
    if (text) return text;
  }
  return null;
}

function redactUrl(value) {
  try {
    const url = new URL(value);
    if (url.username || url.password) {
      url.username = "***";
      url.password = "";
    }
    return url.toString();
  } catch {
    return "<invalid-url>";
  }
}
