package handlers

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

	"github.com/breakpilot/consent-service/internal/models"
	"github.com/gin-gonic/gin"
)

func init() {
	gin.SetMode(gin.TestMode)
}

// TestCreateDSR_InvalidBody tests create DSR with invalid body
func TestCreateDSR_InvalidBody_Returns400(t *testing.T) {
	router := gin.New()

	// Mock handler that mimics the actual behavior for invalid body
	router.POST("/api/v1/dsr", func(c *gin.Context) {
		var req models.CreateDSRRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body", "details": err.Error()})
			return
		}
	})

	// Invalid JSON
	req, _ := http.NewRequest("POST", "/api/v1/dsr", bytes.NewBufferString("{invalid json"))
	req.Header.Set("Content-Type", "application/json")

	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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

// TestCreateDSR_MissingType tests create DSR with missing type
func TestCreateDSR_MissingType_Returns400(t *testing.T) {
	router := gin.New()

	router.POST("/api/v1/dsr", func(c *gin.Context) {
		var req models.CreateDSRRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
			return
		}
		if req.RequestType == "" {
			c.JSON(http.StatusBadRequest, gin.H{"error": "request_type is required"})
			return
		}
	})

	body := `{"requester_email": "test@example.com"}`
	req, _ := http.NewRequest("POST", "/api/v1/dsr", bytes.NewBufferString(body))
	req.Header.Set("Content-Type", "application/json")

	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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

// TestCreateDSR_InvalidType tests create DSR with invalid type
func TestCreateDSR_InvalidType_Returns400(t *testing.T) {
	router := gin.New()

	router.POST("/api/v1/dsr", func(c *gin.Context) {
		var req models.CreateDSRRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
			return
		}
		if !models.IsValidDSRRequestType(req.RequestType) {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid request_type"})
			return
		}
	})

	body := `{"request_type": "invalid_type", "requester_email": "test@example.com"}`
	req, _ := http.NewRequest("POST", "/api/v1/dsr", bytes.NewBufferString(body))
	req.Header.Set("Content-Type", "application/json")

	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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

// TestAdminListDSR_Unauthorized_Returns401 tests admin list without auth
func TestAdminListDSR_Unauthorized_Returns401(t *testing.T) {
	router := gin.New()

	// Simplified auth check
	router.GET("/api/v1/admin/dsr", func(c *gin.Context) {
		authHeader := c.GetHeader("Authorization")
		if authHeader == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization required"})
			return
		}
		c.JSON(http.StatusOK, gin.H{"requests": []interface{}{}})
	})

	req, _ := http.NewRequest("GET", "/api/v1/admin/dsr", nil)

	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

	if w.Code != http.StatusUnauthorized {
		t.Errorf("Expected status 401, got %d", w.Code)
	}
}

// TestAdminListDSR_ValidRequest tests admin list with valid auth
func TestAdminListDSR_ValidRequest_Returns200(t *testing.T) {
	router := gin.New()

	router.GET("/api/v1/admin/dsr", func(c *gin.Context) {
		authHeader := c.GetHeader("Authorization")
		if authHeader == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization required"})
			return
		}
		c.JSON(http.StatusOK, gin.H{
			"requests": []interface{}{},
			"total":    0,
			"limit":    20,
			"offset":   0,
		})
	})

	req, _ := http.NewRequest("GET", "/api/v1/admin/dsr", nil)
	req.Header.Set("Authorization", "Bearer test-token")

	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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

	var response map[string]interface{}
	json.Unmarshal(w.Body.Bytes(), &response)

	if _, ok := response["requests"]; !ok {
		t.Error("Response should contain 'requests' field")
	}
	if _, ok := response["total"]; !ok {
		t.Error("Response should contain 'total' field")
	}
}

