package agent

import (
	"context"
	"encoding/json"
	"fmt"
	"testing"

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/desktop/internal/agent/drivercontract"
	"github.com/tidbcloud/AgentTeam/desktop/internal/types"
)

func TestCodexAckedDeliverySupportIsStructural(t *testing.T) {
	driver := &CodexAppServerDriver{}
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{
		Type:        "active",
		ActiveFlags: []string{"waitingOnApproval"},
	}
	driver.activeTurnID = "turn-1"
	driver.compactionInProgress = true

	require.True(t, driver.SupportsAckedBusyRuntimeInputDelivery())
}

func TestCodexAckedDeliveryRefreshesActiveWithoutTurnThenSteersBody(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		switch req.Method {
		case "thread/read":
			require.Equal(t, "thread-1", req.Params["threadId"])
			require.Equal(t, true, req.Params["includeTurns"])
			return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{
				Thread: appServerThread{
					ID:     "thread-1",
					Status: appServerThreadStatus{Type: "active"},
					Turns: []appServerTurn{{
						ID:     "turn-live",
						Status: appServerTurnStatus{Type: "inProgress"},
					}},
				},
			})}
		case "turn/steer":
			require.Equal(t, "turn-live", req.Params["expectedTurnId"])
			require.Equal(t, "msg-1", req.Params["clientUserMessageId"])
			require.Equal(t, "original body", ackedDeliveryInputText(t, req.Params))
			return appServerEnvelope{Result: rawRPCResult(t, appServerTurnIDResult{TurnID: "turn-live"})}
		default:
			t.Fatalf("unexpected request %s", req.Method)
			return appServerEnvelope{}
		}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "active"}

	err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-1"}, "original body"), "thread-1")

	require.NoError(t, err)
	require.Equal(t, []string{"thread/read", "turn/steer"}, capturedRPCMethods(writer.requests))
}

func TestCodexAckedDeliveryRefreshesUnsteerableCacheThenStartsBody(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		switch req.Method {
		case "thread/read":
			require.Equal(t, true, req.Params["includeTurns"])
			return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{
				Thread: appServerThread{
					ID:     "thread-1",
					Status: appServerThreadStatus{Type: "idle"},
				},
			})}
		case "turn/start":
			require.Equal(t, "thread-1", req.Params["threadId"])
			require.Equal(t, "msg-1", req.Params["clientUserMessageId"])
			require.Equal(t, "original body", ackedDeliveryInputText(t, req.Params))
			return appServerEnvelope{Result: rawRPCResult(t, appServerTurnResult{
				Turn: appServerTurn{ID: "turn-started", Status: appServerTurnStatus{Type: "inProgress"}},
			})}
		default:
			t.Fatalf("unexpected request %s", req.Method)
			return appServerEnvelope{}
		}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "active"}
	driver.activeTurnID = ""

	err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-1"}, "original body"), "thread-1")

	require.NoError(t, err)
	require.Equal(t, []string{"thread/read", "turn/start"}, capturedRPCMethods(writer.requests))
	require.Equal(t, "turn-started", driver.currentActiveTurnID())
}

func TestCodexAckedDeliveryCachedIdleReadsThenStarts(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		switch req.Method {
		case "thread/read":
			return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{
				Thread: appServerThread{ID: "thread-1", Status: appServerThreadStatus{Type: "idle"}},
			})}
		case "turn/start":
			require.Equal(t, "msg-idle", req.Params["clientUserMessageId"])
			return appServerEnvelope{Result: rawRPCResult(t, appServerTurnResult{
				Turn: appServerTurn{ID: "turn-idle", Status: appServerTurnStatus{Type: "inProgress"}},
			})}
		default:
			t.Fatalf("unexpected request %s", req.Method)
			return appServerEnvelope{}
		}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "idle"}

	err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-idle"}, "idle body"), "thread-1")

	require.NoError(t, err)
	require.Equal(t, []string{"thread/read", "turn/start"}, capturedRPCMethods(writer.requests))
}

