// Package http3 提供 HTTP/3 适配器功能的测试。
//
// 该文件测试 HTTP/3 适配器模块的各项功能，包括：
//   - 适配器创建和初始化
//   - HTTP 请求到 fasthttp 请求的转换
//   - fasthttp 响应到 HTTP 响应的转换
//   - 请求方法、URI、头部、请求体的转换
//   - 完整请求响应流程
//
// 作者：xfy
package http3

import (
	"bytes"
	"io"
	"net/http"
	"net/url"
	"testing"

	"github.com/valyala/fasthttp"
)

// TestNewAdapter 测试适配器创建
func TestNewAdapter(t *testing.T) {
	adapter := NewAdapter()
	if adapter == nil {
		t.Fatal("Expected non-nil adapter")
	}
}

// TestWrap 测试 Wrap 函数基本功能
func TestWrap(t *testing.T) {
	adapter := NewAdapter()

	// 创建一个简单的 fasthttp handler
	handler := func(ctx *fasthttp.RequestCtx) {
		ctx.SetStatusCode(200)
		ctx.SetBodyString("Hello from fasthttp")
		ctx.Response.Header.Set("Content-Type", "text/plain")
	}

	httpHandler := adapter.Wrap(handler)
	if httpHandler == nil {
		t.Error("Expected non-nil http.Handler")
	}
}

// TestConvertRequest_Method 测试请求方法转换
func TestConvertRequest_Method(t *testing.T) {
	adapter := NewAdapter()

	tests := []string{"GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS"}

	for _, method := range tests {
		t.Run(method, func(t *testing.T) {
			req := &http.Request{
				Method: method,
				URL:    &url.URL{Path: "/test"},
				Host:   "localhost",
			}

			ctx := &fasthttp.RequestCtx{}
			ctx.Init(&fasthttp.Request{}, nil, nil)

			adapter.convertRequest(req, ctx)

			if string(ctx.Method()) != method {
				t.Errorf("Expected method %s, got %s", method, ctx.Method())
			}
		})
	}
}

// TestConvertRequest_URI 测试 URI 转换
func TestConvertRequest_URI(t *testing.T) {
	adapter := NewAdapter()

	tests := []struct {
		name     string
		path     string
		query    string
		expected string
	}{
		{
			name:     "simple path",
			path:     "/test",
			query:    "",
			expected: "/test",
		},
		{
			name:     "path with query",
			path:     "/test",
			query:    "foo=bar",
			expected: "/test?foo=bar",
		},
		{
			name:     "path with multiple query params",
			path:     "/api/users",
			query:    "id=1&name=test",
			expected: "/api/users?id=1&name=test",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			req := &http.Request{
				Method: "GET",
				URL:    &url.URL{Path: tt.path, RawQuery: tt.query},
				Host:   "localhost",
			}

			ctx := &fasthttp.RequestCtx{}
			ctx.Init(&fasthttp.Request{}, nil, nil)

			adapter.convertRequest(req, ctx)

			if string(ctx.RequestURI()) != tt.expected {
				t.Errorf("Expected URI %s, got %s", tt.expected, ctx.RequestURI())
			}
		})
	}
}

// TestConvertRequest_Headers 测试头部转换
func TestConvertRequest_Headers(t *testing.T) {
	adapter := NewAdapter()

	req := &http.Request{
		Method: "GET",
		URL:    &url.URL{Path: "/test"},
		Host:   "example.com",
		Header: http.Header{
			"X-Custom-Header": []string{"value1", "value2"},
			"Content-Type":    []string{"application/json"},
			"Accept":          []string{"text/html"},
		},
	}

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	adapter.convertRequest(req, ctx)

	// 检查 Host
	if string(ctx.Host()) != "example.com" {
		t.Errorf("Expected Host example.com, got %s", ctx.Host())
	}

	// 检查头部
	if string(ctx.Request.Header.Peek("Content-Type")) != "application/json" {
		t.Errorf("Expected Content-Type application/json, got %s", ctx.Request.Header.Peek("Content-Type"))
	}

	if string(ctx.Request.Header.Peek("Accept")) != "text/html" {
		t.Errorf("Expected Accept text/html, got %s", ctx.Request.Header.Peek("Accept"))
	}
}

