package ucxi

import (
	"bytes"
	"encoding/json"
	"fmt"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"chorus.services/bzzz/pkg/ucxl"
)

// Helper function to create test server for UCXL testing 
func createUCXLTestServer() *Server {
	config := ServerConfig{
		Port:     8080,
		BasePath: "/test",
		Resolver: NewMockResolver(), // Use existing MockResolver from server_test.go
		Storage:  NewMockStorage(),  // Use existing MockStorage from server_test.go
		Logger:   SimpleLogger{},
	}
	return NewServer(config)
}

// Test UCXL standardized response formats
func TestUCXLResponseFormats(t *testing.T) {
	server := createUCXLTestServer()
	
	tests := []struct {
		name           string
		method         string
		endpoint       string
		query          string
		body           string
		expectedCode   ucxl.UCXLCode
		expectedStatus int
	}{
		{
			name:           "GET with valid address returns UCXL-200-SUCCESS",
			method:         "GET",
			endpoint:       "/test/ucxi/v1/get",
			query:          "address=ucxl://agent:role@project:task/*^",
			body:           "",
			expectedCode:   ucxl.CodeSuccess,
			expectedStatus: 200,
		},
		{
			name:           "GET without address returns UCXL-400-BAD_REQUEST",
			method:         "GET",
			endpoint:       "/test/ucxi/v1/get",
			query:          "",
			body:           "",
			expectedCode:   ucxl.CodeBadRequest,
			expectedStatus: 400,
		},
		{
			name:           "GET with invalid address returns UCXL-400-INVALID_ADDRESS",
			method:         "GET",
			endpoint:       "/test/ucxi/v1/get",
			query:          "address=invalid-address",
			body:           "",
			expectedCode:   ucxl.CodeInvalidAddress,
			expectedStatus: 400,
		},
		{
			name:           "PUT with valid data returns UCXL-201-CREATED",
			method:         "PUT",
			endpoint:       "/test/ucxi/v1/put",
			query:          "address=ucxl://agent:role@project:task/*^",
			body:           "test content",
			expectedCode:   ucxl.CodeCreated,
			expectedStatus: 201,
		},
		{
			name:           "DELETE with valid address returns UCXL-200-SUCCESS",
			method:         "DELETE",
			endpoint:       "/test/ucxi/v1/delete",
			query:          "address=ucxl://agent:role@project:task/*^",
			body:           "",
			expectedCode:   ucxl.CodeSuccess,
			expectedStatus: 200,
		},
		{
			name:           "POST to GET endpoint returns UCXL-405-METHOD_NOT_ALLOWED",
			method:         "POST",
			endpoint:       "/test/ucxi/v1/get",
			query:          "",
			body:           "",
			expectedCode:   ucxl.CodeMethodNotAllowed,
			expectedStatus: 405,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			// Create request
			var req *http.Request
			var err error
			
			if tt.body != "" {
				req, err = http.NewRequest(tt.method, tt.endpoint+"?"+tt.query, strings.NewReader(tt.body))
			} else {
				req, err = http.NewRequest(tt.method, tt.endpoint+"?"+tt.query, nil)
			}
			if err != nil {
				t.Fatalf("Failed to create request: %v", err)
			}
			
			req.Header.Set("Content-Type", "text/plain")
			req.Header.Set("X-Request-ID", "test-"+tt.name)

			// Create response recorder
			rr := httptest.NewRecorder()

			// Create HTTP handler
			mux := http.NewServeMux()
			server.registerRoutes(mux)
			handler := server.withMiddleware(mux)

			// Execute request
			handler.ServeHTTP(rr, req)

			// Check status code
			if rr.Code != tt.expectedStatus {
				t.Errorf("Expected status %d, got %d", tt.expectedStatus, rr.Code)
			}

			// Parse response
			var response map[string]interface{}
			if err := json.Unmarshal(rr.Body.Bytes(), &response); err != nil {
				t.Fatalf("Failed to parse response JSON: %v", err)
			}

			// Check for UCXL response structure
			if rr.Code >= 200 && rr.Code < 300 {
				// Success response should have "response" field
				if responseData, ok := response["response"]; ok {
					if responseMap, ok := responseData.(map[string]interface{}); ok {
						if code, ok := responseMap["code"].(string); ok {
							if ucxl.UCXLCode(code) != tt.expectedCode {
								t.Errorf("Expected UCXL code %s, got %s", tt.expectedCode, code)
							}
						} else {
							t.Error("Response missing 'code' field")
						}

						// Check required fields
						if _, ok := responseMap["message"]; !ok {
							t.Error("Response missing 'message' field")
						}
						if _, ok := responseMap["request_id"]; !ok {
							t.Error("Response missing 'request_id' field")
						}
						if _, ok := responseMap["timestamp"]; !ok {
							t.Error("Response missing 'timestamp' field")
						}
					}
				} else {
					t.Error("Success response missing 'response' field")
				}
			} else {
				// Error response should have "error" field
				if errorData, ok := response["error"]; ok {
					if errorMap, ok := errorData.(map[string]interface{}); ok {
						if code, ok := errorMap["code"].(string); ok {
							if ucxl.UCXLCode(code) != tt.expectedCode {
								t.Errorf("Expected UCXL code %s, got %s", tt.expectedCode, code)
							}
						} else {
							t.Error("Error response missing 'code' field")
						}

						// Check required fields
						if _, ok := errorMap["message"]; !ok {
							t.Error("Error response missing 'message' field")
						}
						if _, ok := errorMap["source"]; !ok {
							t.Error("Error response missing 'source' field")
						}
						if _, ok := errorMap["path"]; !ok {
							t.Error("Error response missing 'path' field")
						}
						if _, ok := errorMap["request_id"]; !ok {
							t.Error("Error response missing 'request_id' field")
						}
						if _, ok := errorMap["timestamp"]; !ok {
							t.Error("Error response missing 'timestamp' field")
						}
					}
				} else {
					t.Error("Error response missing 'error' field")
				}
			}
		})
	}
}