func TestCodexDirectDeliveryFreshUnmaterializedThreadFallsBackThenStarts(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		switch req.Method {
		case "thread/read":
			includeTurns, _ := req.Params["includeTurns"].(bool)
			if includeTurns {
				return appServerEnvelope{Error: &appServerResponseError{
					Code:    -32600,
					Message: "thread thread-fresh is not materialized yet; includeTurns is unavailable before first user message",
				}}
			}
			return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{Thread: appServerThread{
				ID:     "thread-fresh",
				Status: appServerThreadStatus{Type: "idle"},
			}})}
		case "turn/start":
			require.Equal(t, "thread-fresh", req.Params["threadId"])
			require.Equal(t, "msg-first", req.Params["clientUserMessageId"])
			require.Equal(t, "first body", ackedDeliveryInputText(t, req.Params))
			return appServerEnvelope{Result: rawRPCResult(t, appServerTurnResult{Turn: appServerTurn{
				ID: "turn-first", Status: appServerTurnStatus{Type: "inProgress"},
			}})}
		default:
			t.Fatalf("unexpected request %s", req.Method)
			return appServerEnvelope{}
		}
	})
	driver.threadID = "thread-fresh"
	driver.threadStatus = appServerThreadStatus{Type: "idle"}

	err := driver.DeliverRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-first"}, "first body"), "thread-fresh")

	require.NoError(t, err)
	require.Equal(t, []string{"thread/read", "thread/read", "turn/start"}, capturedRPCMethods(writer.requests))
	require.Equal(t, "turn-first", driver.currentActiveTurnID())
}

func TestCodexBusyDeliveryUnmaterializedActiveWithoutTurnStopsAtBoundary(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		require.Equal(t, "thread/read", req.Method)
		if req.Params["includeTurns"] == true {
			return appServerEnvelope{Error: &appServerResponseError{
				Code:    -32600,
				Message: "thread thread-fresh is not materialized yet; includeTurns is unavailable before first user message",
			}}
		}
		return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{Thread: appServerThread{
			ID: "thread-fresh", Status: appServerThreadStatus{Type: "active"},
		}})}
	})
	driver.threadID = "thread-fresh"
	driver.threadStatus = appServerThreadStatus{Type: "active"}

	err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-busy"}, "must not speculate"), "thread-fresh")

	require.ErrorIs(t, err, errCodexTurnDispatchBoundary)
	require.Equal(t, []string{"thread/read", "thread/read"}, capturedRPCMethods(writer.requests))
}

func TestCodexMetadataFallbackCannotEraseConcurrentActiveTurn(t *testing.T) {
	var driver *CodexAppServerDriver
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		switch req.Method {
		case "thread/read":
			if req.Params["includeTurns"] == true {
				return appServerEnvelope{Error: &appServerResponseError{
					Code:    -32600,
					Message: "thread thread-1 is not materialized yet; includeTurns is unavailable before first user message",
				}}
			}
			// Simulate turn/started winning after the metadata request was sent but
			// before its older idle response was applied.
			driver.reconcileAckedActiveTurn("thread-1", "turn-live")
			return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{Thread: appServerThread{
				ID: "thread-1", Status: appServerThreadStatus{Type: "idle"},
			}})}
		case "turn/steer":
			require.Equal(t, "turn-live", req.Params["expectedTurnId"])
			return appServerEnvelope{Result: rawRPCResult(t, appServerTurnIDResult{TurnID: "turn-live"})}
		default:
			t.Fatalf("unexpected request %s", req.Method)
			return appServerEnvelope{}
		}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "idle"}

	err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-race"}, "preserve active turn"), "thread-1")

	require.NoError(t, err)
	require.Equal(t, []string{"thread/read", "thread/read", "turn/steer"}, capturedRPCMethods(writer.requests))
}

func TestCodexMetadataFallbackCannotRebindReplacedPrimaryThread(t *testing.T) {
	var driver *CodexAppServerDriver
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		require.Equal(t, "thread/read", req.Method)
		if req.Params["includeTurns"] == true {
			return appServerEnvelope{Error: &appServerResponseError{
				Code:    -32600,
				Message: "thread thread-old is not materialized yet; includeTurns is unavailable before first user message",
			}}
		}
		// A replacement launch binds a different primary while the old metadata
		// request is in flight. Its response must not switch the driver back.
		driver.updateThreadSnapshot(appServerThread{ID: "thread-new", Status: appServerThreadStatus{Type: "idle"}})
		return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{Thread: appServerThread{
			ID: "thread-old", Status: appServerThreadStatus{Type: "idle"},
		}})}
	})
	driver.threadID = "thread-old"
	driver.threadStatus = appServerThreadStatus{Type: "idle"}

	err := driver.DeliverRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-old"}, "must fail closed"), "thread-old")

	require.Error(t, err)
	require.Contains(t, err.Error(), "state is unavailable after refresh")
	require.Equal(t, []string{"thread/read", "thread/read"}, capturedRPCMethods(writer.requests))
	driver.mu.Lock()
	require.Equal(t, "thread-new", driver.threadID)
	driver.mu.Unlock()
}