// TestConvertRequest_Body 测试请求体转换
func TestConvertRequest_Body(t *testing.T) {
	adapter := NewAdapter()

	bodyContent := []byte("test request body")
	req := &http.Request{
		Method: "POST",
		URL:    &url.URL{Path: "/test"},
		Host:   "localhost",
		Body:   io.NopCloser(bytes.NewReader(bodyContent)),
	}

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	adapter.convertRequest(req, ctx)

	if !bytes.Equal(ctx.Request.Body(), bodyContent) {
		t.Errorf("Expected body %s, got %s", bodyContent, ctx.Request.Body())
	}
}

// TestConvertRequest_RemoteAddr 测试远程地址转换
func TestConvertRequest_RemoteAddr(t *testing.T) {
	adapter := NewAdapter()

	req := &http.Request{
		Method:     "GET",
		URL:        &url.URL{Path: "/test"},
		Host:       "localhost",
		RemoteAddr: "192.168.1.1:8080",
	}

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	adapter.convertRequest(req, ctx)

	remoteAddr := ctx.RemoteAddr()
	if remoteAddr == nil {
		t.Error("Expected non-nil remote address")
	} else {
		if remoteAddr.String() != "192.168.1.1:8080" {
			t.Errorf("Expected remote addr 192.168.1.1:8080, got %s", remoteAddr.String())
		}
	}
}

