import type {
  ArtifactEnvelope,
  ArtifactManifest,
  GraphSchema,
  RunReport,
  SerializedExecutionRecord,
} from "./contracts.js";
import {
  isArtifactEnvelope,
  isArtifactManifest,
  isGraphSchema,
  isRunReport,
  isSerializedExecutionRecord,
} from "./guards.js";

export function parseArtifactEnvelope<Payload = unknown>(
  json: string,
  expectedType?: string
): ArtifactEnvelope<Payload> {
  const value: unknown = JSON.parse(json);
  if (!isArtifactEnvelope(value)) {
    throw new Error("Invalid Synaptopus artifact envelope");
  }
  if (expectedType && value.artifact_type !== expectedType) {
    throw new Error(
      `Unexpected artifact type: expected ${expectedType}, got ${value.artifact_type}`
    );
  }
  return value as ArtifactEnvelope<Payload>;
}

export function parseArtifactManifest(json: string): ArtifactManifest {
  const value: unknown = JSON.parse(json);
  if (!isArtifactManifest(value)) {
    throw new Error("Invalid Synaptopus artifact manifest");
  }
  return value;
}

export function parseGraphSchema(json: string): GraphSchema {
  const value = parseArtifactEnvelope<GraphSchema>(json, "graph_schema").payload;
  if (!isGraphSchema(value)) {
    throw new Error("Invalid Synaptopus graph schema");
  }
  return value;
}

export function parseExecutionTrace(json: string): SerializedExecutionRecord {
  const value = parseArtifactEnvelope<SerializedExecutionRecord>(
    json,
    "execution_trace"
  ).payload;
  if (!isSerializedExecutionRecord(value)) {
    throw new Error("Invalid Synaptopus execution trace");
  }
  return value;
}

export function parseRunReport(json: string): RunReport {
  const value = parseArtifactEnvelope<RunReport>(json, "run_report").payload;
  if (!isRunReport(value)) {
    throw new Error("Invalid Synaptopus run report");
  }
  return value;
}