func TestCodexEphemeralMetadataFallbackRoutesIdleThreadWithoutHistory(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		switch req.Method {
		case "thread/read":
			if req.Params["includeTurns"] == true {
				return appServerEnvelope{Error: &appServerResponseError{
					Code:    -32600,
					Message: "ephemeral threads do not support includeTurns",
				}}
			}
			return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{Thread: appServerThread{
				ID: "thread-ephemeral", Status: appServerThreadStatus{Type: "idle"},
			}})}
		case "turn/start":
			require.Equal(t, "msg-ephemeral", req.Params["clientUserMessageId"])
			return appServerEnvelope{Result: rawRPCResult(t, appServerTurnResult{Turn: appServerTurn{ID: "turn-ephemeral"}})}
		default:
			t.Fatalf("unexpected request %s", req.Method)
			return appServerEnvelope{}
		}
	})
	driver.threadID = "thread-ephemeral"
	driver.threadStatus = appServerThreadStatus{Type: "idle"}

	err := driver.DeliverRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-ephemeral"}, "body"), "thread-ephemeral")

	require.NoError(t, err)
	require.Equal(t, []string{"thread/read", "thread/read", "turn/start"}, capturedRPCMethods(writer.requests))
}

func TestCodexIncludeTurnsFallbackFailsClosedOnThreadMismatch(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		require.Equal(t, "thread/read", req.Method)
		if req.Params["includeTurns"] == true {
			return appServerEnvelope{Error: &appServerResponseError{
				Code:    -32600,
				Message: "thread thread-1 is not materialized yet; includeTurns is unavailable before first user message",
			}}
		}
		return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{Thread: appServerThread{
			ID: "thread-other", Status: appServerThreadStatus{Type: "idle"},
		}})}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "idle"}

	err := driver.DeliverRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-1"}, "body"), "thread-1")

	require.Error(t, err)
	require.Contains(t, err.Error(), `returned thread "thread-other"`)
	require.Equal(t, []string{"thread/read", "thread/read"}, capturedRPCMethods(writer.requests))
}

func TestCodexIncludeTurnsFallbackRejectsUnrelatedReadError(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		require.Equal(t, "thread/read", req.Method)
		return appServerEnvelope{Error: &appServerResponseError{
			Code:    -32600,
			Message: "thread not loaded: thread-1",
		}}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "idle"}

	err := driver.DeliverRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-1"}, "body"), "thread-1")

	require.Error(t, err)
	require.Contains(t, err.Error(), "thread not loaded")
	require.Equal(t, []string{"thread/read"}, capturedRPCMethods(writer.requests))
}

func TestCodexDeliveryMarksInitialReadTransportFailureBeforeMutation(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		require.Equal(t, "thread/read", req.Method)
		return appServerEnvelope{Error: &appServerResponseError{
			Code:    codexAppServerTransportFailureCode,
			Message: "transport disconnected during delivery preflight",
		}}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "idle"}

	err := driver.DeliverRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-1"}, "body"), "thread-1")

	require.ErrorIs(t, err, errRuntimeInputMutationNotAttempted)
	require.ErrorIs(t, err, errCodexAppServerTransportAmbiguous,
		"the diagnostic transport cause must remain inspectable")
	require.False(t, isAmbiguousRuntimeDeliveryError(err),
		"read-only transport ambiguity must not become input-mutation uncertainty")
	require.Equal(t, deliveryRetryTransient, classifyDeliveryRetryError(err))
	require.Equal(t, []string{"thread/read"}, capturedRPCMethods(writer.requests))
}

func TestCodexDeliveryMarksFallbackReadTransportFailureBeforeMutation(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		require.Equal(t, "thread/read", req.Method)
		if req.Params["includeTurns"] == true {
			return appServerEnvelope{Error: &appServerResponseError{
				Code:    -32600,
				Message: "thread thread-fresh is not materialized yet; includeTurns is unavailable before first user message",
			}}
		}
		return appServerEnvelope{Error: &appServerResponseError{
			Code:    codexAppServerTransportFailureCode,
			Message: "transport disconnected during metadata fallback",
		}}
	})
	driver.threadID = "thread-fresh"
	driver.threadStatus = appServerThreadStatus{Type: "idle"}

	err := driver.DeliverRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-first"}, "first body"), "thread-fresh")

	require.ErrorIs(t, err, errRuntimeInputMutationNotAttempted)
	require.ErrorIs(t, err, errCodexAppServerTransportAmbiguous)
	require.False(t, isAmbiguousRuntimeDeliveryError(err))
	require.Equal(t, deliveryRetryTransient, classifyDeliveryRetryError(err))
	require.Equal(t, []string{"thread/read", "thread/read"}, capturedRPCMethods(writer.requests))
}

