import type { ProviderTurnActionPolicy } from "@best-agent/protocol";
import type { ProviderGenerateCheckpointRequest } from "../checkpoint-codec.js";
import { promptDeliverableMissingObservation } from "./deliverable-observation.js";
import {
  collectReplayArtifactObligationFailures,
  compileReplayArtifactObligations,
} from "./provider-replay-deliverable-repair.js";
import { isRoutingDowngradeEligible } from "./provider-replay-context.js";
import { runReplayRepairDecision } from "./provider-replay-decision-runner.js";
import { requireReplayRepairProfile } from "./provider-replay-profile.js";
import { replayTurnContext } from "./provider-replay-repair-decision-runner.js";
import type { ReplayTerminalRepairState } from "./provider-replay-terminal-repair-state.js";
import { appendRuntimeObservation } from "./runtime-observation.js";
import { resolveProviderVisibleTools } from "./tool-constraint.js";

export async function repairReplayGenerateDeliverables(input: {
  responseText: string;
  state: ReplayTerminalRepairState;
}): Promise<string | undefined> {
  const { payload, replayContextAvailableTools, replayProviderTurnBudget, replayRouteConfig } =
    input.state;
  const { runtime, turn } = input.state;
  if (payload.requestKind !== "generate" || !payload.request) {
    return undefined;
  }
  const request = payload.request as ProviderGenerateCheckpointRequest;
  const availableTools = replayContextAvailableTools ?? [];
  const artifactObligations = compileReplayArtifactObligations({
    availableTools,
    cwd: runtime.cwd,
    messages: request.messages,
    objective: payload.replayContext?.objective,
    payloadArtifactObligations: payload.artifactObligations,
  });
  if (artifactObligations.length === 0) {
    return input.responseText;
  }
  const deliverableFailures = await collectReplayArtifactObligationFailures({
    artifactObligations,
    cwd: runtime.cwd,
    runtime,
    turn,
  });
  if (deliverableFailures.length === 0) {
    return input.responseText;
  }
  const { profile, profileName } = requireReplayRepairProfile({
    missingProfileMessage:
      "Provider request checkpoint is missing the profile needed to repair replayed generate deliverables.",
    profileName: payload.replayContext?.profileName,
    runtime,
  });
  const repairObservation = promptDeliverableMissingObservation(deliverableFailures);
  const repairMessages = appendRuntimeObservation(request.messages, repairObservation);
  const repairSystemPrompt = request.systemPrompt;
  const visibleTools = resolveProviderVisibleTools(availableTools, undefined, repairMessages);
  const repairActionPolicy: ProviderTurnActionPolicy = {
    allowedActions: ["tool"],
    directResponseAllowed: false,
  };
  const repairedText = await runReplayRepairDecision({
    actionPolicy: repairActionPolicy,
    allowPhaseResult: false,
    allowPlanUpdate: false,
    artifactObligations,
    assertArtifacts: true,
    assertTerminal: false,
    availableTools,
    baseMessages: request.messages,
    cacheControl: request.cacheControl,
    controls: {
      allowPhaseResult: false,
      allowPlanUpdate: false,
    },
    correctionOperation: payload.operation,
    providerContext: replayTurnContext({
      artifactObligations,
      availableTools,
      payload,
      profile,
      profileName,
      replayProviderTurnBudget,
      replayRouteConfig,
      requiredToolConstraint: undefined,
    }),
    repairCode: "PROMPT_DELIVERABLE_MISSING",
    repairObservation,
    requiredToolConstraint: undefined,
    resolveContext: replayTurnContext({
      artifactObligations,
      availableTools,
      downgradeEligible: isRoutingDowngradeEligible(payload.replayContext?.phaseName),
      payload,
      profile,
      profileName,
      replayProviderTurnBudget,
      replayRouteConfig,
      requiredToolConstraint: undefined,
    }),
    runtime,
    objective: payload.replayContext?.objective,
    systemPrompt: repairSystemPrompt,
    toolsForTrace: availableTools,
    toolStepCount: payload.replayContext?.toolStepCount ?? 0,
    traceSystemPrompt: request.systemPrompt,
    turn,
    visibleTools,
  });
  return runtime.assertValidTerminalAssistantText(repairedText);
}
