import type {
  Item,
  ItemId,
  StepId,
  ThreadEvidenceRecord,
  ThreadMetadata,
  ToolCallItem,
  ToolFailureKind,
  ToolInputValue,
  ToolResultEnvelope,
  ToolResultItem,
  ToolResultOutcome,
  Turn,
  TurnId,
} from "@best-agent/protocol";
import type { ToolResumeContext } from "../checkpoint-codec.js";

export type ToolItemPersistenceService = {
  pushItems(items: Item[]): Promise<void>;
};

export type ToolCallItemPersistence = {
  createToolCallItem(
    turn: Turn,
    toolName: string,
    input: string,
    callId?: ItemId,
    normalizedInput?: ToolInputValue,
    providerToolName?: string,
  ): ToolCallItem;
};

export type ToolResultItemPersistence = {
  buildToolResultEnvelope(
    turn: Turn,
    toolName: string,
    input: ToolInputValue,
    output: string,
    toolResultItem: ToolResultItem,
    envelopeOverride?: Partial<ToolResultEnvelope>,
  ): ToolResultEnvelope;
  createToolResultItemWithTrace(
    turn: Turn,
    toolName: string,
    output: string,
    callId: ItemId,
    structuredContent?: ThreadMetadata,
    metadata?: {
      errorCode?: string;
      failureKind?: ToolFailureKind;
      outcome?: ToolResultOutcome;
    },
    traceMetadata?: {
      forceTracePersistence?: boolean;
      outputManaged?: boolean;
      traceOutput?: string;
    },
  ): Promise<ToolResultItem>;
};

export type ToolCheckpointPersistenceService = {
  saveToolDispatchCheckpoint(
    turnId: TurnId,
    context: ToolResumeContext,
  ): Promise<StepId | undefined>;
  saveToolOutputCheckpoint(
    turn: Turn,
    context: ToolResumeContext,
    toolOutput: string,
    toolResultItem?: ToolResultItem,
    toolEnvelope?: ToolResultEnvelope,
    evidenceRecords?: ThreadEvidenceRecord[],
  ): Promise<void>;
};

export type ToolFailurePersistenceService = {
  appendToolFailureResultIfMissing(
    turn: Turn,
    input: {
      envelopeOverride?: Partial<ToolResultEnvelope>;
      errorCode?: string;
      failureKind: ToolFailureKind;
      forceTracePersistence?: boolean;
      outputManaged?: boolean;
      output: string;
      resumeContext?: ToolResumeContext;
      structuredContent?: ThreadMetadata;
      traceOutput?: string;
      toolCallId: ItemId;
      toolInput: ToolInputValue;
      toolName: string;
    },
  ): Promise<void>;
  toolCallHasTerminalResult(turn: Turn, toolCallId: ItemId): Promise<boolean>;
};