// Test status endpoint provides comprehensive information per Issue 010
func TestStatusEndpoint(t *testing.T) {
	server := createUCXLTestServer()

	req, err := http.NewRequest("GET", "/test/ucxi/v1/status", nil)
	if err != nil {
		t.Fatalf("Failed to create request: %v", err)
	}
	req.Header.Set("X-Request-ID", "test-status")

	rr := httptest.NewRecorder()
	mux := http.NewServeMux()
	server.registerRoutes(mux)
	handler := server.withMiddleware(mux)
	handler.ServeHTTP(rr, req)

	if rr.Code != 200 {
		t.Errorf("Expected status 200, got %d", rr.Code)
	}

	var response map[string]interface{}
	if err := json.Unmarshal(rr.Body.Bytes(), &response); err != nil {
		t.Fatalf("Failed to parse response JSON: %v", err)
	}

	// Check UCXL response structure
	responseData, ok := response["response"].(map[string]interface{})
	if !ok {
		t.Fatal("Response missing 'response' field")
	}

	data, ok := responseData["data"].(map[string]interface{})
	if !ok {
		t.Fatal("Response data missing")
	}

	// Check required status fields per Issue 010
	requiredFields := []string{"server", "ucxi", "resolver", "storage", "navigators", "p2p", "metrics"}
	for _, field := range requiredFields {
		if _, ok := data[field]; !ok {
			t.Errorf("Status response missing required field: %s", field)
		}
	}

	// Check server info
	if serverInfo, ok := data["server"].(map[string]interface{}); ok {
		serverFields := []string{"port", "base_path", "running", "version"}
		for _, field := range serverFields {
			if _, ok := serverInfo[field]; !ok {
				t.Errorf("Server info missing field: %s", field)
			}
		}
	} else {
		t.Error("Status response missing server information")
	}

	// Check resolver stats
	if resolverInfo, ok := data["resolver"].(map[string]interface{}); ok {
		if enabled, ok := resolverInfo["enabled"].(bool); !ok || !enabled {
			t.Error("Resolver should be enabled in test")
		}
	} else {
		t.Error("Status response missing resolver information")
	}

	// Check storage metrics
	if storageInfo, ok := data["storage"].(map[string]interface{}); ok {
		if enabled, ok := storageInfo["enabled"].(bool); !ok || !enabled {
			t.Error("Storage should be enabled in test")
		}
	} else {
		t.Error("Status response missing storage information")
	}
}