func TestCodexDeliveryKeepsTurnStartTransportFailureMutationAmbiguous(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		switch req.Method {
		case "thread/read":
			return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{Thread: appServerThread{
				ID: "thread-1", Status: appServerThreadStatus{Type: "idle"},
			}})}
		case "turn/start":
			return appServerEnvelope{Error: &appServerResponseError{
				Code:    codexAppServerTransportFailureCode,
				Message: "response lost after turn/start dispatch",
			}}
		default:
			t.Fatalf("unexpected request %s", req.Method)
			return appServerEnvelope{}
		}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "idle"}

	err := driver.DeliverRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-1"}, "body"), "thread-1")

	require.ErrorIs(t, err, errCodexAppServerTransportAmbiguous)
	require.NotErrorIs(t, err, errRuntimeInputMutationNotAttempted)
	require.True(t, isAmbiguousRuntimeDeliveryError(err),
		"a lost mutating response must remain correlated uncertainty")
	require.Equal(t, deliveryRetryTransient, classifyDeliveryRetryError(err))
	require.Equal(t, []string{"thread/read", "turn/start"}, capturedRPCMethods(writer.requests),
		"the driver must never retry a transport-ambiguous mutation")
}

func TestCodexAckedDeliverySystemErrorStartsRecoveryTurn(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		switch req.Method {
		case "thread/read":
			return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{
				Thread: appServerThread{ID: "thread-1", Status: appServerThreadStatus{Type: "systemError"}},
			})}
		case "turn/start":
			require.Equal(t, "msg-recover", req.Params["clientUserMessageId"])
			return appServerEnvelope{Result: rawRPCResult(t, appServerTurnResult{
				Turn: appServerTurn{ID: "turn-recover", Status: appServerTurnStatus{Type: "inProgress"}},
			})}
		default:
			t.Fatalf("unexpected request %s", req.Method)
			return appServerEnvelope{}
		}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "systemError"}

	err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-recover"}, "recover body"), "thread-1")

	require.NoError(t, err)
	require.Equal(t, []string{"thread/read", "turn/start"}, capturedRPCMethods(writer.requests))
}

func TestCodexAckedDeliveryNotLoadedResumesThenRoutes(t *testing.T) {
	readCalls := 0
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		switch req.Method {
		case "thread/read":
			readCalls++
			if readCalls == 1 {
				return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{
					Thread: appServerThread{ID: "thread-1", Status: appServerThreadStatus{Type: "notLoaded"}},
				})}
			}
			require.Equal(t, true, req.Params["includeTurns"])
			return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{
				Thread: appServerThread{ID: "thread-1", Status: appServerThreadStatus{Type: "idle"}},
			})}
		case "thread/resume":
			require.Equal(t, "thread-1", req.Params["threadId"])
			require.Equal(t, true, req.Params["excludeTurns"])
			return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{
				Thread: appServerThread{ID: "thread-1", Status: appServerThreadStatus{Type: "idle"}},
			})}
		case "turn/start":
			require.Equal(t, "msg-resume", req.Params["clientUserMessageId"])
			return appServerEnvelope{Result: rawRPCResult(t, appServerTurnResult{
				Turn: appServerTurn{ID: "turn-resumed", Status: appServerTurnStatus{Type: "inProgress"}},
			})}
		default:
			t.Fatalf("unexpected request %s", req.Method)
			return appServerEnvelope{}
		}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "notLoaded"}

	err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-resume"}, "resume body"), "thread-1")

	require.NoError(t, err)
	require.Equal(t, []string{"thread/read", "thread/resume", "thread/read", "turn/start"}, capturedRPCMethods(writer.requests))
}

func TestCodexAckedDeliveryActiveWithoutTurnStopsAtLifecycleBoundary(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		switch req.Method {
		case "thread/read":
			return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{
				Thread: appServerThread{ID: "thread-1", Status: appServerThreadStatus{Type: "active"}},
			})}
		default:
			t.Fatalf("unexpected request %s", req.Method)
			return appServerEnvelope{}
		}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "active"}

	err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-fallback"}, "fallback body"), "thread-1")

	require.ErrorIs(t, err, errCodexTurnDispatchBoundary)
	require.Equal(t, []string{"thread/read"}, capturedRPCMethods(writer.requests), "active-no-turn recovery must never speculate with turn/start")
}

