import { createHash } from "node:crypto";

export const CI_PLAN_IDENTITY_VERSION = "v1";

export function attachCiPlanIdentity(plan, context = {}) {
  const canonical = canonicalCiPlanIdentity(plan, context);
  const digest = createHash("sha256").update(stableStringify(canonical)).digest("hex");
  return {
    ...plan,
    planIdentity: {
      version: CI_PLAN_IDENTITY_VERSION,
      value: `sha256:${digest}`,
      inputs: canonical.inputs,
      scope: canonical.scope
    }
  };
}

export function canonicalCiPlanIdentity(plan, context = {}) {
  const services = Array.isArray(plan?.services) ? plan.services : [];
  return {
    version: CI_PLAN_IDENTITY_VERSION,
    inputs: {
      target: text(context.releaseTarget),
      consumer: text(context.releaseConsumer),
      lane: text(plan?.compatibility?.lane),
      sourceCommitId: text(plan?.sourceCommitId),
      baseCommitId: text(plan?.baseCommitId),
      catalog: {
        authority: text(plan?.artifactCatalog?.authority),
        sourceCommitId: text(plan?.artifactCatalog?.catalogSourceCommitId),
        digest: text(plan?.artifactCatalog?.catalogSha256),
        gitopsCommitId: text(plan?.artifactCatalog?.gitopsCommitId)
      },
      registryProbe: {
        enabled: plan?.inputs?.verifyReuseRegistry === true,
        services: services.map((service) => ({
          serviceId: text(service?.serviceId),
          status: text(service?.reuseRegistry?.status),
          image: text(service?.reuseRegistry?.image),
          digest: text(service?.reuseRegistry?.digest)
        })).filter((service) => service.serviceId).sort(compareServiceId)
      }
    },
    scope: {
      buildServices: sortedStrings(plan?.buildServices),
      rolloutServices: sortedStrings(plan?.rolloutServices),
      affectedServices: sortedStrings(plan?.affectedServices)
    }
  };
}

export function stableStringify(value) {
  if (Array.isArray(value)) return `[${value.map(stableStringify).join(",")}]`;
  if (value && typeof value === "object") {
    return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableStringify(value[key])}`).join(",")}}`;
  }
  return JSON.stringify(value);
}

function sortedStrings(value) {
  return [...new Set(Array.isArray(value) ? value.map(text).filter(Boolean) : [])].sort();
}

function compareServiceId(left, right) {
  return left.serviceId.localeCompare(right.serviceId);
}

function text(value) {
  return typeof value === "string" ? value.trim() : "";
}
