// Copyright (c) 2024 Alibaba Group Holding Ltd.
//
// Licensed 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 main

import (
	"encoding/json"
	"testing"

	"github.com/higress-group/proxy-wasm-go-sdk/proxywasm/types"
	"github.com/higress-group/wasm-go/pkg/test"
	"github.com/stretchr/testify/require"
)

// 测试配置：基本配置（数字过期时间）
var basicConfig = func() json.RawMessage {
	data, _ := json.Marshal(map[string]interface{}{
		"suffix":  "jpg|png|jpeg",
		"expires": "3600",
	})
	return data
}()

// 测试配置：最大缓存时间配置
var maxExpiresConfig = func() json.RawMessage {
	data, _ := json.Marshal(map[string]interface{}{
		"suffix":  "css|js",
		"expires": "max",
	})
	return data
}()

// 测试配置：不缓存配置
var epochExpiresConfig = func() json.RawMessage {
	data, _ := json.Marshal(map[string]interface{}{
		"suffix":  "html|htm",
		"expires": "epoch",
	})
	return data
}()

// 测试配置：无后缀限制配置
var noSuffixConfig = func() json.RawMessage {
	data, _ := json.Marshal(map[string]interface{}{
		"expires": "7200",
	})
	return data
}()

// 测试配置：单后缀配置
var singleSuffixConfig = func() json.RawMessage {
	data, _ := json.Marshal(map[string]interface{}{
		"suffix":  "pdf",
		"expires": "1800",
	})
	return data
}()

// 测试配置：空后缀配置
var emptySuffixConfig = func() json.RawMessage {
	data, _ := json.Marshal(map[string]string{
		"suffix":  "",
		"expires": "3600",
	})
	return data
}()