// Test announce endpoint with JSON payload
func TestAnnounceEndpoint(t *testing.T) {
	server := createUCXLTestServer()

	payload := map[string]interface{}{
		"address": "ucxl://agent:role@project:task/*^",
		"content": map[string]interface{}{
			"data":         "dGVzdCBjb250ZW50", // base64 encoded "test content"
			"content_type": "text/plain",
			"metadata":     map[string]string{"author": "test"},
		},
	}

	payloadBytes, err := json.Marshal(payload)
	if err != nil {
		t.Fatalf("Failed to marshal payload: %v", err)
	}

	req, err := http.NewRequest("POST", "/test/ucxi/v1/announce", bytes.NewReader(payloadBytes))
	if err != nil {
		t.Fatalf("Failed to create request: %v", err)
	}
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("X-Request-ID", "test-announce")

	rr := httptest.NewRecorder()
	mux := http.NewServeMux()
	server.registerRoutes(mux)
	handler := server.withMiddleware(mux)
	handler.ServeHTTP(rr, req)

	if rr.Code != 200 {
		t.Errorf("Expected status 200, got %d", rr.Code)
	}

	var response map[string]interface{}
	if err := json.Unmarshal(rr.Body.Bytes(), &response); err != nil {
		t.Fatalf("Failed to parse response JSON: %v", err)
	}

	// Verify UCXL success response structure
	responseData, ok := response["response"].(map[string]interface{})
	if !ok {
		t.Fatal("Response missing 'response' field")
	}

	if code, ok := responseData["code"].(string); !ok || ucxl.UCXLCode(code) != ucxl.CodeSuccess {
		t.Errorf("Expected UCXL-200-SUCCESS, got %s", code)
	}
}

// Test error handling with invalid UCXL addresses
func TestInvalidAddressHandling(t *testing.T) {
	server := createUCXLTestServer()

	invalidAddresses := []string{
		"not-a-ucxl-address",
		"ucxl://",
		"ucxl://agent",
		"ucxl://agent:role",
		"ucxl://agent:role@project",
		"ucxl://agent:role@project:task",
		"ucxl://agent:role@project:task/invalid-temporal",
	}

	for i, address := range invalidAddresses {
		t.Run(fmt.Sprintf("InvalidAddress%d", i), func(t *testing.T) {
			req, err := http.NewRequest("GET", "/test/ucxi/v1/get?address="+address, nil)
			if err != nil {
				t.Fatalf("Failed to create request: %v", err)
			}
			req.Header.Set("X-Request-ID", fmt.Sprintf("test-invalid-%d", i))

			rr := httptest.NewRecorder()
			mux := http.NewServeMux()
			server.registerRoutes(mux)
			handler := server.withMiddleware(mux)
			handler.ServeHTTP(rr, req)

			if rr.Code != 400 {
				t.Errorf("Expected status 400, got %d", rr.Code)
			}

			var response map[string]interface{}
			if err := json.Unmarshal(rr.Body.Bytes(), &response); err != nil {
				t.Fatalf("Failed to parse response JSON: %v", err)
			}

			// Should be UCXL error format
			errorData, ok := response["error"].(map[string]interface{})
			if !ok {
				t.Fatal("Error response missing 'error' field")
			}

			code, ok := errorData["code"].(string)
			if !ok {
				t.Fatal("Error missing 'code' field")
			}

			// Should be either invalid address or bad request
			ucxlCode := ucxl.UCXLCode(code)
			if ucxlCode != ucxl.CodeInvalidAddress && ucxlCode != ucxl.CodeBadRequest {
				t.Errorf("Expected INVALID_ADDRESS or BAD_REQUEST, got %s", code)
			}
		})
	}
}

// Benchmark UCXL response building
func BenchmarkUCXLResponseBuilding(b *testing.B) {
	builder := ucxl.NewResponseBuilder("test-request-id", "ucxi-server")
	data := map[string]interface{}{
		"test": "data",
		"count": 42,
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_ = builder.OK(data)
	}
}

// Benchmark UCXL error building
func BenchmarkUCXLErrorBuilding(b *testing.B) {
	builder := ucxl.NewResponseBuilder("test-request-id", "ucxi-server")
	details := map[string]interface{}{
		"field": "address",
		"provided": "invalid-address",
	}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_ = builder.ErrorWithDetails(ucxl.CodeInvalidAddress, "Invalid address", "/test/path", details)
	}
}