// Package http2 提供 HTTP/2 TLS 连接集成测试。
//
// 该文件测试 HTTP/2 服务器的 TLS 相关功能：
//   - TLS 握手成功/失败
//   - ALPN 协商 h2/http1.1
//   - HTTP/1.1 回退路径
//
// 作者：xfy
package http2

import (
	"context"
	"crypto/rand"
	"crypto/rsa"
	"crypto/tls"
	"crypto/x509"
	"crypto/x509/pkix"
	"math/big"
	"net"
	"sync"
	"testing"
	"time"

	"github.com/valyala/fasthttp"
	"rua.plus/lolly/internal/config"
)

// generateTestCert 生成测试用自签名证书。
func generateTestCert(t *testing.T) (tls.Certificate, *x509.CertPool) {
	t.Helper()

	privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
	if err != nil {
		t.Fatalf("Failed to generate private key: %v", err)
	}

	template := &x509.Certificate{
		SerialNumber: big.NewInt(1),
		Subject: pkix.Name{
			Organization: []string{"Test Org"},
		},
		NotBefore:             time.Now(),
		NotAfter:              time.Now().Add(time.Hour),
		KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
		BasicConstraintsValid: true,
		DNSNames:              []string{"localhost"},
		IPAddresses:           []net.IP{net.ParseIP("127.0.0.1")},
	}

	certDER, err := x509.CreateCertificate(rand.Reader, template, template, &privateKey.PublicKey, privateKey)
	if err != nil {
		t.Fatalf("Failed to create certificate: %v", err)
	}

	cert := tls.Certificate{
		Certificate: [][]byte{certDER},
		PrivateKey:  privateKey,
	}

	certPool := x509.NewCertPool()
	certPool.AppendCertsFromPEM(certDER)

	return cert, certPool
}

// TestTLSHandshakeSuccess 测试 TLS 握手成功。
func TestTLSHandshakeSuccess(t *testing.T) {
	cert, _ := generateTestCert(t)

	handler := func(ctx *fasthttp.RequestCtx) {
		ctx.WriteString("Hello HTTP/2")
		ctx.SetStatusCode(fasthttp.StatusOK)
	}

	cfg := &config.HTTP2Config{
		Enabled:              true,
		MaxConcurrentStreams: 100,
	}

	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
		NextProtos:   []string{"h2", "http/1.1"},
	}

	server, err := NewServer(cfg, handler, tlsConfig)
	if err != nil {
		t.Fatalf("Failed to create server: %v", err)
	}

	// 创建管道连接
	serverConn, clientConn := net.Pipe()
	defer func() {
		_ = serverConn.Close()
		_ = clientConn.Close()
	}()

	// 包装服务器端连接为 TLS
	tlsServerConn := tls.Server(serverConn, tlsConfig)

	// 需要先 Add(1) 因为 handleConnection 会调用 Done()
	server.connWg.Add(1)

	// 在后台处理连接
	go func() {
		server.handleConnection(tlsServerConn)
	}()

	// 客户端 TLS 握手
	tlsClientConfig := &tls.Config{
		InsecureSkipVerify: true,
		NextProtos:         []string{"h2"},
	}
	tlsClientConn := tls.Client(clientConn, tlsClientConfig)

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := tlsClientConn.HandshakeContext(ctx); err != nil {
		t.Fatalf("TLS handshake failed: %v", err)
	}

	// 验证协商的协议
	state := tlsClientConn.ConnectionState()
	if state.NegotiatedProtocol != "h2" {
		t.Errorf("Expected negotiated protocol 'h2', got '%s'", state.NegotiatedProtocol)
	}

	// 关闭连接
	_ = tlsClientConn.Close()
	_ = tlsServerConn.Close()

	// 等待处理完成
	done := make(chan struct{})
	go func() {
		server.connWg.Wait()
		close(done)
	}()
	select {
	case <-done:
		t.Log("Connection handling completed")
	case <-time.After(2 * time.Second):
		t.Log("Timeout waiting for connection handling")
	}
}

// TestTLSHandshakeFailure 测试 TLS 握手失败。
func TestTLSHandshakeFailure(t *testing.T) {
	cert, _ := generateTestCert(t)

	handler := func(ctx *fasthttp.RequestCtx) {
		ctx.WriteString("Hello")
	}

	cfg := &config.HTTP2Config{
		Enabled: true,
	}

	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
		NextProtos:   []string{"h2"},
	}

	server, err := NewServer(cfg, handler, tlsConfig)
	if err != nil {
		t.Fatalf("Failed to create server: %v", err)
	}

	serverConn, clientConn := net.Pipe()

	// 包装服务器端连接为 TLS
	tlsServerConn := tls.Server(serverConn, tlsConfig)

	// 需要先 Add(1) 因为 handleConnection 会调用 Done()
	server.connWg.Add(1)

	// 在后台处理连接
	go func() {
		server.handleConnection(tlsServerConn)
	}()

	// 客户端不进行 TLS 握手，直接发送无效数据
	_, _ = clientConn.Write([]byte("INVALID DATA NOT TLS"))

	// 等待处理完成
	time.Sleep(200 * time.Millisecond)

	// 关闭连接
	_ = clientConn.Close()
	_ = tlsServerConn.Close()

	// 等待处理完成
	done := make(chan struct{})
	go func() {
		server.connWg.Wait()
		close(done)
	}()
	select {
	case <-done:
		t.Log("Connection handling completed after handshake failure")
	case <-time.After(2 * time.Second):
		t.Log("Timeout waiting for connection handling")
	}
}