// TestAdminGetDSRStats_ValidRequest tests admin stats endpoint
func TestAdminGetDSRStats_ValidRequest_Returns200(t *testing.T) {
	router := gin.New()

	router.GET("/api/v1/admin/dsr/stats", func(c *gin.Context) {
		authHeader := c.GetHeader("Authorization")
		if authHeader == "" {
			c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization required"})
			return
		}
		c.JSON(http.StatusOK, gin.H{
			"total_requests":         0,
			"pending_requests":       0,
			"overdue_requests":       0,
			"completed_this_month":   0,
			"average_processing_days": 0,
			"by_type":                map[string]int{},
			"by_status":              map[string]int{},
		})
	})

	req, _ := http.NewRequest("GET", "/api/v1/admin/dsr/stats", nil)
	req.Header.Set("Authorization", "Bearer test-token")

	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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

	var response map[string]interface{}
	json.Unmarshal(w.Body.Bytes(), &response)

	expectedFields := []string{"total_requests", "pending_requests", "overdue_requests", "by_type", "by_status"}
	for _, field := range expectedFields {
		if _, ok := response[field]; !ok {
			t.Errorf("Response should contain '%s' field", field)
		}
	}
}

// TestAdminUpdateDSR_InvalidStatus_Returns400 tests admin update with invalid status
func TestAdminUpdateDSR_InvalidStatus_Returns400(t *testing.T) {
	router := gin.New()

	router.PUT("/api/v1/admin/dsr/:id", func(c *gin.Context) {
		var req models.UpdateDSRRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
			return
		}
		if req.Status != nil && !models.IsValidDSRStatus(*req.Status) {
			c.JSON(http.StatusBadRequest, gin.H{"error": "invalid status"})
			return
		}
		c.JSON(http.StatusOK, gin.H{"message": "Updated"})
	})

	body := `{"status": "invalid_status"}`
	req, _ := http.NewRequest("PUT", "/api/v1/admin/dsr/123", bytes.NewBufferString(body))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer test-token")

	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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

// TestAdminVerifyIdentity_ValidRequest_Returns200 tests identity verification
func TestAdminVerifyIdentity_ValidRequest_Returns200(t *testing.T) {
	router := gin.New()

	router.POST("/api/v1/admin/dsr/:id/verify-identity", func(c *gin.Context) {
		var req models.VerifyDSRIdentityRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
			return
		}
		if req.Method == "" {
			c.JSON(http.StatusBadRequest, gin.H{"error": "method is required"})
			return
		}
		c.JSON(http.StatusOK, gin.H{"message": "Identität verifiziert"})
	})

	body := `{"method": "id_card"}`
	req, _ := http.NewRequest("POST", "/api/v1/admin/dsr/123/verify-identity", bytes.NewBufferString(body))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer test-token")

	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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

// TestAdminExtendDeadline_MissingReason_Returns400 tests extend deadline without reason
func TestAdminExtendDeadline_MissingReason_Returns400(t *testing.T) {
	router := gin.New()

	router.POST("/api/v1/admin/dsr/:id/extend", func(c *gin.Context) {
		var req models.ExtendDSRDeadlineRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
			return
		}
		if req.Reason == "" {
			c.JSON(http.StatusBadRequest, gin.H{"error": "reason is required"})
			return
		}
		c.JSON(http.StatusOK, gin.H{"message": "Deadline extended"})
	})

	body := `{"days": 30}`
	req, _ := http.NewRequest("POST", "/api/v1/admin/dsr/123/extend", bytes.NewBufferString(body))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer test-token")

	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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

// TestAdminCompleteDSR_ValidRequest_Returns200 tests complete DSR
func TestAdminCompleteDSR_ValidRequest_Returns200(t *testing.T) {
	router := gin.New()

	router.POST("/api/v1/admin/dsr/:id/complete", func(c *gin.Context) {
		var req models.CompleteDSRRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
			return
		}
		c.JSON(http.StatusOK, gin.H{"message": "Anfrage erfolgreich abgeschlossen"})
	})

	body := `{"result_summary": "Alle Daten wurden bereitgestellt"}`
	req, _ := http.NewRequest("POST", "/api/v1/admin/dsr/123/complete", bytes.NewBufferString(body))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer test-token")

	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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