func TestParseConfig(t *testing.T) {
	test.RunGoTest(t, func(t *testing.T) {
		// 测试基本配置解析
		t.Run("basic config", func(t *testing.T) {
			host, status := test.NewTestHost(basicConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			config, err := host.GetMatchConfig()
			require.NoError(t, err)
			require.NotNil(t, config)
		})

		// 测试最大缓存时间配置解析
		t.Run("max expires config", func(t *testing.T) {
			host, status := test.NewTestHost(maxExpiresConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			config, err := host.GetMatchConfig()
			require.NoError(t, err)
			require.NotNil(t, config)
		})

		// 测试不缓存配置解析
		t.Run("epoch expires config", func(t *testing.T) {
			host, status := test.NewTestHost(epochExpiresConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			config, err := host.GetMatchConfig()
			require.NoError(t, err)
			require.NotNil(t, config)
		})

		// 测试无后缀限制配置解析
		t.Run("no suffix config", func(t *testing.T) {
			host, status := test.NewTestHost(noSuffixConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			config, err := host.GetMatchConfig()
			require.NoError(t, err)
			require.NotNil(t, config)
		})

		// 测试单后缀配置解析
		t.Run("single suffix config", func(t *testing.T) {
			host, status := test.NewTestHost(singleSuffixConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			config, err := host.GetMatchConfig()
			require.NoError(t, err)
			require.NotNil(t, config)
		})

		// 测试空后缀配置解析
		t.Run("empty suffix config", func(t *testing.T) {
			host, status := test.NewTestHost(emptySuffixConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			config, err := host.GetMatchConfig()
			require.NoError(t, err)
			require.NotNil(t, config)
		})
	})
}

func TestOnHttpRequestHeaders(t *testing.T) {
	test.RunTest(t, func(t *testing.T) {
		// 测试基本请求头处理（带查询参数）
		t.Run("request headers with query params", func(t *testing.T) {
			host, status := test.NewTestHost(basicConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			// 设置请求头，包含查询参数
			action := host.CallOnHttpRequestHeaders([][2]string{
				{":authority", "example.com"},
				{":path", "/images/photo.jpg?size=large"},
				{":method", "GET"},
			})

			// 应该返回 ActionContinue
			require.Equal(t, types.ActionContinue, action)

			host.CompleteHttp()
		})

		// 测试请求头处理（无查询参数）
		t.Run("request headers without query params", func(t *testing.T) {
			host, status := test.NewTestHost(basicConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			// 设置请求头，不包含查询参数
			action := host.CallOnHttpRequestHeaders([][2]string{
				{":authority", "example.com"},
				{":path", "/images/photo.png"},
				{":method", "GET"},
			})

			// 应该返回 ActionContinue
			require.Equal(t, types.ActionContinue, action)

			host.CompleteHttp()
		})

		// 测试请求头处理（复杂路径）
		t.Run("request headers with complex path", func(t *testing.T) {
			host, status := test.NewTestHost(basicConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			// 设置请求头，包含复杂路径
			action := host.CallOnHttpRequestHeaders([][2]string{
				{":authority", "example.com"},
				{":path", "/static/css/main.css?v=1.0.0&theme=dark"},
				{":method", "GET"},
			})

			// 应该返回 ActionContinue
			require.Equal(t, types.ActionContinue, action)

			host.CompleteHttp()
		})
	})
}

func TestOnHttpResponseHeaders(t *testing.T) {
	test.RunTest(t, func(t *testing.T) {
		// 测试匹配后缀的响应头处理（数字过期时间）
		t.Run("matching suffix with numeric expires", func(t *testing.T) {
			host, status := test.NewTestHost(basicConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			// 先处理请求头
			host.CallOnHttpRequestHeaders([][2]string{
				{":authority", "example.com"},
				{":path", "/images/photo.jpg"},
				{":method", "GET"},
			})

			// 处理响应头
			action := host.CallOnHttpResponseHeaders([][2]string{
				{":status", "200"},
				{"content-type", "image/jpeg"},
			})

			// 应该返回 ActionContinue
			require.Equal(t, types.ActionContinue, action)

			// 验证是否添加了缓存控制头
			responseHeaders := host.GetResponseHeaders()
			require.True(t, test.HasHeader(responseHeaders, "expires"))
			require.True(t, test.HasHeaderWithValue(responseHeaders, "cache-control", "maxAge=3600"))

			host.CompleteHttp()
		})

		// 测试匹配后缀的响应头处理（最大缓存时间）
		t.Run("matching suffix with max expires", func(t *testing.T) {
			host, status := test.NewTestHost(maxExpiresConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			// 先处理请求头
			host.CallOnHttpRequestHeaders([][2]string{
				{":authority", "example.com"},
				{":path", "/static/main.css"},
				{":method", "GET"},
			})

			// 处理响应头
			action := host.CallOnHttpResponseHeaders([][2]string{
				{":status", "200"},
				{"content-type", "text/css"},
			})

			// 应该返回 ActionContinue
			require.Equal(t, types.ActionContinue, action)

			// 验证是否添加了缓存控制头
			responseHeaders := host.GetResponseHeaders()
			require.True(t, test.HasHeader(responseHeaders, "expires"))
			require.True(t, test.HasHeaderWithValue(responseHeaders, "cache-control", "maxAge=315360000"))

			host.CompleteHttp()
		})

		// 测试匹配后缀的响应头处理（不缓存）
		t.Run("matching suffix with epoch expires", func(t *testing.T) {
			host, status := test.NewTestHost(epochExpiresConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			// 先处理请求头
			host.CallOnHttpRequestHeaders([][2]string{
				{":authority", "example.com"},
				{":path", "/page.html"},
				{":method", "GET"},
			})

			// 处理响应头
			action := host.CallOnHttpResponseHeaders([][2]string{
				{":status", "200"},
				{"content-type", "text/html"},
			})

			// 应该返回 ActionContinue
			require.Equal(t, types.ActionContinue, action)

			// 验证是否添加了缓存控制头
			responseHeaders := host.GetResponseHeaders()
			require.True(t, test.HasHeader(responseHeaders, "expires"))
			require.True(t, test.HasHeaderWithValue(responseHeaders, "cache-control", "no-cache"))

			host.CompleteHttp()
		})

		// 测试不匹配后缀的响应头处理
		t.Run("non-matching suffix", func(t *testing.T) {
			host, status := test.NewTestHost(basicConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			// 先处理请求头
			host.CallOnHttpRequestHeaders([][2]string{
				{":authority", "example.com"},
				{":path", "/api/data.json"},
				{":method", "GET"},
			})

			// 处理响应头
			action := host.CallOnHttpResponseHeaders([][2]string{
				{":status", "200"},
				{"content-type", "application/json"},
			})

			// 应该返回 ActionContinue
			require.Equal(t, types.ActionContinue, action)

			// 验证是否没有添加缓存控制头
			responseHeaders := host.GetResponseHeaders()
			require.False(t, test.HasHeader(responseHeaders, "expires"))
			require.False(t, test.HasHeader(responseHeaders, "cache-control"))

			host.CompleteHttp()
		})

		// 测试无后缀限制的响应头处理
		t.Run("no suffix restriction", func(t *testing.T) {
			host, status := test.NewTestHost(noSuffixConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			// 先处理请求头
			host.CallOnHttpRequestHeaders([][2]string{
				{":authority", "example.com"},
				{":path", "/any/file.txt"},
				{":method", "GET"},
			})

			// 处理响应头
			action := host.CallOnHttpResponseHeaders([][2]string{
				{":status", "200"},
				{"content-type", "text/plain"},
			})

			// 应该返回 ActionContinue
			require.Equal(t, types.ActionContinue, action)

			// 验证是否添加了缓存控制头
			responseHeaders := host.GetResponseHeaders()
			require.True(t, test.HasHeader(responseHeaders, "expires"))
			require.True(t, test.HasHeaderWithValue(responseHeaders, "cache-control", "maxAge=7200"))

			host.CompleteHttp()
		})

		// 测试单后缀匹配
		t.Run("single suffix match", func(t *testing.T) {
			host, status := test.NewTestHost(singleSuffixConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			// 先处理请求头
			host.CallOnHttpRequestHeaders([][2]string{
				{":authority", "example.com"},
				{":path", "/documents/report.pdf"},
				{":method", "GET"},
			})

			// 处理响应头
			action := host.CallOnHttpResponseHeaders([][2]string{
				{":status", "200"},
				{"content-type", "application/pdf"},
			})

			// 应该返回 ActionContinue
			require.Equal(t, types.ActionContinue, action)

			// 验证是否添加了缓存控制头
			responseHeaders := host.GetResponseHeaders()
			require.True(t, test.HasHeader(responseHeaders, "expires"))
			require.True(t, test.HasHeaderWithValue(responseHeaders, "cache-control", "maxAge=1800"))

			host.CompleteHttp()
		})

		// 测试空后缀配置
		t.Run("empty suffix config", func(t *testing.T) {
			host, status := test.NewTestHost(emptySuffixConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			// 先处理请求头
			host.CallOnHttpRequestHeaders([][2]string{
				{":authority", "example.com"},
				{":path", "/any/file.xyz"},
				{":method", "GET"},
			})

			// 处理响应头
			action := host.CallOnHttpResponseHeaders([][2]string{
				{":status", "200"},
				{"content-type", "application/octet-stream"},
			})

			// 应该返回 ActionContinue
			require.Equal(t, types.ActionContinue, action)

			// 验证是否添加了缓存控制头
			responseHeaders := host.GetResponseHeaders()
			require.True(t, test.HasHeader(responseHeaders, "expires"))
			require.True(t, test.HasHeaderWithValue(responseHeaders, "cache-control", "maxAge=3600"))

			host.CompleteHttp()
		})
	})
}

func TestCompleteFlow(t *testing.T) {
	test.RunTest(t, func(t *testing.T) {
		t.Run("complete cache control flow", func(t *testing.T) {
			host, status := test.NewTestHost(basicConfig)
			defer host.Reset()
			require.Equal(t, types.OnPluginStartStatusOK, status)

			// 1. 处理请求头
			action := host.CallOnHttpRequestHeaders([][2]string{
				{":authority", "example.com"},
				{":path", "/images/logo.png"},
				{":method", "GET"},
			})

			// 应该返回 ActionContinue
			require.Equal(t, types.ActionContinue, action)

			// 2. 处理响应头
			action = host.CallOnHttpResponseHeaders([][2]string{
				{":status", "200"},
				{"content-type", "image/png"},
			})

			// 应该返回 ActionContinue
			require.Equal(t, types.ActionContinue, action)

			// 3. 验证完整的缓存控制流程
			responseHeaders := host.GetResponseHeaders()

			// 验证是否添加了必要的缓存控制响应头
			require.True(t, test.HasHeader(responseHeaders, "expires"))
			require.True(t, test.HasHeaderWithValue(responseHeaders, "cache-control", "maxAge=3600"))

			host.CompleteHttp()
		})
	})
}