// TestConvertResponse_Status 测试响应状态码转换
func TestConvertResponse_Status(t *testing.T) {
	adapter := NewAdapter()

	tests := []int{200, 201, 400, 404, 500}

	for _, status := range tests {
		t.Run(string(rune(status)), func(t *testing.T) {
			ctx := &fasthttp.RequestCtx{}
			ctx.Init(&fasthttp.Request{}, nil, nil)
			ctx.SetStatusCode(status)

			// 创建 mock ResponseWriter
			rw := &mockResponseWriter{}

			adapter.convertResponse(ctx, rw)

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

// TestConvertResponse_DefaultStatus 测试默认状态码
func TestConvertResponse_DefaultStatus(t *testing.T) {
	adapter := NewAdapter()

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)
	// 不设置状态码

	rw := &mockResponseWriter{}

	adapter.convertResponse(ctx, rw)

	// 默认应该是 200
	if rw.status != 200 {
		t.Errorf("Expected default status 200, got %d", rw.status)
	}
}

// TestConvertResponse_Headers 测试响应头部转换
func TestConvertResponse_Headers(t *testing.T) {
	adapter := NewAdapter()

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)
	ctx.Response.Header.Set("Content-Type", "application/json")
	ctx.Response.Header.Set("X-Custom", "value")

	rw := &mockResponseWriter{}

	adapter.convertResponse(ctx, rw)

	if rw.header.Get("Content-Type") != "application/json" {
		t.Errorf("Expected Content-Type application/json, got %s", rw.header.Get("Content-Type"))
	}

	if rw.header.Get("X-Custom") != "value" {
		t.Errorf("Expected X-Custom value, got %s", rw.header.Get("X-Custom"))
	}
}

// TestConvertResponse_Body 测试响应体转换
func TestConvertResponse_Body(t *testing.T) {
	adapter := NewAdapter()

	bodyContent := []byte("response body content")

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)
	ctx.SetBody(bodyContent)

	rw := &mockResponseWriter{}

	adapter.convertResponse(ctx, rw)

	if !bytes.Equal(rw.body, bodyContent) {
		t.Errorf("Expected body %s, got %s", bodyContent, rw.body)
	}
}

// TestWrap_RoundTrip 完整流程测试
func TestWrap_RoundTrip(t *testing.T) {
	adapter := NewAdapter()

	// fasthttp handler
	fastHandler := func(ctx *fasthttp.RequestCtx) {
		// 检查请求
		if string(ctx.Method()) != "POST" {
			t.Errorf("Expected POST method, got %s", ctx.Method())
		}

		// 设置响应
		ctx.SetStatusCode(201)
		ctx.SetBodyString("Created")
		ctx.Response.Header.Set("X-Response-Header", "test-value")
	}

	httpHandler := adapter.Wrap(fastHandler)

	// 创建请求
	req := &http.Request{
		Method: "POST",
		URL:    &url.URL{Path: "/create"},
		Host:   "localhost",
		Header: http.Header{
			"Content-Type": []string{"application/json"},
		},
		Body: io.NopCloser(bytes.NewReader([]byte("request data"))),
	}

	// 创建 mock ResponseWriter
	rw := &mockResponseWriter{}

	// 执行
	httpHandler.ServeHTTP(rw, req)

	// 检查响应
	if rw.status != 201 {
		t.Errorf("Expected status 201, got %d", rw.status)
	}

	if rw.header.Get("X-Response-Header") != "test-value" {
		t.Errorf("Expected X-Response-Header test-value, got %s", rw.header.Get("X-Response-Header"))
	}

	if string(rw.body) != "Created" {
		t.Errorf("Expected body 'Created', got %s", rw.body)
	}
}

// mockResponseWriter 用于测试的 mock ResponseWriter
type mockResponseWriter struct {
	header http.Header
	body   []byte
	status int
}

func (m *mockResponseWriter) Header() http.Header {
	if m.header == nil {
		m.header = make(http.Header)
	}
	return m.header
}

func (m *mockResponseWriter) WriteHeader(statusCode int) {
	m.status = statusCode
}

func (m *mockResponseWriter) Write(data []byte) (int, error) {
	m.body = append(m.body, data...)
	if m.status == 0 {
		m.status = 200
	}
	return len(data), nil
}

// TestStreamRequestBody_LargeBody 测试大请求体的流式处理
func TestStreamRequestBody_LargeBody(t *testing.T) {
	adapter := NewAdapter()

	// 创建大于 64KB 的请求体
	largeBody := make([]byte, 100*1024) // 100KB
	for i := range largeBody {
		largeBody[i] = byte(i % 256)
	}

	req := &http.Request{
		Method:        "POST",
		URL:           &url.URL{Path: "/test"},
		Host:          "localhost",
		Body:          io.NopCloser(bytes.NewReader(largeBody)),
		ContentLength: int64(len(largeBody)),
	}

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	adapter.convertRequest(req, ctx)

	if !bytes.Equal(ctx.Request.Body(), largeBody) {
		t.Errorf("Large body mismatch: expected %d bytes, got %d bytes", len(largeBody), len(ctx.Request.Body()))
	}
}

// TestStreamRequestBody_UnknownContentLength 测试未知内容长度的请求体
func TestStreamRequestBody_UnknownContentLength(t *testing.T) {
	adapter := NewAdapter()

	bodyContent := []byte("test body with unknown length")
	req := &http.Request{
		Method:        "POST",
		URL:           &url.URL{Path: "/test"},
		Host:          "localhost",
		Body:          io.NopCloser(bytes.NewReader(bodyContent)),
		ContentLength: -1, // 未知长度
	}

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	adapter.convertRequest(req, ctx)

	if !bytes.Equal(ctx.Request.Body(), bodyContent) {
		t.Errorf("Body mismatch: expected %s, got %s", bodyContent, ctx.Request.Body())
	}
}

// TestStreamRequestBody_NoBody 测试无请求体的情况
func TestStreamRequestBody_NoBody(t *testing.T) {
	adapter := NewAdapter()

	req := &http.Request{
		Method: "GET",
		URL:    &url.URL{Path: "/test"},
		Host:   "localhost",
		Body:   nil,
	}

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	adapter.convertRequest(req, ctx)

	if len(ctx.Request.Body()) != 0 {
		t.Errorf("Expected empty body, got %d bytes", len(ctx.Request.Body()))
	}
}

// TestStreamRequestBody_NoBodyConstant 测试 http.NoBody 的情况
func TestStreamRequestBody_NoBodyConstant(t *testing.T) {
	adapter := NewAdapter()

	req := &http.Request{
		Method: "GET",
		URL:    &url.URL{Path: "/test"},
		Host:   "localhost",
		Body:   http.NoBody,
	}

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	adapter.convertRequest(req, ctx)

	if len(ctx.Request.Body()) != 0 {
		t.Errorf("Expected empty body with http.NoBody, got %d bytes", len(ctx.Request.Body()))
	}
}

// TestConvertRequest_EmptyRemoteAddr 测试空远程地址
func TestConvertRequest_EmptyRemoteAddr(t *testing.T) {
	adapter := NewAdapter()

	req := &http.Request{
		Method:     "GET",
		URL:        &url.URL{Path: "/test"},
		Host:       "localhost",
		RemoteAddr: "",
	}

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	adapter.convertRequest(req, ctx)

	// 空远程地址不应该导致错误
	// fasthttp 会设置默认值，所以只需验证不会 panic
}

// TestConvertRequest_InvalidRemoteAddr 测试无效远程地址
func TestConvertRequest_InvalidRemoteAddr(t *testing.T) {
	adapter := NewAdapter()

	req := &http.Request{
		Method:     "GET",
		URL:        &url.URL{Path: "/test"},
		Host:       "localhost",
		RemoteAddr: "invalid-address",
	}

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	adapter.convertRequest(req, ctx)

	// 无效远程地址应该被忽略，不应导致错误
	// ctx.RemoteAddr() 可能为 nil 或默认值
}

// TestWrap_TypeAssertionFailure 测试类型断言失败的情况
func TestWrap_TypeAssertionFailure(t *testing.T) {
	adapter := NewAdapter()

	// 创建一个会触发类型断言的 handler
	handler := func(ctx *fasthttp.RequestCtx) {
		ctx.SetStatusCode(200)
		ctx.SetBodyString("OK")
	}

	httpHandler := adapter.Wrap(handler)

	// 执行请求
	req := &http.Request{
		Method: "GET",
		URL:    &url.URL{Path: "/test"},
		Host:   "localhost",
	}

	rw := &mockResponseWriter{}
	httpHandler.ServeHTTP(rw, req)

	// 应该正常处理
	if rw.status != 200 {
		t.Errorf("Expected status 200, got %d", rw.status)
	}
}

// TestConvertResponse_EmptyBody 测试空响应体
func TestConvertResponse_EmptyBody(t *testing.T) {
	adapter := NewAdapter()

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)
	ctx.SetStatusCode(204) // No Content

	rw := &mockResponseWriter{}

	adapter.convertResponse(ctx, rw)

	if rw.status != 204 {
		t.Errorf("Expected status 204, got %d", rw.status)
	}

	if len(rw.body) != 0 {
		t.Errorf("Expected empty body, got %d bytes", len(rw.body))
	}
}