// TestAdminRejectDSR_MissingLegalBasis_Returns400 tests reject DSR without legal basis
func TestAdminRejectDSR_MissingLegalBasis_Returns400(t *testing.T) {
	router := gin.New()

	router.POST("/api/v1/admin/dsr/:id/reject", func(c *gin.Context) {
		var req models.RejectDSRRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
			return
		}
		if req.LegalBasis == "" {
			c.JSON(http.StatusBadRequest, gin.H{"error": "legal_basis is required"})
			return
		}
		c.JSON(http.StatusOK, gin.H{"message": "Rejected"})
	})

	body := `{"reason": "Some reason"}`
	req, _ := http.NewRequest("POST", "/api/v1/admin/dsr/123/reject", bytes.NewBufferString(body))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer test-token")

	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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

// TestAdminRejectDSR_ValidRequest_Returns200 tests reject DSR with valid data
func TestAdminRejectDSR_ValidRequest_Returns200(t *testing.T) {
	router := gin.New()

	router.POST("/api/v1/admin/dsr/:id/reject", func(c *gin.Context) {
		var req models.RejectDSRRequest
		if err := c.ShouldBindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})
			return
		}
		if req.LegalBasis == "" {
			c.JSON(http.StatusBadRequest, gin.H{"error": "legal_basis is required"})
			return
		}
		c.JSON(http.StatusOK, gin.H{"message": "Anfrage abgelehnt"})
	})

	body := `{"reason": "Daten benötigt für Rechtsstreit", "legal_basis": "Art. 17(3)e"}`
	req, _ := http.NewRequest("POST", "/api/v1/admin/dsr/123/reject", bytes.NewBufferString(body))
	req.Header.Set("Content-Type", "application/json")
	req.Header.Set("Authorization", "Bearer test-token")

	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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

// TestGetDSRTemplates_Returns200 tests templates endpoint
func TestGetDSRTemplates_Returns200(t *testing.T) {
	router := gin.New()

	router.GET("/api/v1/admin/dsr-templates", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{
			"templates": []map[string]interface{}{
				{
					"id":            "uuid-1",
					"template_type": "dsr_receipt_access",
					"name":          "Eingangsbestätigung (Art. 15)",
				},
			},
		})
	})

	req, _ := http.NewRequest("GET", "/api/v1/admin/dsr-templates", nil)
	req.Header.Set("Authorization", "Bearer test-token")

	w := httptest.NewRecorder()
	router.ServeHTTP(w, req)

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

	var response map[string]interface{}
	json.Unmarshal(w.Body.Bytes(), &response)

	if _, ok := response["templates"]; !ok {
		t.Error("Response should contain 'templates' field")
	}
}

// TestRequestTypeValidation tests all valid request types
func TestRequestTypeValidation(t *testing.T) {
	validTypes := []string{"access", "rectification", "erasure", "restriction", "portability"}

	for _, reqType := range validTypes {
		if !models.IsValidDSRRequestType(reqType) {
			t.Errorf("Expected %s to be a valid request type", reqType)
		}
	}

	invalidTypes := []string{"invalid", "delete", "copy", ""}
	for _, reqType := range invalidTypes {
		if models.IsValidDSRRequestType(reqType) {
			t.Errorf("Expected %s to be an invalid request type", reqType)
		}
	}
}

// TestStatusValidation tests all valid statuses
func TestStatusValidation(t *testing.T) {
	validStatuses := []string{"intake", "identity_verification", "processing", "completed", "rejected", "cancelled"}

	for _, status := range validStatuses {
		if !models.IsValidDSRStatus(status) {
			t.Errorf("Expected %s to be a valid status", status)
		}
	}

	invalidStatuses := []string{"invalid", "pending", "done", ""}
	for _, status := range invalidStatuses {
		if models.IsValidDSRStatus(status) {
			t.Errorf("Expected %s to be an invalid status", status)
		}
	}
}
