package models

import (
	"net/http"
	"net/http/httptest"
	"testing"
)

func TestFlusherPreservingResponseWriter_Creation(t *testing.T) {
	recorder := httptest.NewRecorder()
	writer := &FlusherPreservingResponseWriter{
		ResponseWriter: recorder,
	}

	if writer.ResponseWriter == nil {
		t.Error("Expected ResponseWriter to be set")
	}
}

func TestFlusherPreservingResponseWriter_Write(t *testing.T) {
	recorder := httptest.NewRecorder()
	writer := &FlusherPreservingResponseWriter{
		ResponseWriter: recorder,
	}

	testData := []byte("Hello, World!")
	n, err := writer.Write(testData)

	if err != nil {
		t.Fatalf("Write failed: %v", err)
	}

	if n != len(testData) {
		t.Errorf("Expected to write %d bytes, wrote %d", len(testData), n)
	}

	if recorder.Body.String() != "Hello, World!" {
		t.Errorf("Expected body 'Hello, World!', got '%s'", recorder.Body.String())
	}
}

func TestFlusherPreservingResponseWriter_Flush(t *testing.T) {
	recorder := httptest.NewRecorder()
	writer := &FlusherPreservingResponseWriter{
		ResponseWriter: recorder,
	}

	// Flush should not panic even if underlying writer doesn't support it
	writer.Flush()

	// Write something
	writer.Write([]byte("test data"))

	// Flush again
	writer.Flush()

	if recorder.Body.String() != "test data" {
		t.Errorf("Expected body 'test data', got '%s'", recorder.Body.String())
	}
}

func TestFlusherPreservingResponseWriter_Header(t *testing.T) {
	recorder := httptest.NewRecorder()
	writer := &FlusherPreservingResponseWriter{
		ResponseWriter: recorder,
	}

	writer.Header().Set("Content-Type", "application/json")
	writer.Header().Set("X-Custom-Header", "test-value")

	if recorder.Header().Get("Content-Type") != "application/json" {
		t.Error("Expected Content-Type header to be set")
	}

	if recorder.Header().Get("X-Custom-Header") != "test-value" {
		t.Error("Expected X-Custom-Header to be set")
	}
}

func TestFlusherPreservingResponseWriter_WriteHeader(t *testing.T) {
	recorder := httptest.NewRecorder()
	writer := &FlusherPreservingResponseWriter{
		ResponseWriter: recorder,
	}

	writer.WriteHeader(http.StatusCreated)

	if recorder.Code != http.StatusCreated {
		t.Errorf("Expected status code %d, got %d", http.StatusCreated, recorder.Code)
	}
}

func TestResponseWriter_Creation(t *testing.T) {
	recorder := httptest.NewRecorder()
	writer := &ResponseWriter{
		ResponseWriter: recorder,
		Size:           0,
	}

	if writer.ResponseWriter == nil {
		t.Error("Expected ResponseWriter to be set")
	}

	if writer.Size != 0 {
		t.Errorf("Expected initial Size 0, got %d", writer.Size)
	}
}

func TestResponseWriter_Write(t *testing.T) {
	recorder := httptest.NewRecorder()
	writer := &ResponseWriter{
		ResponseWriter: recorder,
		Size:           0,
	}

	testData := []byte("Test response data")
	n, err := writer.Write(testData)

	if err != nil {
		t.Fatalf("Write failed: %v", err)
	}

	if n != len(testData) {
		t.Errorf("Expected to write %d bytes, wrote %d", len(testData), n)
	}

	if writer.Size != len(testData) {
		t.Errorf("Expected Size %d, got %d", len(testData), writer.Size)
	}

	if recorder.Body.String() != "Test response data" {
		t.Errorf("Expected body 'Test response data', got '%s'", recorder.Body.String())
	}
}

func TestResponseWriter_MultipleWrites(t *testing.T) {
	recorder := httptest.NewRecorder()
	writer := &ResponseWriter{
		ResponseWriter: recorder,
		Size:           0,
	}

	data1 := []byte("First write. ")
	data2 := []byte("Second write. ")
	data3 := []byte("Third write.")

	writer.Write(data1)
	writer.Write(data2)
	writer.Write(data3)

	expectedSize := len(data1) + len(data2) + len(data3)
	if writer.Size != expectedSize {
		t.Errorf("Expected total Size %d, got %d", expectedSize, writer.Size)
	}

	expectedBody := "First write. Second write. Third write."
	if recorder.Body.String() != expectedBody {
		t.Errorf("Expected body '%s', got '%s'", expectedBody, recorder.Body.String())
	}
}

