import { sha256Canonical } from "../../../schema/src/canonical.js";
import { normalizeSemVer } from "../../../schema/src/decisions/scope.js";
import type { ActionRef, ExecutionContext } from "../../../schema/src/records/context.js";

export type DetectorRef = {
  id: string;
  version: string;
};

export type FindingTarget = {
  kind: string;
  canonical: string;
};

export type FindingIdParts = {
  detector: DetectorRef;
  target: FindingTarget;
  context: ExecutionContext;
  action?: ActionRef;
};

type FindingIdentityPayload = {
  detector: {
    id: string;
    version: string;
  };
  target: FindingTarget;
  context: BrowserFindingContextIdentity | NonBrowserFindingContextIdentity;
  action?: {
    id: string;
  };
};

type BrowserFindingContextIdentity = {
  kind: "browser";
  cellId: string;
};

type NonBrowserFindingContextIdentity = {
  kind: Exclude<ExecutionContext["kind"], "browser">;
  surfaceId: string;
  adapterId: string;
  seed: string;
};

function resolveAction(
  parts: FindingIdParts,
): ActionRef | undefined {
  if (parts.action !== undefined) {
    return parts.action;
  }
  if (parts.context.kind !== "browser" && parts.context.action !== undefined) {
    return parts.context.action;
  }
  return undefined;
}

function buildContextIdentity(context: ExecutionContext): FindingIdentityPayload["context"] {
  if (context.kind === "browser") {
    return {
      kind: "browser",
      cellId: context.cell.id,
    };
  }

  return {
    kind: context.kind,
    surfaceId: context.surfaceId,
    adapterId: context.adapterId,
    seed: context.seed,
  };
}

function buildFindingIdentityPayload(parts: FindingIdParts): FindingIdentityPayload {
  const action = resolveAction(parts);
  const payload: FindingIdentityPayload = {
    detector: {
      id: parts.detector.id,
      version: normalizeSemVer(parts.detector.version),
    },
    target: {
      kind: parts.target.kind,
      canonical: parts.target.canonical,
    },
    context: buildContextIdentity(parts.context),
  };

  if (action !== undefined) {
    payload.action = { id: action.id };
  }

  return payload;
}

export function findingId(parts: FindingIdParts): string {
  return sha256Canonical(buildFindingIdentityPayload(parts));
}