func TestCodexLegacyBusyDeliveryActiveWithoutTurnDoesNotMutate(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		switch req.Method {
		case "thread/read":
			return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{
				Thread: appServerThread{ID: "thread-1", Status: appServerThreadStatus{Type: "active"}},
			})}
		default:
			t.Fatalf("unexpected request %s", req.Method)
			return appServerEnvelope{}
		}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "active"}

	err := driver.DeliverBusyStdinInput(context.Background(), testRuntimeInput("legacy body"), "thread-1")

	require.ErrorIs(t, err, errCodexTurnDispatchBoundary)
	require.Equal(t, []string{"thread/read"}, capturedRPCMethods(writer.requests))
}

func TestCodexAckedDeliveryMissingActiveSteerStartsSameBody(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		switch req.Method {
		case "turn/steer":
			require.Equal(t, "turn-stale", req.Params["expectedTurnId"])
			require.Equal(t, "msg-1", req.Params["clientUserMessageId"])
			require.Equal(t, "original body", ackedDeliveryInputText(t, req.Params))
			return appServerEnvelope{Error: &appServerResponseError{
				Code:    -32602,
				Message: "no active turn to steer",
			}}
		case "turn/start":
			require.Equal(t, "msg-1", req.Params["clientUserMessageId"])
			require.Equal(t, "original body", ackedDeliveryInputText(t, req.Params))
			return appServerEnvelope{Result: rawRPCResult(t, appServerTurnResult{
				Turn: appServerTurn{ID: "turn-started", Status: appServerTurnStatus{Type: "inProgress"}},
			})}
		default:
			t.Fatalf("unexpected request %s", req.Method)
			return appServerEnvelope{}
		}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "active"}
	driver.activeTurnID = "turn-stale"

	err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-1"}, "original body"), "thread-1")

	require.NoError(t, err)
	require.Equal(t, []string{"turn/steer", "turn/start"}, capturedRPCMethods(writer.requests))
	require.Equal(t, "turn-started", driver.currentActiveTurnID())
}

func TestCodexAckedDeliveryTurnMismatchRetriesActualTurnOnce(t *testing.T) {
	steerCalls := 0
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		require.Equal(t, "turn/steer", req.Method)
		steerCalls++
		require.Equal(t, "msg-1", req.Params["clientUserMessageId"])
		require.Equal(t, "original body", ackedDeliveryInputText(t, req.Params))
		if steerCalls == 1 {
			require.Equal(t, "turn-stale", req.Params["expectedTurnId"])
			return appServerEnvelope{Error: &appServerResponseError{
				Code:    -32602,
				Message: "expected active turn id `turn-stale` but found `turn-live`",
			}}
		}
		require.Equal(t, "turn-live", req.Params["expectedTurnId"])
		return appServerEnvelope{Result: rawRPCResult(t, appServerTurnIDResult{TurnID: "turn-live"})}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "active"}
	driver.activeTurnID = "turn-stale"

	err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-1"}, "original body"), "thread-1")

	require.NoError(t, err)
	require.Equal(t, []string{"turn/steer", "turn/steer"}, capturedRPCMethods(writer.requests))
	require.Equal(t, "turn-live", driver.currentActiveTurnID())
}

func TestCodexAckedDeliveryTurnMismatchDoesNotAgentTeam(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		expected := fmt.Sprint(req.Params["expectedTurnId"])
		actual := "turn-live"
		if expected == "turn-live" {
			actual = "turn-newer"
		}
		return appServerEnvelope{Error: &appServerResponseError{
			Code:    -32602,
			Message: fmt.Sprintf("expected active turn id `%s` but found `%s`", expected, actual),
		}}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "active"}
	driver.activeTurnID = "turn-stale"

	err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-1"}, "original body"), "thread-1")

	require.Error(t, err)
	require.Contains(t, err.Error(), "turn-newer")
	require.Len(t, writer.requests, 2)
	require.Equal(t, "turn-newer", driver.currentActiveTurnID())
}