func TestResponseWriter_EmptyWrite(t *testing.T) {
	recorder := httptest.NewRecorder()
	writer := &ResponseWriter{
		ResponseWriter: recorder,
		Size:           0,
	}

	emptyData := []byte("")
	n, err := writer.Write(emptyData)

	if err != nil {
		t.Fatalf("Write failed: %v", err)
	}

	if n != 0 {
		t.Errorf("Expected to write 0 bytes, wrote %d", n)
	}

	if writer.Size != 0 {
		t.Errorf("Expected Size 0 after empty write, got %d", writer.Size)
	}
}

func TestResponseWriter_Header(t *testing.T) {
	recorder := httptest.NewRecorder()
	writer := &ResponseWriter{
		ResponseWriter: recorder,
	}

	writer.Header().Set("Content-Type", "text/plain")
	writer.Header().Set("Cache-Control", "no-cache")

	if recorder.Header().Get("Content-Type") != "text/plain" {
		t.Error("Expected Content-Type header to be set")
	}

	if recorder.Header().Get("Cache-Control") != "no-cache" {
		t.Error("Expected Cache-Control header to be set")
	}
}

func TestResponseWriter_WriteHeader(t *testing.T) {
	recorder := httptest.NewRecorder()
	writer := &ResponseWriter{
		ResponseWriter: recorder,
	}

	writer.WriteHeader(http.StatusNotFound)

	if recorder.Code != http.StatusNotFound {
		t.Errorf("Expected status code %d, got %d", http.StatusNotFound, recorder.Code)
	}
}

func TestResponseWriter_SizeTracking(t *testing.T) {
	recorder := httptest.NewRecorder()
	writer := &ResponseWriter{
		ResponseWriter: recorder,
		Size:           0,
	}

	testCases := []struct {
		name string
		data string
	}{
		{"Small", "a"},
		{"Medium", "This is a medium-sized response"},
		{"Large", "This is a much larger response with lots of content to test size tracking across multiple writes"},
	}

	totalSize := 0
	for _, tc := range testCases {
		t.Run(tc.name, func(t *testing.T) {
			data := []byte(tc.data)
			n, err := writer.Write(data)

			if err != nil {
				t.Fatalf("Write failed: %v", err)
			}

			totalSize += n

			if writer.Size != totalSize {
				t.Errorf("Expected cumulative Size %d, got %d", totalSize, writer.Size)
			}
		})
	}
}

func TestResponseWriter_LargeWrite(t *testing.T) {
	recorder := httptest.NewRecorder()
	writer := &ResponseWriter{
		ResponseWriter: recorder,
		Size:           0,
	}

	// Create a large payload (10KB)
	largeData := make([]byte, 10*1024)
	for i := range largeData {
		largeData[i] = byte('A' + (i % 26))
	}

	n, err := writer.Write(largeData)

	if err != nil {
		t.Fatalf("Write failed: %v", err)
	}

	if n != len(largeData) {
		t.Errorf("Expected to write %d bytes, wrote %d", len(largeData), n)
	}

	if writer.Size != len(largeData) {
		t.Errorf("Expected Size %d, got %d", len(largeData), writer.Size)
	}
}

func TestFlusherPreservingResponseWriter_WithHandler(t *testing.T) {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "text/event-stream")
		w.WriteHeader(http.StatusOK)
		w.Write([]byte("data: test event\n\n"))

		if flusher, ok := w.(http.Flusher); ok {
			flusher.Flush()
		}
	})

	req := httptest.NewRequest("GET", "/sse", nil)
	recorder := httptest.NewRecorder()
	wrapper := &FlusherPreservingResponseWriter{ResponseWriter: recorder}

	handler.ServeHTTP(wrapper, req)

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

	if recorder.Header().Get("Content-Type") != "text/event-stream" {
		t.Error("Expected Content-Type header for SSE")
	}
}

func TestResponseWriter_WithHandler(t *testing.T) {
	handler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		w.Header().Set("Content-Type", "application/json")
		w.WriteHeader(http.StatusOK)
		w.Write([]byte(`{"message":"success"}`))
	})

	req := httptest.NewRequest("GET", "/api/test", nil)
	recorder := httptest.NewRecorder()
	wrapper := &ResponseWriter{ResponseWriter: recorder, Size: 0}

	handler.ServeHTTP(wrapper, req)

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

	expectedSize := len(`{"message":"success"}`)
	if wrapper.Size != expectedSize {
		t.Errorf("Expected Size %d, got %d", expectedSize, wrapper.Size)
	}
}
