package cmd

import (
	"encoding/json"
	"io"
	"net/http"
	"net/http/httptest"
	"os"
	"strings"
	"testing"

	"github.com/stretchr/testify/require"

	agentteamexec "github.com/tidbcloud/AgentTeam/desktop/internal/api/exec"
)

// TestExecCLIRejectsSelectorMismatchedReceipts proves the final Cobra/stderr
// boundary does not turn a malformed applied receipt into a recovery command.
// The daemon route and LocalClient are real; only the upstream response is a
// deliberately mismatched receipt for scalar, composite, and batch selectors.
func TestExecCLIRejectsSelectorMismatchedReceipts(t *testing.T) {
	_, closeDaemon := setExecCommandTestRuntime(t, nil)
	t.Cleanup(closeDaemon)
	daemonBaseURL := strings.TrimSpace(os.Getenv(agentteamexec.EnvBaseURL))
	tokenPath := os.Getenv(agentteamexec.EnvTokenFile)
	tokenBytes, err := os.ReadFile(tokenPath)
	require.NoError(t, err)
	catalogRequest, err := http.NewRequest(http.MethodGet, daemonBaseURL+"/catalog", nil)
	require.NoError(t, err)
	catalogRequest.Header.Set("Authorization", "Bearer "+strings.TrimSpace(string(tokenBytes)))
	catalogResponse, err := http.DefaultClient.Do(catalogRequest)
	require.NoError(t, err)
	catalogBody, err := io.ReadAll(catalogResponse.Body)
	require.NoError(t, catalogResponse.Body.Close())
	require.Equal(t, http.StatusOK, catalogResponse.StatusCode)

	proxy := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if strings.HasSuffix(r.URL.Path, "/catalog") {
			w.Header().Set("Content-Type", "application/json")
			_, _ = w.Write(catalogBody)
			return
		}
		var receipt map[string]any
		switch {
		case strings.HasSuffix(r.URL.Path, "/channel/update"):
			receipt = map[string]any{
				"applied": true, "action": "channel update",
				"identifiers": map[string]string{"channelId": "chn_wrong", "requestId": "req_scalar"}, "idempotencyKey": "req_scalar",
			}
		case strings.HasSuffix(r.URL.Path, "/workflow/step"):
			receipt = map[string]any{
				"applied": true, "action": "workflow step",
				"identifiers": map[string]string{"runId": "wri_wrong", "stepId": "wfx_1", "idempotencyKey": "step_composite"}, "idempotencyKey": "step_composite",
			}
		case strings.HasSuffix(r.URL.Path, "/agent/delete"):
			receipt = map[string]any{
				"applied": true, "action": "agent delete",
				"identifiers": map[string]string{"agentIds": `["agt_2","agt_1"]`, "requestId": "req_batch"}, "idempotencyKey": "req_batch",
			}
		default:
			http.NotFound(w, r)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusRequestEntityTooLarge)
		_ = json.NewEncoder(w).Encode(map[string]any{"error": agentteamexec.ErrorEnvelope{
			Code: agentteamexec.CodeResultBudgetExceeded, Problem: "result too large",
			Metadata: map[string]any{"mutation_applied": true, "mutation_receipt": receipt},
		}})
	}))
	t.Cleanup(proxy.Close)
	setExecCommandTokenFile(t, proxy.URL+"/api/internal/exec/servers/server-1/agents/agent-1", strings.TrimSpace(string(tokenBytes)))

	cases := []struct {
		name, domain, action, input string
	}{
		{name: "scalar", domain: "channel", action: "update", input: `{"requestId":"req_scalar","channelId":"chn_1","expectedVersion":1,"displayName":"ops"}`},
		{name: "composite", domain: "workflow", action: "step", input: `{"action":"complete","runId":"wri_1","stepId":"wfx_1","idempotencyKey":"step_composite","output":{}}`},
		{name: "batch", domain: "agent", action: "delete", input: `{"requestId":"req_batch","agentIds":["agt_1","agt_2"]}`},
	}
	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			_, stderr, err := executeCobra(newExecCommand(), tc.domain, tc.action, tc.input)
			require.Error(t, err)
			require.NotContains(t, stderr, `"mutation_applied":true`)
			require.Contains(t, stderr, "Mutation outcome is unknown")
			require.NotContains(t, strings.ToLower(stderr), "agentteam exec "+tc.domain)
		})
	}
}
