package exec

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

	"github.com/stretchr/testify/require"

	"github.com/tidbcloud/AgentTeam/desktop/internal/wire/apiclient"
)

func TestRoleRemoteUsesSevenExactRuntimeRoutesAndJSON(t *testing.T) {
	var requests []string
	var bodies []string
	server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
		requests = append(requests, request.Method+" "+request.URL.RequestURI())
		require.Equal(t, "Bearer token", request.Header.Get("Authorization"))
		if request.Method == http.MethodPost && strings.HasSuffix(request.URL.Path, "/roles/create") ||
			request.Method == http.MethodPost && strings.HasSuffix(request.URL.Path, "/roles/update") ||
			request.Method == http.MethodPost && strings.HasSuffix(request.URL.Path, "/roles/delete") ||
			request.Method == http.MethodPost && strings.HasSuffix(request.URL.Path, "/roles/apply") {
			require.NotEmpty(t, request.Header.Get("Idempotency-Key"))
			require.Equal(t, request.Header.Get("Idempotency-Key"), request.Header.Get("X-Request-ID"))
		}
		if request.Body != nil && request.Method != http.MethodGet {
			body, err := io.ReadAll(request.Body)
			require.NoError(t, err)
			bodies = append(bodies, string(body))
		}
		switch request.URL.Path {
		case "/api/v1/workspaces/ws/agents/agent/runtime/roles":
			_, _ = io.WriteString(writer, `{"roles":[],"nextCursor":"2"}`)
		case "/api/v1/workspaces/ws/agents/agent/runtime/roles/get":
			_, _ = io.WriteString(writer, `{"role":{"roleId":"role_1","name":"Reviewer","definition":"Review","visibility":"private","roleVersionId":"rlv_1","canManage":true}}`)
		case "/api/v1/workspaces/ws/agents/agent/runtime/roles/request-get":
			_, _ = io.WriteString(writer, `{"requestId":"req_1","action":"apply","status":"processing","approvalId":"appr_1","agentId":"agt_target"}`)
		default:
			_, _ = io.WriteString(writer, `{"approvalId":"appr_1","status":"pending"}`)
		}
	}))
	defer server.Close()
	remote := roleRemote{client: &apiclient.Client{
		ServerURL: server.URL, AgentID: "agent", AuthToken: "token",
		RouteWorkspaceID: "ws", HTTPClient: server.Client(),
	}}

	list, err := remote.list(context.Background(), roleListRequest{
		View: "all", Query: "review", Limit: 7, Cursor: "1",
	})
	requireRoleRemoteImplemented(t, err)
	require.NotNil(t, list.Roles)
	_, err = remote.get(context.Background(), roleGetRequest{RoleID: "role_1"})
	requireRoleRemoteImplemented(t, err)
	_, err = remote.requestGet(context.Background(), roleRequestGetRequest{RequestID: "req_1"})
	requireRoleRemoteImplemented(t, err)
	_, err = remote.create(context.Background(), roleCreateRequest{
		RequestID: "req_create", Name: "Reviewer", Definition: "Review", Description: "Reviews",
	})
	requireRoleRemoteImplemented(t, err)
	empty := ""
	_, err = remote.update(context.Background(), roleUpdateRequest{
		RequestID: "req_update", RoleID: "role_1",
		ExpectedRoleVersionID: "rlv_1", Description: &empty,
	})
	requireRoleRemoteImplemented(t, err)
	_, err = remote.delete(context.Background(), roleDeleteRequest{
		RequestID: "req_delete", RoleID: "role_1", ExpectedRoleVersionID: "rlv_1",
	})
	requireRoleRemoteImplemented(t, err)
	_, err = remote.apply(context.Background(), roleApplyRequest{
		RequestID: "req_apply", RoleID: "role_1", RoleVersionID: "rlv_1", AgentID: "agt_target",
	})
	requireRoleRemoteImplemented(t, err)

	require.Equal(t, []string{
		"GET /api/v1/workspaces/ws/agents/agent/runtime/roles?cursor=1&limit=7&q=review&view=all",
		"POST /api/v1/workspaces/ws/agents/agent/runtime/roles/get",
		"POST /api/v1/workspaces/ws/agents/agent/runtime/roles/request-get",
		"POST /api/v1/workspaces/ws/agents/agent/runtime/roles/create",
		"POST /api/v1/workspaces/ws/agents/agent/runtime/roles/update",
		"POST /api/v1/workspaces/ws/agents/agent/runtime/roles/delete",
		"POST /api/v1/workspaces/ws/agents/agent/runtime/roles/apply",
	}, requests)
	require.JSONEq(t, `{"roleId":"role_1"}`, bodies[0])
	require.JSONEq(t, `{"requestId":"req_1"}`, bodies[1])
	require.JSONEq(t, `{"requestId":"req_create","name":"Reviewer","definition":"Review","description":"Reviews"}`, bodies[2])
	require.JSONEq(t, `{"requestId":"req_update","roleId":"role_1","expectedRoleVersionId":"rlv_1","description":""}`, bodies[3])
	require.JSONEq(t, `{"requestId":"req_delete","roleId":"role_1","expectedRoleVersionId":"rlv_1"}`, bodies[4])
	require.JSONEq(t, `{"requestId":"req_apply","roleId":"role_1","roleVersionId":"rlv_1","agentId":"agt_target"}`, bodies[5])
	for _, body := range bodies {
		require.NotContains(t, body, "workspaceId")
		require.NotContains(t, body, "managerUserId")
		require.NotContains(t, body, "ownedAgentIds")
	}
}

func TestRoleRemotePreservesStableAPIErrors(t *testing.T) {
	server := httptest.NewServer(http.HandlerFunc(func(writer http.ResponseWriter, _ *http.Request) {
		writer.WriteHeader(http.StatusConflict)
		_ = json.NewEncoder(writer).Encode(map[string]string{
			"error": "role request conflict", "code": "role_request_conflict",
		})
	}))
	defer server.Close()
	remote := roleRemote{client: &apiclient.Client{
		ServerURL: server.URL, AgentID: "agent", AuthToken: "token",
		RouteWorkspaceID: "ws", HTTPClient: server.Client(),
	}}
	_, err := remote.create(context.Background(), roleCreateRequest{
		RequestID: "req_create", Name: "Reviewer", Definition: "Review",
	})
	require.Error(t, err)
	classified := classifyAPIError(err, "request Role creation failed")
	require.Equal(t, CodeConflict, classified.Code)
	require.Equal(t, "request Role creation failed", classified.Problem)
	require.NotContains(t, classified.Problem, "role request conflict")
}

func requireRoleRemoteImplemented(t *testing.T, err error) {
	t.Helper()
	require.NoError(t, err)
}

var _ roleRuntime = roleRemote{}