func TestCodexAckedDeliveryMismatchThenMissingDoesNotStartThirdMutation(t *testing.T) {
	steerCalls := 0
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		require.Equal(t, "turn/steer", req.Method)
		steerCalls++
		if steerCalls == 1 {
			require.Equal(t, "turn-stale", req.Params["expectedTurnId"])
			return appServerEnvelope{Error: &appServerResponseError{
				Code:    -32602,
				Message: "expected active turn id `turn-stale` but found `turn-live`",
			}}
		}
		require.Equal(t, "turn-live", req.Params["expectedTurnId"])
		return appServerEnvelope{Error: &appServerResponseError{
			Code:    -32602,
			Message: "no active turn to steer",
		}}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "active"}
	driver.activeTurnID = "turn-stale"

	err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-1"}, "original body"), "thread-1")

	require.Error(t, err)
	require.Contains(t, err.Error(), "no active turn to steer")
	require.Equal(t, []string{"turn/steer", "turn/steer"}, capturedRPCMethods(writer.requests))
	require.Empty(t, driver.currentActiveTurnID())
	driver.mu.Lock()
	require.Equal(t, "idle", normalizeThreadStatus(driver.threadStatus).Type)
	driver.mu.Unlock()
}

func TestCodexLegacyBusyDeliveryDoesNotRetryAmbiguousMutation(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		require.Equal(t, "turn/steer", req.Method)
		return appServerEnvelope{Error: &appServerResponseError{
			Code:    codexAppServerTransportFailureCode,
			Message: "response lost after dispatch",
		}}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "active"}
	driver.activeTurnID = "turn-live"

	err := driver.DeliverBusyStdinInput(context.Background(), testRuntimeInput("legacy body"), "thread-1")

	require.ErrorIs(t, err, errCodexAppServerTransportAmbiguous)
	require.Equal(t, []string{"turn/steer"}, capturedRPCMethods(writer.requests))
}

func TestCodexAckedDeliveryRefreshesThenSteersWhileWaitingOnApproval(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		switch req.Method {
		case "thread/read":
			return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{
				Thread: appServerThread{
					ID: "thread-1",
					Status: appServerThreadStatus{
						Type:        "active",
						ActiveFlags: []string{"waitingOnApproval"},
					},
					Turns: []appServerTurn{{
						ID:     "turn-live",
						Status: appServerTurnStatus{Type: "inProgress"},
					}},
				},
			})}
		case "turn/steer":
			require.Equal(t, "turn-live", req.Params["expectedTurnId"])
			require.Equal(t, "msg-1", req.Params["clientUserMessageId"])
			require.Equal(t, "original body", ackedDeliveryInputText(t, req.Params))
			return appServerEnvelope{Result: rawRPCResult(t, appServerTurnIDResult{TurnID: "turn-live"})}
		default:
			t.Fatalf("unexpected request %s", req.Method)
			return appServerEnvelope{}
		}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "active"}
	driver.activeTurnID = ""

	err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-1"}, "original body"), "thread-1")

	require.NoError(t, err)
	require.Equal(t, []string{"thread/read", "turn/steer"}, capturedRPCMethods(writer.requests))
}

func TestCodexAckedDeliveryReturnsNonSteerableTurnError(t *testing.T) {
	for _, turnKind := range []string{"review", "compact"} {
		t.Run(turnKind, func(t *testing.T) {
			driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
				require.Equal(t, "turn/steer", req.Method)
				data, err := json.Marshal(map[string]any{
					"message": fmt.Sprintf("cannot steer a %s turn", turnKind),
					"codexErrorInfo": map[string]any{
						"activeTurnNotSteerable": map[string]any{"turnKind": turnKind},
					},
				})
				require.NoError(t, err)
				return appServerEnvelope{Error: &appServerResponseError{
					Code:    -32602,
					Message: fmt.Sprintf("cannot steer a %s turn", turnKind),
					Data:    data,
				}}
			})
			driver.threadID = "thread-1"
			driver.threadStatus = appServerThreadStatus{Type: "active"}
			driver.activeTurnID = "turn-1"

			err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-1"}, "original body"), "thread-1")

			require.Error(t, err)
			require.Contains(t, err.Error(), "cannot steer")
			require.Len(t, writer.requests, 1)
			driver.mu.Lock()
			require.Equal(t, turnKind, driver.activeTurnNonSteerableKind)
			driver.mu.Unlock()
		})
	}
}

func TestCodexAckedDeliveryDoesNotReadAwayKnownCompactionFence(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		t.Fatalf("known compaction must not issue %s", req.Method)
		return appServerEnvelope{}
	})
	driver.threadID = "thread-1"
	driver.threadStatus = appServerThreadStatus{Type: "active"}
	driver.compactionInProgress = true

	err := driver.DeliverAckedBusyRuntimeInput(context.Background(), testRuntimeInputWithConfig(drivercontract.RuntimeInput{ID: "msg-compact"}, "must wait"), "thread-1")

	require.Error(t, err)
	require.Contains(t, err.Error(), "compaction")
	require.Empty(t, writer.requests)
}

