/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package triple

import (
	"net/http"
	"testing"
)

import (
	"github.com/stretchr/testify/assert"
)

import (
	"dubbo.apache.org/dubbo-go/v3/common/constant"
	"dubbo.apache.org/dubbo-go/v3/global"
)

func Test_generateAttachments(t *testing.T) {
	tests := []struct {
		desc   string
		input  func() http.Header
		expect func(t *testing.T, res map[string]any)
	}{
		{
			desc: "empty header",
			input: func() http.Header {
				return http.Header{}
			},
			expect: func(t *testing.T, res map[string]any) {
				assert.Zero(t, len(res))
			},
		},
		{
			desc: "normal header with lowercase keys",
			input: func() http.Header {
				header := make(http.Header)
				header.Set("key1", "val1")
				header.Set("key2", "val2_1")
				header.Add("key2", "val2_2")
				return header
			},
			expect: func(t *testing.T, res map[string]any) {
				assert.Equal(t, 2, len(res))
				assert.Equal(t, []string{"val1"}, res["key1"])
				assert.Equal(t, []string{"val2_1", "val2_2"}, res["key2"])
			},
		},
		{
			desc: "normal header with uppercase keys",
			input: func() http.Header {
				header := make(http.Header)
				header.Set("Key1", "val1")
				header.Set("Key2", "val2_1")
				header.Add("Key2", "val2_2")
				return header
			},
			expect: func(t *testing.T, res map[string]any) {
				assert.Equal(t, 2, len(res))
				assert.Equal(t, []string{"val1"}, res["key1"])
				assert.Equal(t, []string{"val2_1", "val2_2"}, res["key2"])
			},
		},
	}

	for _, test := range tests {
		t.Run(test.desc, func(t *testing.T) {
			atta := generateAttachments(test.input())
			test.expect(t, atta)
		})
	}
}

func TestServer_StartWithHttp2AndHttp3(t *testing.T) {
	// Test configuration for enabling both HTTP/2 and HTTP/3
	tripleConfig := &global.TripleConfig{
		Http3: &global.Http3Config{
			Enable: true, // Enable HTTP/3 (which now means both HTTP/2 and HTTP/3)
		},
	}

	server := NewServer(tripleConfig)

	// This test verifies that the server correctly determines the protocol
	// when Enable is set to true
	// Note: We can't actually start the server in a unit test due to port binding
	// but we can verify the configuration logic

	assert.NotNil(t, server)
	assert.Equal(t, tripleConfig, server.cfg)
}

func TestServer_ProtocolSelection(t *testing.T) {
	tests := []struct {
		name             string
		http3Config      *global.Http3Config
		expectedProtocol string
	}{
		{
			name: "HTTP/2 only (default)",
			http3Config: &global.Http3Config{
				Enable: false,
			},
			expectedProtocol: constant.CallHTTP2,
		},
		{
			name: "HTTP/2 and HTTP/3 both",
			http3Config: &global.Http3Config{
				Enable: true,
			},
			expectedProtocol: constant.CallHTTP2AndHTTP3,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tripleConfig := &global.TripleConfig{
				Http3: tt.http3Config,
			}

			// Extract the protocol selection logic for testing
			var callProtocol string
			if tripleConfig != nil && tripleConfig.Http3 != nil && tripleConfig.Http3.Enable {
				callProtocol = constant.CallHTTP2AndHTTP3
			} else {
				callProtocol = constant.CallHTTP2
			}

			assert.Equal(t, tt.expectedProtocol, callProtocol)
		})
	}
}
