import type {
  ArtifactEnvelope,
  ArtifactManifest,
  GraphEdgeSpec,
  GraphNodeSpec,
  GraphSchema,
  RunReport,
  SerializedExecutionRecord,
} from "./contracts.js";

function isObject(value: unknown): value is Record<string, unknown> {
  return typeof value === "object" && value !== null;
}

function isStringArray(value: unknown): value is string[] {
  return Array.isArray(value) && value.every((item) => typeof item === "string");
}

export function isGraphNodeSpec(value: unknown): value is GraphNodeSpec {
  return (
    isObject(value) &&
    typeof value.node_id === "string" &&
    typeof value.node_type === "string" &&
    isStringArray(value.input_names) &&
    isStringArray(value.output_names)
  );
}

export function isGraphEdgeSpec(value: unknown): value is GraphEdgeSpec {
  return (
    isObject(value) &&
    typeof value.source_node_id === "string" &&
    typeof value.source_output === "string" &&
    typeof value.target_node_id === "string" &&
    typeof value.target_input === "string"
  );
}

export function isGraphSchema(value: unknown): value is GraphSchema {
  return (
    isObject(value) &&
    Array.isArray(value.nodes) &&
    value.nodes.every(isGraphNodeSpec) &&
    Array.isArray(value.edges) &&
    value.edges.every(isGraphEdgeSpec)
  );
}

export function isArtifactEnvelope(value: unknown): value is ArtifactEnvelope {
  return (
    isObject(value) &&
    typeof value.artifact_type === "string" &&
    typeof value.schema_version === "string" &&
    "payload" in value &&
    isObject(value.metadata)
  );
}

export function isArtifactManifest(value: unknown): value is ArtifactManifest {
  return (
    isObject(value) &&
    typeof value.schema_version === "string" &&
    Array.isArray(value.artifacts) &&
    value.artifacts.every(
      (item) =>
        isObject(item) &&
        typeof item.artifact_type === "string" &&
        typeof item.file_name === "string"
    ) &&
    isObject(value.metadata)
  );
}

export function isSerializedExecutionRecord(
  value: unknown
): value is SerializedExecutionRecord {
  return (
    isObject(value) &&
    Array.isArray(value.accepted) &&
    Array.isArray(value.attempts) &&
    "final_state" in value &&
    typeof value.total_seconds === "number"
  );
}

export function isRunReport(value: unknown): value is RunReport {
  return (
    isObject(value) &&
    isObject(value.parameters) &&
    typeof value.accepted_count === "number" &&
    typeof value.attempt_count === "number" &&
    typeof value.total_seconds === "number" &&
    isObject(value.sequence_analysis) &&
    typeof value.average_attempts_per_accept === "number"
  );
}
