package handlers

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

	"github.com/gin-gonic/gin"
)

// TestWebhookEventTypes tests the event types we handle
func TestWebhookEventTypes(t *testing.T) {
	eventTypes := []struct {
		eventType   string
		shouldHandle bool
	}{
		{"checkout.session.completed", true},
		{"customer.subscription.created", true},
		{"customer.subscription.updated", true},
		{"customer.subscription.deleted", true},
		{"invoice.paid", true},
		{"invoice.payment_failed", true},
		{"customer.created", true}, // Handled but just logged
		{"unknown.event.type", false},
	}

	for _, tt := range eventTypes {
		t.Run(tt.eventType, func(t *testing.T) {
			if tt.eventType == "" {
				t.Error("Event type should not be empty")
			}
		})
	}
}

// TestWebhookRequest_MissingSignature tests handling of missing signature
func TestWebhookRequest_MissingSignature(t *testing.T) {
	gin.SetMode(gin.TestMode)
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)

	// Create request without Stripe-Signature header
	body := []byte(`{"id": "evt_test_123", "type": "test.event"}`)
	c.Request = httptest.NewRequest("POST", "/webhook", bytes.NewReader(body))
	c.Request.Header.Set("Content-Type", "application/json")
	// Note: No Stripe-Signature header

	// Simulate the check we do in the handler
	sigHeader := c.GetHeader("Stripe-Signature")
	if sigHeader == "" {
		c.JSON(http.StatusBadRequest, gin.H{"error": "missing signature"})
	}

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

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

	if response["error"] != "missing signature" {
		t.Errorf("Expected 'missing signature' error, got '%v'", response["error"])
	}
}

// TestWebhookRequest_EmptyBody tests handling of empty request body
func TestWebhookRequest_EmptyBody(t *testing.T) {
	gin.SetMode(gin.TestMode)
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)

	// Create request with empty body
	c.Request = httptest.NewRequest("POST", "/webhook", bytes.NewReader([]byte{}))
	c.Request.Header.Set("Content-Type", "application/json")
	c.Request.Header.Set("Stripe-Signature", "t=123,v1=signature")

	// Read the body
	body := make([]byte, 0)

	// Simulate empty body handling
	if len(body) == 0 {
		c.JSON(http.StatusBadRequest, gin.H{"error": "empty body"})
	}

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

// TestWebhookIdempotency tests idempotency behavior
func TestWebhookIdempotency(t *testing.T) {
	// Test that the same event ID should not be processed twice
	eventID := "evt_test_123456789"

	// Simulate event tracking
	processedEvents := make(map[string]bool)

	// First time - should process
	if !processedEvents[eventID] {
		processedEvents[eventID] = true
	}

	// Second time - should skip
	alreadyProcessed := processedEvents[eventID]
	if !alreadyProcessed {
		t.Error("Event should be marked as processed")
	}
}

// TestWebhookResponse_Processed tests successful webhook response
func TestWebhookResponse_Processed(t *testing.T) {
	gin.SetMode(gin.TestMode)
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)

	c.JSON(http.StatusOK, gin.H{"status": "processed"})

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

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

	if response["status"] != "processed" {
		t.Errorf("Expected status 'processed', got '%v'", response["status"])
	}
}

// TestWebhookResponse_AlreadyProcessed tests idempotent response
func TestWebhookResponse_AlreadyProcessed(t *testing.T) {
	gin.SetMode(gin.TestMode)
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)

	c.JSON(http.StatusOK, gin.H{"status": "already_processed"})

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

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

	if response["status"] != "already_processed" {
		t.Errorf("Expected status 'already_processed', got '%v'", response["status"])
	}
}

// TestWebhookResponse_InternalError tests error response
func TestWebhookResponse_InternalError(t *testing.T) {
	gin.SetMode(gin.TestMode)
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)

	c.JSON(http.StatusInternalServerError, gin.H{"error": "handler error"})

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

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

	if response["error"] != "handler error" {
		t.Errorf("Expected 'handler error', got '%v'", response["error"])
	}
}

// TestWebhookResponse_InvalidSignature tests signature verification failure
func TestWebhookResponse_InvalidSignature(t *testing.T) {
	gin.SetMode(gin.TestMode)
	w := httptest.NewRecorder()
	c, _ := gin.CreateTestContext(w)

	c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid signature"})

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

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

	if response["error"] != "invalid signature" {
		t.Errorf("Expected 'invalid signature', got '%v'", response["error"])
	}
}

// TestCheckoutSessionCompleted_EventStructure tests the event data structure
func TestCheckoutSessionCompleted_EventStructure(t *testing.T) {
	// Test the expected structure of a checkout.session.completed event
	eventData := map[string]interface{}{
		"id":                  "cs_test_123",
		"customer":            "cus_test_456",
		"subscription":        "sub_test_789",
		"mode":                "subscription",
		"payment_status":      "paid",
		"status":              "complete",
		"metadata": map[string]interface{}{
			"user_id": "550e8400-e29b-41d4-a716-446655440000",
			"plan_id": "standard",
		},
	}

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

	var decoded map[string]interface{}
	err = json.Unmarshal(data, &decoded)
	if err != nil {
		t.Fatalf("Failed to unmarshal event data: %v", err)
	}

	// Verify required fields
	if decoded["customer"] == nil {
		t.Error("Event should have 'customer' field")
	}
	if decoded["subscription"] == nil {
		t.Error("Event should have 'subscription' field")
	}
	metadata, ok := decoded["metadata"].(map[string]interface{})
	if !ok || metadata["user_id"] == nil {
		t.Error("Event should have 'metadata.user_id' field")
	}
}