// TestConvertRequest_Protocol 测试协议版本设置
func TestConvertRequest_Protocol(t *testing.T) {
	adapter := NewAdapter()

	req := &http.Request{
		Method: "GET",
		URL:    &url.URL{Path: "/test"},
		Host:   "localhost",
	}

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	adapter.convertRequest(req, ctx)

	protocol := string(ctx.Request.Header.Protocol())
	if protocol != "HTTP/3" {
		t.Errorf("Expected protocol HTTP/3, got %s", protocol)
	}
}

// errorReader 是一个会返回错误的 io.Reader
type errorReader struct{}

func (e *errorReader) Read(_ []byte) (n int, err error) {
	return 0, io.ErrUnexpectedEOF
}

// TestStreamRequestBody_ReadError 测试读取请求体时的错误处理
func TestStreamRequestBody_ReadError(t *testing.T) {
	adapter := NewAdapter()

	req := &http.Request{
		Method:        "POST",
		URL:           &url.URL{Path: "/test"},
		Host:          "localhost",
		Body:          io.NopCloser(&errorReader{}),
		ContentLength: -1, // 强制使用流式读取
	}

	ctx := &fasthttp.RequestCtx{}
	ctx.Init(&fasthttp.Request{}, nil, nil)

	// 这不应该 panic，应该优雅处理错误
	adapter.convertRequest(req, ctx)

	// 错误读取时，body 应该为空
	if len(ctx.Request.Body()) != 0 {
		t.Errorf("Expected empty body on read error, got %d bytes", len(ctx.Request.Body()))
	}
}
