const unknownValue = "unknown";

export function normalizeIsoTimestamp(value) {
  const source = String(value ?? "").trim();
  if (!source) return null;
  if (/^\d+$/u.test(source)) {
    const seconds = Number.parseInt(source, 10);
    if (Number.isSafeInteger(seconds)) {
      const date = new Date(seconds * 1000);
      if (Number.isFinite(date.getTime())) return date.toISOString();
    }
  }
  const date = new Date(source);
  return Number.isFinite(date.getTime()) ? date.toISOString() : null;
}

export function imageTagFromReference(imageReference) {
  const source = String(imageReference ?? "").trim();
  const slashIndex = source.lastIndexOf("/");
  const colonIndex = source.lastIndexOf(":");
  if (colonIndex <= slashIndex) return null;
  return source.slice(colonIndex + 1) || null;
}

export function shortRevision(value) {
  const source = String(value ?? "").trim();
  return source.length >= 7 ? source.slice(0, 7) : source || unknownValue;
}

export function buildMetadataFromEnv(env = process.env, { serviceId = "hwlab-unknown", fallbackImageRepository = null } = {}) {
  const commitId = firstNonEmpty(env.HWLAB_COMMIT_ID, env.HWLAB_GIT_SHA, env.GIT_COMMIT) ?? unknownValue;
  const revision = firstNonEmpty(env.HWLAB_REVISION, commitId) ?? unknownValue;
  const fallbackRepository = fallbackImageRepository ?? `ghcr.io/pikastech/${serviceId}`;
  const imageReference = firstNonEmpty(env.HWLAB_IMAGE, `${fallbackRepository}:${shortRevision(commitId)}`) ?? unknownValue;
  const imageTag = firstNonEmpty(env.HWLAB_IMAGE_TAG, imageTagFromReference(imageReference), shortRevision(commitId)) ?? unknownValue;
  const buildCreatedAt = normalizeIsoTimestamp(
    firstNonEmpty(env.HWLAB_BUILD_CREATED_AT, env.HWLAB_IMAGE_CREATED_AT, env.SOURCE_DATE_EPOCH, env.BUILD_DATE)
  );
  const buildSource = firstNonEmpty(env.HWLAB_BUILD_SOURCE, "runtime-env") ?? "runtime-env";

  return {
    revision,
    commit: {
      id: commitId,
      source: buildSource
    },
    image: {
      reference: imageReference,
      tag: imageTag,
      digest: firstNonEmpty(env.HWLAB_IMAGE_DIGEST, unknownValue) ?? unknownValue
    },
    build: {
      createdAt: buildCreatedAt,
      source: buildSource,
      provenance: firstNonEmpty(env.HWLAB_BUILD_PROVENANCE, null),
      metadataSource: buildCreatedAt ? "runtime-env:HWLAB_BUILD_CREATED_AT" : "unavailable",
      unavailableReason: buildCreatedAt ? null : "HWLAB_BUILD_CREATED_AT missing from runtime environment"
    },
    runtime: runtimeIdentityFromEnv(env)
  };
}

export function runtimeIdentityFromEnv(env = process.env) {
  const runtimeMode = firstNonEmpty(env.HWLAB_RUNTIME_MODE, null);
  const bootRepo = firstNonEmpty(env.HWLAB_BOOT_REPO, null);
  const bootCommit = firstNonEmpty(env.HWLAB_BOOT_COMMIT, null);
  const bootSh = firstNonEmpty(env.HWLAB_BOOT_SH, null);
  const environmentImage = firstNonEmpty(env.HWLAB_ENVIRONMENT_IMAGE, null);
  const environmentDigest = firstNonEmpty(env.HWLAB_ENVIRONMENT_DIGEST, env.HWLAB_IMAGE_DIGEST, null);
  const environmentInputHash = firstNonEmpty(env.HWLAB_ENVIRONMENT_INPUT_HASH, null);
  const codeInputHash = firstNonEmpty(env.HWLAB_CODE_INPUT_HASH, null);
  const pod = runtimePodIdentityFromEnv(env);
  if (!runtimeMode && !bootRepo && !bootCommit && !bootSh && !environmentDigest && !pod) return null;
  return pruneUndefined({
    mode: runtimeMode,
    environmentImage,
    environmentDigest,
    environmentInputHash,
    codeInputHash,
    pod,
    boot: pruneUndefined({
      repo: bootRepo,
      commit: bootCommit,
      sh: bootSh
    })
  });
}

function runtimePodIdentityFromEnv(env = process.env) {
  const name = firstNonEmpty(env.HWLAB_RUNTIME_POD_NAME, env.POD_NAME, env.HOSTNAME, null);
  const namespace = firstNonEmpty(env.HWLAB_RUNTIME_NAMESPACE, env.POD_NAMESPACE, env.KUBERNETES_NAMESPACE, env.HWLAB_NAMESPACE, null);
  const container = firstNonEmpty(env.HWLAB_RUNTIME_CONTAINER, env.HWLAB_CONTAINER_NAME, null);
  const nodeName = firstNonEmpty(env.HWLAB_RUNTIME_NODE_NAME, env.NODE_NAME, null);
  if (!name && !namespace && !container && !nodeName) return null;
  return pruneUndefined({ name, namespace, container, nodeName });
}

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

function pruneUndefined(value) {
  return Object.fromEntries(Object.entries(value).filter(([, item]) => item !== undefined && item !== null && item !== ""));
}