// TestSubscriptionCreated_EventStructure tests subscription.created event structure
func TestSubscriptionCreated_EventStructure(t *testing.T) {
	eventData := map[string]interface{}{
		"id":       "sub_test_123",
		"customer": "cus_test_456",
		"status":   "trialing",
		"items": map[string]interface{}{
			"data": []map[string]interface{}{
				{
					"price": map[string]interface{}{
						"id":       "price_test_789",
						"metadata": map[string]interface{}{"plan_id": "standard"},
					},
				},
			},
		},
		"trial_end":          1735689600,
		"current_period_end": 1735689600,
		"metadata": map[string]interface{}{
			"user_id": "550e8400-e29b-41d4-a716-446655440000",
			"plan_id": "standard",
		},
	}

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

	var decoded map[string]interface{}
	err = json.Unmarshal(data, &decoded)
	if err != nil {
		t.Fatalf("Failed to unmarshal event data: %v", err)
	}

	// Verify required fields
	if decoded["status"] != "trialing" {
		t.Errorf("Expected status 'trialing', got '%v'", decoded["status"])
	}
}

// TestSubscriptionUpdated_StatusTransitions tests subscription status transitions
func TestSubscriptionUpdated_StatusTransitions(t *testing.T) {
	validTransitions := []struct {
		from string
		to   string
	}{
		{"trialing", "active"},
		{"active", "past_due"},
		{"past_due", "active"},
		{"active", "canceled"},
		{"trialing", "canceled"},
	}

	for _, tt := range validTransitions {
		t.Run(tt.from+"->"+tt.to, func(t *testing.T) {
			if tt.from == "" || tt.to == "" {
				t.Error("Status should not be empty")
			}
		})
	}
}

// TestInvoicePaid_EventStructure tests invoice.paid event structure
func TestInvoicePaid_EventStructure(t *testing.T) {
	eventData := map[string]interface{}{
		"id":                   "in_test_123",
		"subscription":         "sub_test_456",
		"customer":             "cus_test_789",
		"status":               "paid",
		"amount_paid":          1990,
		"currency":             "eur",
		"period_start":         1735689600,
		"period_end":           1738368000,
		"hosted_invoice_url":   "https://invoice.stripe.com/test",
		"invoice_pdf":          "https://invoice.stripe.com/test.pdf",
	}

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

	var decoded map[string]interface{}
	err = json.Unmarshal(data, &decoded)
	if err != nil {
		t.Fatalf("Failed to unmarshal event data: %v", err)
	}

	// Verify required fields
	if decoded["status"] != "paid" {
		t.Errorf("Expected status 'paid', got '%v'", decoded["status"])
	}
	if decoded["subscription"] == nil {
		t.Error("Event should have 'subscription' field")
	}
}

// TestInvoicePaymentFailed_EventStructure tests invoice.payment_failed event structure
func TestInvoicePaymentFailed_EventStructure(t *testing.T) {
	eventData := map[string]interface{}{
		"id":               "in_test_123",
		"subscription":     "sub_test_456",
		"customer":         "cus_test_789",
		"status":           "open",
		"attempt_count":    1,
		"next_payment_attempt": 1735776000,
	}

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

	var decoded map[string]interface{}
	err = json.Unmarshal(data, &decoded)
	if err != nil {
		t.Fatalf("Failed to unmarshal event data: %v", err)
	}

	// Verify fields
	if decoded["attempt_count"] == nil {
		t.Error("Event should have 'attempt_count' field")
	}
}

// TestSubscriptionDeleted_EventStructure tests subscription.deleted event structure
func TestSubscriptionDeleted_EventStructure(t *testing.T) {
	eventData := map[string]interface{}{
		"id":            "sub_test_123",
		"customer":      "cus_test_456",
		"status":        "canceled",
		"ended_at":      1735689600,
		"canceled_at":   1735689600,
	}

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

	var decoded map[string]interface{}
	err = json.Unmarshal(data, &decoded)
	if err != nil {
		t.Fatalf("Failed to unmarshal event data: %v", err)
	}

	// Verify required fields
	if decoded["status"] != "canceled" {
		t.Errorf("Expected status 'canceled', got '%v'", decoded["status"])
	}
}

// TestStripeSignatureFormat tests the Stripe signature header format
func TestStripeSignatureFormat(t *testing.T) {
	// Stripe signature format: t=timestamp,v1=signature
	validSignatures := []string{
		"t=1609459200,v1=abc123def456",
		"t=1609459200,v1=signature_here,v0=old_signature",
	}

	for _, sig := range validSignatures {
		if len(sig) < 10 {
			t.Errorf("Signature seems too short: %s", sig)
		}
		// Should start with timestamp
		if sig[:2] != "t=" {
			t.Errorf("Signature should start with 't=': %s", sig)
		}
	}
}

// TestWebhookEventID_Format tests Stripe event ID format
func TestWebhookEventID_Format(t *testing.T) {
	validEventIDs := []string{
		"evt_1234567890abcdef",
		"evt_test_123456789",
		"evt_live_987654321",
	}

	for _, eventID := range validEventIDs {
		// Event IDs should start with "evt_"
		if len(eventID) < 10 || eventID[:4] != "evt_" {
			t.Errorf("Invalid event ID format: %s", eventID)
		}
	}
}
