package agentidp

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

var mockAuditEvent = AuditEvent{
	EventID:   "ev-1",
	AgentID:   "uuid-1",
	Action:    "token.issued",
	Outcome:   "success",
	IPAddress: "1.2.3.4",
	UserAgent: "curl",
	Metadata:  map[string]interface{}{},
	Timestamp: "2026-01-01T00:00:00Z",
}

var mockPaginatedAudit = PaginatedAuditEvents{
	Data:  []AuditEvent{mockAuditEvent},
	Total: 1,
	Page:  1,
	Limit: 20,
}

func TestAuditClient_QueryAuditLog(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodGet || r.URL.Path != "/api/v1/audit" {
			t.Errorf("unexpected: %s %s", r.Method, r.URL.Path)
		}
		w.Header().Set("Content-Type", "application/json")
		_ = json.NewEncoder(w).Encode(mockPaginatedAudit)
	}))
	defer srv.Close()

	client := newAuditClient(srv.URL, staticToken, &http.Client{})
	result, err := client.QueryAuditLog(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) == 0 || result.Data[0].EventID != "ev-1" {
		t.Error("unexpected data in paginated result")
	}
}

func TestAuditClient_QueryAuditLog_WithParams(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		q := r.URL.Query()
		if q.Get("agentId") != "uuid-1" {
			t.Errorf("expected agentId=uuid-1, got %q", q.Get("agentId"))
		}
		if q.Get("action") != "token.issued" {
			t.Errorf("expected action=token.issued, got %q", q.Get("action"))
		}
		if q.Get("fromDate") != "2026-01-01" {
			t.Errorf("expected fromDate=2026-01-01, got %q", q.Get("fromDate"))
		}
		w.Header().Set("Content-Type", "application/json")
		_ = json.NewEncoder(w).Encode(mockPaginatedAudit)
	}))
	defer srv.Close()

	client := newAuditClient(srv.URL, staticToken, &http.Client{})
	_, err := client.QueryAuditLog(context.Background(), &QueryAuditParams{
		AgentID:  "uuid-1",
		Action:   "token.issued",
		FromDate: "2026-01-01",
	})
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
}

func TestAuditClient_GetAuditEvent(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Method != http.MethodGet || r.URL.Path != "/api/v1/audit/ev-1" {
			t.Errorf("unexpected: %s %s", r.Method, r.URL.Path)
		}
		w.Header().Set("Content-Type", "application/json")
		_ = json.NewEncoder(w).Encode(mockAuditEvent)
	}))
	defer srv.Close()

	client := newAuditClient(srv.URL, staticToken, &http.Client{})
	event, err := client.GetAuditEvent(context.Background(), "ev-1")
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if event.EventID != "ev-1" {
		t.Errorf("expected ev-1, got %q", event.EventID)
	}
	if event.Action != "token.issued" {
		t.Errorf("expected token.issued, got %q", event.Action)
	}
}

func TestAuditClient_Error_Propagated(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":    "AuditEventNotFoundError",
			"message": "Event not found.",
		})
	}))
	defer srv.Close()

	client := newAuditClient(srv.URL, staticToken, &http.Client{})
	_, err := client.GetAuditEvent(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 != "AuditEventNotFoundError" {
		t.Errorf("expected AuditEventNotFoundError, got %q", apiErr.Code)
	}
}