func ackedDeliveryInputText(t *testing.T, params map[string]any) string {
	t.Helper()
	input, ok := params["input"].([]any)
	require.True(t, ok)
	require.Len(t, input, 1)
	item, ok := input[0].(map[string]any)
	require.True(t, ok)
	text, ok := item["text"].(string)
	require.True(t, ok)
	return text
}

func capturedRPCMethods(requests []capturedRPCRequest) []string {
	methods := make([]string, 0, len(requests))
	for _, request := range requests {
		methods = append(methods, request.Method)
	}
	return methods
}

func TestCodexReconcileRuntimeInputUsesSingleAuthoritativeRead(t *testing.T) {
	for _, tc := range []struct {
		name   string
		thread appServerThread
		want   RuntimeInputReconciliation
	}{
		{
			name: "acked",
			thread: appServerThread{
				ID:     "thread-1",
				Status: appServerThreadStatus{Type: "idle"},
				Turns: []appServerTurn{{
					ID:        "turn-1",
					ItemsView: "full",
					Status:    appServerTurnStatus{Type: "completed"},
					Items: []appServerItem{{
						Type:     "userMessage",
						ID:       "user-1",
						ClientID: "input-target",
					}},
				}},
			},
			want: RuntimeInputReconciliationAcked,
		},
		{
			name: "absent from full history",
			thread: appServerThread{
				ID:     "thread-1",
				Status: appServerThreadStatus{Type: "idle"},
				Turns: []appServerTurn{{
					ID:        "turn-1",
					ItemsView: "full",
					Status:    appServerTurnStatus{Type: "completed"},
					Items:     []appServerItem{{Type: "userMessage", ClientID: "input-other"}},
				}},
			},
			want: RuntimeInputReconciliationAbsent,
		},
		{
			name: "pending active items not loaded",
			thread: appServerThread{
				ID:     "thread-1",
				Status: appServerThreadStatus{Type: "active"},
				Turns: []appServerTurn{{
					ID:        "turn-live",
					ItemsView: "notLoaded",
					Status:    appServerTurnStatus{Type: "inProgress"},
				}},
			},
			want: RuntimeInputReconciliationPending,
		},
		{
			name: "pending active full history not materialized yet",
			thread: appServerThread{
				ID:     "thread-1",
				Status: appServerThreadStatus{Type: "active"},
				Turns: []appServerTurn{{
					ID:        "turn-live",
					ItemsView: "full",
					Status:    appServerTurnStatus{Type: "inProgress"},
				}},
			},
			want: RuntimeInputReconciliationPending,
		},
		{
			name: "unknown incomplete terminal history",
			thread: appServerThread{
				ID:     "thread-1",
				Status: appServerThreadStatus{Type: "idle"},
				Turns: []appServerTurn{{
					ID:        "turn-1",
					ItemsView: "summary",
					Status:    appServerTurnStatus{Type: "completed"},
				}},
			},
			want: RuntimeInputReconciliationUnknown,
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
				require.Equal(t, "thread/read", req.Method)
				require.Equal(t, "thread-1", req.Params["threadId"])
				require.Equal(t, true, req.Params["includeTurns"])
				return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{Thread: tc.thread})}
			})

			got, err := driver.ReconcileRuntimeInput(context.Background(), "input-target", "thread-1")

			require.NoError(t, err)
			require.Equal(t, tc.want, got)
			require.Equal(t, []string{"thread/read"}, capturedRPCMethods(writer.requests))
		})
	}
}

func TestCodexReconcileUnmaterializedThreadRemainsFailClosed(t *testing.T) {
	for _, tc := range []struct {
		name   string
		status string
		want   RuntimeInputReconciliation
	}{
		{name: "idle is not proof of rejection", status: "idle", want: RuntimeInputReconciliationUnknown},
		{name: "active may be materializing", status: "active", want: RuntimeInputReconciliationPending},
	} {
		t.Run(tc.name, func(t *testing.T) {
			driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
				require.Equal(t, "thread/read", req.Method)
				if req.Params["includeTurns"] == true {
					return appServerEnvelope{Error: &appServerResponseError{
						Code:    -32600,
						Message: "thread thread-fresh is not materialized yet; includeTurns is unavailable before first user message",
					}}
				}
				return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{Thread: appServerThread{
					ID: "thread-fresh", Status: appServerThreadStatus{Type: tc.status},
				}})}
			})

			got, err := driver.ReconcileRuntimeInput(context.Background(), "input-first", "thread-fresh")

			require.NoError(t, err)
			require.Equal(t, tc.want, got)
			require.Equal(t, []string{"thread/read", "thread/read"}, capturedRPCMethods(writer.requests))
		})
	}
}

