package agentidp

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"
)

// mockAgent is the canonical test agent fixture.
var mockAgent = Agent{
	AgentID:       "uuid-1",
	Email:         "a@b.ai",
	AgentType:     "screener",
	Version:       "1.0.0",
	Capabilities:  []string{"read"},
	Owner:         "team",
	DeploymentEnv: "production",
	Status:        "active",
	CreatedAt:     "2026-01-01T00:00:00Z",
	UpdatedAt:     "2026-01-01T00:00:00Z",
}

var mockPaginatedAgents = PaginatedAgents{
	Data:  []Agent{mockAgent},
	Total: 1,
	Page:  1,
	Limit: 20,
}

// staticToken returns a fixed token for all test service clients.
func staticToken(_ context.Context) (string, error) {
	return "test-bearer-token", nil
}

func newAgentServer(t *testing.T, method, path string, status int, body interface{}) *httptest.Server {
	t.Helper()
	return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != method {
			t.Errorf("expected method %s, got %s", method, r.Method)
		}
		if r.URL.Path != path {
			t.Errorf("expected path %s, got %s", path, r.URL.Path)
		}
		if r.Header.Get("Authorization") == "" {
			t.Error("missing Authorization header")
		}
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(status)
		if body != nil {
			_ = json.NewEncoder(w).Encode(body)
		}
	}))
}

func TestAgentRegistryClient_RegisterAgent(t *testing.T) {
	srv := newAgentServer(t, http.MethodPost, "/api/v1/agents", 201, mockAgent)
	defer srv.Close()

	client := newAgentRegistryClient(srv.URL, staticToken, &http.Client{})
	agent, err := client.RegisterAgent(context.Background(), RegisterAgentRequest{
		Email: "a@b.ai", AgentType: "screener", Version: "1.0.0",
		Capabilities: []string{"read"}, Owner: "team", DeploymentEnv: "production",
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if agent.AgentID != "uuid-1" {
		t.Errorf("expected uuid-1, got %q", agent.AgentID)
	}
}

func TestAgentRegistryClient_ListAgents(t *testing.T) {
	srv := newAgentServer(t, http.MethodGet, "/api/v1/agents", 200, mockPaginatedAgents)
	defer srv.Close()

	client := newAgentRegistryClient(srv.URL, staticToken, &http.Client{})
	result, err := client.ListAgents(context.Background(), nil)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if result.Total != 1 {
		t.Errorf("expected total 1, got %d", result.Total)
	}
	if len(result.Data) != 1 || result.Data[0].AgentID != "uuid-1" {
		t.Error("unexpected data in paginated result")
	}
}

func TestAgentRegistryClient_ListAgents_WithParams(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Query().Get("status") != "active" {
			t.Errorf("expected status=active, got %q", r.URL.Query().Get("status"))
		}
		w.Header().Set("Content-Type", "application/json")
		_ = json.NewEncoder(w).Encode(mockPaginatedAgents)
	}))
	defer srv.Close()

	client := newAgentRegistryClient(srv.URL, staticToken, &http.Client{})
	_, err := client.ListAgents(context.Background(), &ListAgentsParams{Status: "active"})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
}

func TestAgentRegistryClient_GetAgent(t *testing.T) {
	srv := newAgentServer(t, http.MethodGet, "/api/v1/agents/uuid-1", 200, mockAgent)
	defer srv.Close()

	client := newAgentRegistryClient(srv.URL, staticToken, &http.Client{})
	agent, err := client.GetAgent(context.Background(), "uuid-1")
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if agent.AgentID != "uuid-1" {
		t.Errorf("expected uuid-1, got %q", agent.AgentID)
	}
}

func TestAgentRegistryClient_GetAgent_NotFound(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(404)
		_ = json.NewEncoder(w).Encode(map[string]string{
			"code":    "AgentNotFoundError",
			"message": "Agent not found.",
		})
	}))
	defer srv.Close()

	client := newAgentRegistryClient(srv.URL, staticToken, &http.Client{})
	_, err := client.GetAgent(context.Background(), "bad-id")
	if err == nil {
		t.Fatal("expected error, got nil")
	}
	apiErr, ok := err.(*AgentIdPError)
	if !ok {
		t.Fatalf("expected *AgentIdPError, got %T", err)
	}
	if apiErr.Code != "AgentNotFoundError" {
		t.Errorf("expected AgentNotFoundError, got %q", apiErr.Code)
	}
	if apiErr.HTTPStatus != 404 {
		t.Errorf("expected 404, got %d", apiErr.HTTPStatus)
	}
}

func TestAgentRegistryClient_UpdateAgent(t *testing.T) {
	updated := mockAgent
	updated.Version = "2.0.0"
	srv := newAgentServer(t, http.MethodPatch, "/api/v1/agents/uuid-1", 200, updated)
	defer srv.Close()

	v := "2.0.0"
	client := newAgentRegistryClient(srv.URL, staticToken, &http.Client{})
	agent, err := client.UpdateAgent(context.Background(), "uuid-1", UpdateAgentRequest{Version: &v})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if agent.Version != "2.0.0" {
		t.Errorf("expected version 2.0.0, got %q", agent.Version)
	}
}

func TestAgentRegistryClient_DecommissionAgent(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodDelete {
			t.Errorf("expected DELETE, got %s", r.Method)
		}
		w.WriteHeader(204)
	}))
	defer srv.Close()

	client := newAgentRegistryClient(srv.URL, staticToken, &http.Client{})
	err := client.DecommissionAgent(context.Background(), "uuid-1")
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
}
