export type ProtocolEvent = {
  seq?: number;
  type: string;
  payload?: unknown;
};

export type StreamDecodeChunking = {
  chunkingId: string;
  chunks: string[];
  observation: {
    events: ProtocolEvent[];
    terminalCount: number;
    parseErrors: string[];
  };
};

export type StreamDecodeConstraints = {
  preserveOrder?: boolean;
  requireSingleTerminal?: boolean;
  chunkBoundaryIndependent?: boolean;
  requireParseable?: boolean;
};

export type StdoutPurityObservation = {
  protocolFrames: string[];
  contaminations: Array<{ offset: number; text: string }>;
  partialFrames: number;
  terminalCount: number;
  duplicateTerminalCount: number;
  postTerminalEvents: number;
};

export type CompatibilityContract = {
  allowUnknownFields?: boolean;
  rejectVersionSkew?: boolean;
  expectedVersion?: number;
  charset?: "utf-8" | "utf-16";
  newline?: "lf" | "crlf";
  bom?: "reject" | "strip" | "preserve" | "forbid";
  compression?: "none" | "gzip";
  rejectPartialWrites?: boolean;
};

export type SerializationMetadata = {
  contentType?: string;
  hasBom?: boolean;
  newlineStyle?: "lf" | "crlf" | "mixed";
  compressed?: boolean;
  partialWrite?: boolean;
  unknownFields?: string[];
  inputVersion?: number;
  outputVersion?: number;
};

export type ProtocolScenario =
  | {
      scenarioId: string;
      kind: "stream-decode";
      frames: string[];
      terminalType: string;
      constraints: StreamDecodeConstraints;
      chunkings: StreamDecodeChunking[];
    }
  | {
      scenarioId: string;
      kind: "stdout-purity";
      stdout: string;
      stderr?: string;
      declaredSideChannels?: string[];
      terminalType?: string;
      observation: StdoutPurityObservation;
    }
  | {
      scenarioId: string;
      kind: "serialization-round-trip";
      typedValue: unknown;
      compatibilityContract: CompatibilityContract;
      observation: {
        serialized: string;
        deserialized: unknown;
        metadata: SerializationMetadata;
      };
    };

export type ProtocolFixture = {
  fixtureId: string;
  protocolVersion: string;
  scenarios: ProtocolScenario[];
  intentionalException?: {
    rules: string[];
    reason: string;
  };
};