func TestCodexReconcileEphemeralMetadataCannotProveAbsence(t *testing.T) {
	driver, writer := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
		require.Equal(t, "thread/read", req.Method)
		if req.Params["includeTurns"] == true {
			return appServerEnvelope{Error: &appServerResponseError{
				Code:    -32600,
				Message: "ephemeral threads do not support includeTurns",
			}}
		}
		return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{Thread: appServerThread{
			ID: "thread-ephemeral", Status: appServerThreadStatus{Type: "idle"},
		}})}
	})

	got, err := driver.ReconcileRuntimeInput(context.Background(), "input-unknown", "thread-ephemeral")

	require.NoError(t, err)
	require.Equal(t, RuntimeInputReconciliationUnknown, got)
	require.Equal(t, []string{"thread/read", "thread/read"}, capturedRPCMethods(writer.requests))
}

func TestCodexReconcileRuntimeDeliveryReceiptScansDurableToolResult(t *testing.T) {
	receipt := types.NewRuntimeDeliveryReceipt("0123456789abcdef0123456789abcdef")
	marker := types.RuntimeDeliveryReceiptMarker(receipt)
	rawMarker, err := json.Marshal(map[string]any{"nested": []any{"prefix " + marker + " suffix"}})
	require.NoError(t, err)

	for _, tc := range []struct {
		name   string
		thread appServerThread
		want   RuntimeInputReconciliation
	}{
		{
			name: "acked marker in tool result",
			thread: appServerThread{ID: "thread-1", Status: appServerThreadStatus{Type: "idle"}, Turns: []appServerTurn{{
				ItemsView: "full",
				Items:     []appServerItem{{Type: "mcpToolCall", Result: rawMarker}},
			}}},
			want: RuntimeInputReconciliationAcked,
		},
		{
			name: "acked marker in dynamic content item",
			thread: appServerThread{ID: "thread-1", Status: appServerThreadStatus{Type: "idle"}, Turns: []appServerTurn{{
				ItemsView: "full",
				Items: []appServerItem{{Type: "dynamicToolCall", ContentItems: []appServerDynamicToolCallOutputContentItem{{
					Type: "inputText", Text: marker,
				}}}},
			}}},
			want: RuntimeInputReconciliationAcked,
		},
		{
			name: "absent from complete idle history",
			thread: appServerThread{ID: "thread-1", Status: appServerThreadStatus{Type: "idle"}, Turns: []appServerTurn{{
				ItemsView: "full", Items: []appServerItem{{Type: "mcpToolCall", Result: json.RawMessage(`{"content":"different"}`)}},
			}}},
			want: RuntimeInputReconciliationAbsent,
		},
		{
			name: "active complete history remains pending",
			thread: appServerThread{ID: "thread-1", Status: appServerThreadStatus{Type: "active"}, Turns: []appServerTurn{{
				ItemsView: "full",
			}}},
			want: RuntimeInputReconciliationPending,
		},
		{
			name: "active incomplete history remains pending",
			thread: appServerThread{ID: "thread-1", Status: appServerThreadStatus{Type: "active"}, Turns: []appServerTurn{{
				ItemsView: "summary",
			}}},
			want: RuntimeInputReconciliationPending,
		},
		{
			name: "idle incomplete history is unknown not absent",
			thread: appServerThread{ID: "thread-1", Status: appServerThreadStatus{Type: "idle"}, Turns: []appServerTurn{{
				ItemsView: "notLoaded",
			}}},
			want: RuntimeInputReconciliationUnknown,
		},
	} {
		t.Run(tc.name, func(t *testing.T) {
			driver, _ := newTestCodexDriver(t, func(req capturedRPCRequest) appServerEnvelope {
				require.Equal(t, "thread/read", req.Method)
				return appServerEnvelope{Result: rawRPCResult(t, appServerThreadResult{Thread: tc.thread})}
			})

			got, err := driver.ReconcileRuntimeInput(context.Background(), receipt, "thread-1")

			require.NoError(t, err)
			require.Equal(t, tc.want, got)
		})
	}
}