// TestALPNNegotiationH2 测试 ALPN 协商选择 h2。

// TestALPNHTTP11Fallback 测试 ALPN 协商回退到 HTTP/1.1。
func TestALPNHTTP11Fallback(t *testing.T) {
	cert, _ := generateTestCert(t)

	handler := func(ctx *fasthttp.RequestCtx) {
		ctx.WriteString("HTTP/1.1 response")
		ctx.SetStatusCode(fasthttp.StatusOK)
	}

	cfg := &config.HTTP2Config{
		Enabled: true,
	}

	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
		NextProtos:   []string{"h2", "http/1.1"},
	}

	server, err := NewServer(cfg, handler, tlsConfig)
	if err != nil {
		t.Fatalf("Failed to create server: %v", err)
	}

	serverConn, clientConn := net.Pipe()
	defer func() {
		_ = serverConn.Close()
		_ = clientConn.Close()
	}()

	tlsServerConn := tls.Server(serverConn, tlsConfig)

	// 需要先 Add(1) 因为 handleConnection 会调用 Done()
	server.connWg.Add(1)

	go func() {
		server.handleConnection(tlsServerConn)
	}()

	// 客户端只支持 HTTP/1.1
	tlsClientConfig := &tls.Config{
		InsecureSkipVerify: true,
		NextProtos:         []string{"http/1.1"},
	}
	tlsClientConn := tls.Client(clientConn, tlsClientConfig)

	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := tlsClientConn.HandshakeContext(ctx); err != nil {
		t.Fatalf("TLS handshake failed: %v", err)
	}

	// 验证协商的协议是 http/1.1
	state := tlsClientConn.ConnectionState()
	if state.NegotiatedProtocol != "http/1.1" {
		t.Errorf("Expected negotiated protocol 'http/1.1', got '%s'", state.NegotiatedProtocol)
	}

	_ = tlsClientConn.Close()
	_ = tlsServerConn.Close()
}

// TestTLSListenerWrapper 测试 TLS 监听器包装。

// TestTLSListenerExistingProtos 测试已有 NextProtos 的情况。

// TestServeHTTP1Fallback 测试 HTTP/1.1 回退。
func TestServeHTTP1Fallback(t *testing.T) {
	handler := func(ctx *fasthttp.RequestCtx) {
		ctx.WriteString("HTTP/1.1 response")
		ctx.SetStatusCode(fasthttp.StatusOK)
		ctx.Response.Header.Set("X-Test", "value")
	}

	cfg := &config.HTTP2Config{
		Enabled: true,
	}

	server, err := NewServer(cfg, handler, nil)
	if err != nil {
		t.Fatalf("Failed to create server: %v", err)
	}

	serverConn, clientConn := net.Pipe()
	defer func() {
		_ = serverConn.Close()
		_ = clientConn.Close()
	}()

	var wg sync.WaitGroup
	wg.Go(func() {
		server.serveHTTP1(serverConn)
	})

	// 发送 HTTP/1.1 请求
	request := "GET /test HTTP/1.1\r\nHost: localhost\r\n\r\n"
	_, _ = clientConn.Write([]byte(request))

	// 读取响应
	buf := make([]byte, 1024)
	_ = clientConn.SetReadDeadline(time.Now().Add(2 * time.Second))
	n, err := clientConn.Read(buf)
	if err != nil {
		t.Fatalf("Failed to read response: %v", err)
	}

	response := string(buf[:n])
	if response == "" {
		t.Error("Expected non-empty response")
	}

	// 关闭连接
	_ = clientConn.Close()
	wg.Wait()
}

// TestConnectionPoolOperations 测试连接池操作。
func TestConnectionPoolOperations(t *testing.T) {
	pool := newConnectionPool()

	// 创建模拟连接
	conn1 := &mockTestConn{remoteAddr: &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 12345}}
	conn2 := &mockTestConn{remoteAddr: &net.TCPAddr{IP: net.ParseIP("127.0.0.1"), Port: 12346}}

	// 添加连接
	pool.add("client1", conn1)
	pool.add("client1", conn2)

	// 验证连接数
	if count := len(pool.conns["client1"]); count != 2 {
		t.Errorf("Expected 2 connections, got %d", count)
	}

	// 获取连接
	conns := pool.conns["client1"]
	if len(conns) != 2 {
		t.Errorf("Expected 2 connections, got %d", len(conns))
	}

	// 移除连接
	pool.remove("client1", conn1)
	if count := len(pool.conns["client1"]); count != 1 {
		t.Errorf("Expected 1 connection after removal, got %d", count)
	}

	// 关闭所有连接
	pool.closeAll()
	if count := len(pool.conns["client1"]); count != 0 {
		t.Errorf("Expected 0 connections after closeAll, got %d", count)
	}
}

// mockTestConn 是用于测试的模拟连接。
type mockTestConn struct {
	remoteAddr net.Addr
}

func (m *mockTestConn) Read(_ []byte) (n int, err error)  { return 0, nil }
func (m *mockTestConn) Write(_ []byte) (n int, err error) { return 0, nil }
func (m *mockTestConn) Close() error                      { return nil }
func (m *mockTestConn) LocalAddr() net.Addr               { return m.remoteAddr }
func (m *mockTestConn) RemoteAddr() net.Addr              { return m.remoteAddr }
func (m *mockTestConn) SetDeadline(_ time.Time) error     { return nil }
func (m *mockTestConn) SetReadDeadline(_ time.Time) error { return nil }
func (m *mockTestConn) SetWriteDeadline(_ time.Time) error {
	return nil
}
