// Package handler 提供错误页面管理器功能的测试。
//
// 该文件测试错误页面管理模块的各项功能，包括：
//   - 管理器构造函数
//   - 空配置处理
//   - 部分加载失败处理
//   - 全部加载失败处理
//   - 错误页面查找
//   - 默认页面 fallback
//   - 状态码检查
//   - 响应码覆盖
//   - 配置状态检查
//
// 作者：xfy
package handler

import (
	"fmt"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"rua.plus/lolly/internal/config"
)

// TestNewErrorPageManager_EmptyConfig 测试空配置情况
func TestNewErrorPageManager_EmptyConfig(t *testing.T) {
	tests := []struct {
		want *ErrorPageManager
		name string
		cfg  config.ErrorPageConfig
	}{
		{
			name: "完全空配置",
			cfg:  config.ErrorPageConfig{},
		},
		{
			name: "空的 pages 和 default",
			cfg: config.ErrorPageConfig{
				Pages:   map[int]string{},
				Default: "",
			},
		},
		{
			name: "设置了 responseCode 但无页面",
			cfg: config.ErrorPageConfig{
				Pages:        map[int]string{},
				Default:      "",
				ResponseCode: 200,
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			manager, err := NewErrorPageManager(&tt.cfg)
			if err != nil {
				t.Errorf("NewErrorPageManager() 不应返回错误, got %v", err)
			}
			if manager == nil {
				t.Fatal("NewErrorPageManager() 返回 nil")
			}
			if manager.IsConfigured() {
				t.Error("IsConfigured() 应返回 false")
			}
			if manager.GetResponseCode() != tt.cfg.ResponseCode {
				t.Errorf("GetResponseCode() = %d, want %d", manager.GetResponseCode(), tt.cfg.ResponseCode)
			}
		})
	}
}

// TestNewErrorPageManager_PartialLoadFailure 测试部分加载失败
func TestNewErrorPageManager_PartialLoadFailure(t *testing.T) {
	tmpDir := t.TempDir()

	// 创建有效的错误页面文件
	validPage := filepath.Join(tmpDir, "404.html")
	if err := os.WriteFile(validPage, []byte("404 page"), 0o644); err != nil {
		t.Fatalf("创建测试文件失败: %v", err)
	}

	// 不存在的文件路径
	nonExistent := filepath.Join(tmpDir, "nonexistent", "500.html")

	tests := []struct {
		wantPages      map[int]bool
		name           string
		cfg            config.ErrorPageConfig
		wantConfigured bool
		wantPartialErr bool
	}{
		{
			name: "一个成功一个失败",
			cfg: config.ErrorPageConfig{
				Pages: map[int]string{
					404: validPage,
					500: nonExistent,
				},
			},
			wantConfigured: true,
			wantPages:      map[int]bool{404: true},
			wantPartialErr: true,
		},
		{
			name: "特定页面成功默认失败",
			cfg: config.ErrorPageConfig{
				Pages: map[int]string{
					404: validPage,
				},
				Default: filepath.Join(tmpDir, "default.html"),
			},
			wantConfigured: true,
			wantPages:      map[int]bool{404: true},
			wantPartialErr: true,
		},
		{
			name: "默认成功特定页面失败",
			cfg: config.ErrorPageConfig{
				Pages: map[int]string{
					404: nonExistent,
				},
				Default: validPage,
			},
			wantConfigured: true,
			wantPages:      map[int]bool{},
			wantPartialErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			manager, err := NewErrorPageManager(&tt.cfg)

			// 检查是否为部分错误
			if tt.wantPartialErr {
				if err == nil {
					t.Error("期望返回部分加载错误，但 got nil")
					return
				}
				if _, ok := err.(*PartialLoadError); !ok {
					t.Errorf("期望返回 *PartialLoadError，但 got %T", err)
					return
				}
			} else if err != nil {
				t.Errorf("NewErrorPageManager() 不应返回错误, got %v", err)
				return
			}

			if manager == nil {
				t.Fatal("NewErrorPageManager() 返回 nil")
			}

			if got := manager.IsConfigured(); got != tt.wantConfigured {
				t.Errorf("IsConfigured() = %v, want %v", got, tt.wantConfigured)
			}

			// 检查特定页面是否存在
			for code, shouldExist := range tt.wantPages {
				if got := manager.HasPage(code); got != shouldExist {
					t.Errorf("HasPage(%d) = %v, want %v", code, got, shouldExist)
				}
			}
		})
	}
}

// TestNewErrorPageManager_AllLoadFailure 测试全部加载失败
func TestNewErrorPageManager_AllLoadFailure(t *testing.T) {
	tmpDir := t.TempDir()

	// 不存在的文件路径
	nonExistent1 := filepath.Join(tmpDir, "nonexistent1.html")
	nonExistent2 := filepath.Join(tmpDir, "nonexistent2.html")

	tests := []struct {
		name    string
		cfg     config.ErrorPageConfig
		wantErr bool
	}{
		{
			name: "单个页面加载失败",
			cfg: config.ErrorPageConfig{
				Pages: map[int]string{
					404: nonExistent1,
				},
			},
			wantErr: true,
		},
		{
			name: "多个页面全部加载失败",
			cfg: config.ErrorPageConfig{
				Pages: map[int]string{
					404: nonExistent1,
					500: nonExistent2,
				},
			},
			wantErr: true,
		},
		{
			name: "默认页面加载失败",
			cfg: config.ErrorPageConfig{
				Default: nonExistent1,
			},
			wantErr: true,
		},
		{
			name: "页面和默认都加载失败",
			cfg: config.ErrorPageConfig{
				Pages: map[int]string{
					404: nonExistent1,
				},
				Default: nonExistent2,
			},
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			manager, err := NewErrorPageManager(&tt.cfg)
			if tt.wantErr {
				if err == nil {
					t.Error("期望返回错误，但 got nil")
				}
				// 全部失败时不应返回 PartialLoadError
				if _, ok := err.(*PartialLoadError); ok {
					t.Error("全部失败时不应返回 *PartialLoadError")
				}
				if manager != nil {
					t.Error("全部失败时 manager 应为 nil")
				}
			} else {
				if err != nil {
					t.Errorf("NewErrorPageManager() 不应返回错误, got %v", err)
				}
			}
		})
	}
}

// TestPartialLoadError_Error 测试错误消息格式
func TestPartialLoadError_Error(t *testing.T) {
	tests := []struct {
		name   string
		errors map[int]error
		want   string
	}{
		{
			name:   "单个错误",
			errors: map[int]error{404: os.ErrNotExist},
			want:   "部分错误页面加载失败: 1 个错误",
		},
		{
			name:   "多个错误",
			errors: map[int]error{404: os.ErrNotExist, 500: os.ErrPermission},
			want:   "部分错误页面加载失败: 2 个错误",
		},
		{
			name:   "包含默认页面错误",
			errors: map[int]error{0: os.ErrNotExist, 404: os.ErrNotExist},
			want:   "部分错误页面加载失败: 2 个错误",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := &PartialLoadError{Errors: tt.errors}
			got := err.Error()
			if !strings.Contains(got, tt.want) {
				t.Errorf("Error() = %q, want contain %q", got, tt.want)
			}
		})
	}
}

// TestErrorPageManager_GetPage 测试获取错误页面
func TestErrorPageManager_GetPage(t *testing.T) {
	tmpDir := t.TempDir()

	// 创建测试页面文件
	page404 := filepath.Join(tmpDir, "404.html")
	page500 := filepath.Join(tmpDir, "500.html")
	pageDefault := filepath.Join(tmpDir, "default.html")

	if err := os.WriteFile(page404, []byte("404 page content"), 0o644); err != nil {
		t.Fatalf("创建 404 页面失败: %v", err)
	}
	if err := os.WriteFile(page500, []byte("500 page content"), 0o644); err != nil {
		t.Fatalf("创建 500 页面失败: %v", err)
	}
	if err := os.WriteFile(pageDefault, []byte("default page content"), 0o644); err != nil {
		t.Fatalf("创建默认页面失败: %v", err)
	}

	tests := []struct {
		name             string
		wantContent      string
		cfg              config.ErrorPageConfig
		requestCode      int
		wantResponseCode int
		wantFound        bool
	}{
		{
			name: "找到特定状态码页面",
			cfg: config.ErrorPageConfig{
				Pages: map[int]string{
					404: page404,
					500: page500,
				},
			},
			requestCode:      404,
			wantContent:      "404 page content",
			wantFound:        true,
			wantResponseCode: 404,
		},
		{
			name: "找到另一个状态码页面",
			cfg: config.ErrorPageConfig{
				Pages: map[int]string{
					404: page404,
					500: page500,
				},
			},
			requestCode:      500,
			wantContent:      "500 page content",
			wantFound:        true,
			wantResponseCode: 500,
		},
		{
			name: "未找到特定页面，使用默认页面",
			cfg: config.ErrorPageConfig{
				Pages: map[int]string{
					404: page404,
				},
				Default: pageDefault,
			},
			requestCode:      500,
			wantContent:      "default page content",
			wantFound:        true,
			wantResponseCode: 500,
		},
		{
			name: "未找到页面且无默认页面",
			cfg: config.ErrorPageConfig{
				Pages: map[int]string{
					404: page404,
				},
			},
			requestCode:      500,
			wantContent:      "",
			wantFound:        false,
			wantResponseCode: 500,
		},
		{
			name: "有默认页面但请求特定页面",
			cfg: config.ErrorPageConfig{
				Default: pageDefault,
			},
			requestCode:      503,
			wantContent:      "default page content",
			wantFound:        true,
			wantResponseCode: 503,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			manager, err := NewErrorPageManager(&tt.cfg)
			if err != nil {
				t.Fatalf("NewErrorPageManager() 失败: %v", err)
			}

			content, found, responseCode := manager.GetPage(tt.requestCode)

			if found != tt.wantFound {
				t.Errorf("GetPage() found = %v, want %v", found, tt.wantFound)
			}
			if string(content) != tt.wantContent {
				t.Errorf("GetPage() content = %q, want %q", string(content), tt.wantContent)
			}
			if responseCode != tt.wantResponseCode {
				t.Errorf("GetPage() responseCode = %d, want %d", responseCode, tt.wantResponseCode)
			}
		})
	}
}

// TestErrorPageManager_GetPage_WithResponseCodeOverride 测试响应码覆盖
func TestErrorPageManager_GetPage_WithResponseCodeOverride(t *testing.T) {
	tmpDir := t.TempDir()

	page404 := filepath.Join(tmpDir, "404.html")
	if err := os.WriteFile(page404, []byte("404 page"), 0o644); err != nil {
		t.Fatalf("创建测试文件失败: %v", err)
	}

	cfg := config.ErrorPageConfig{
		Pages: map[int]string{
			404: page404,
		},
		ResponseCode: 200, // 覆盖响应码
	}

	manager, err := NewErrorPageManager(&cfg)
	if err != nil {
		t.Fatalf("NewErrorPageManager() 失败: %v", err)
	}

	_, _, responseCode := manager.GetPage(404)
	if responseCode != 200 {
		t.Errorf("GetPage() responseCode = %d, want 200", responseCode)
	}

	// 测试默认页面也受覆盖影响
	cfg2 := config.ErrorPageConfig{
		Default:      page404,
		ResponseCode: 418,
	}

	manager2, err := NewErrorPageManager(&cfg2)
	if err != nil {
		t.Fatalf("NewErrorPageManager() 失败: %v", err)
	}

	_, _, responseCode2 := manager2.GetPage(500)
	if responseCode2 != 418 {
		t.Errorf("GetPage() responseCode = %d, want 418", responseCode2)
	}
}

// TestErrorPageManager_HasPage 测试页面存在检查
func TestErrorPageManager_HasPage(t *testing.T) {
	tmpDir := t.TempDir()

	page404 := filepath.Join(tmpDir, "404.html")
	pageDefault := filepath.Join(tmpDir, "default.html")

	if err := os.WriteFile(page404, []byte("404"), 0o644); err != nil {
		t.Fatalf("创建测试文件失败: %v", err)
	}
	if err := os.WriteFile(pageDefault, []byte("default"), 0o644); err != nil {
		t.Fatalf("创建测试文件失败: %v", err)
	}

	tests := []struct {
		name     string
		cfg      config.ErrorPageConfig
		code     int
		expected bool
	}{
		{
			name: "配置的特定页面存在",
			cfg: config.ErrorPageConfig{
				Pages: map[int]string{404: page404},
			},
			code:     404,
			expected: true,
		},
		{
			name: "未配置的页面但有默认页面",
			cfg: config.ErrorPageConfig{
				Pages:   map[int]string{404: page404},
				Default: pageDefault,
			},
			code:     500,
			expected: true, // 因为有默认页面
		},
		{
			name: "只有默认页面",
			cfg: config.ErrorPageConfig{
				Default: pageDefault,
			},
			code:     404,
			expected: true,
		},
		{
			name: "页面不存在且无默认页面",
			cfg: config.ErrorPageConfig{
				Pages: map[int]string{404: page404},
			},
			code:     500,
			expected: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			manager, err := NewErrorPageManager(&tt.cfg)
			if err != nil {
				t.Fatalf("NewErrorPageManager() 失败: %v", err)
			}

			if got := manager.HasPage(tt.code); got != tt.expected {
				t.Errorf("HasPage(%d) = %v, want %v", tt.code, got, tt.expected)
			}
		})
	}
}

// TestErrorPageManager_GetResponseCode 测试获取响应码覆盖值
func TestErrorPageManager_GetResponseCode(t *testing.T) {
	tests := []struct {
		name string
		code int
		want int
	}{
		{
			name: "无覆盖",
			code: 0,
			want: 0,
		},
		{
			name: "覆盖为 200",
			code: 200,
			want: 200,
		},
		{
			name: "覆盖为 418",
			code: 418,
			want: 418,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			cfg := config.ErrorPageConfig{
				ResponseCode: tt.code,
			}
			manager, err := NewErrorPageManager(&cfg)
			if err != nil {
				t.Fatalf("NewErrorPageManager() 失败: %v", err)
			}

			if got := manager.GetResponseCode(); got != tt.want {
				t.Errorf("GetResponseCode() = %d, want %d", got, tt.want)
			}
		})
	}
}

// TestErrorPageManager_IsConfigured 测试配置状态检查
func TestErrorPageManager_IsConfigured(t *testing.T) {
	tmpDir := t.TempDir()

	page404 := filepath.Join(tmpDir, "404.html")
	pageDefault := filepath.Join(tmpDir, "default.html")

	if err := os.WriteFile(page404, []byte("404"), 0o644); err != nil {
		t.Fatalf("创建测试文件失败: %v", err)
	}
	if err := os.WriteFile(pageDefault, []byte("default"), 0o644); err != nil {
		t.Fatalf("创建测试文件失败: %v", err)
	}

	tests := []struct {
		name     string
		cfg      config.ErrorPageConfig
		expected bool
	}{
		{
			name:     "空配置",
			cfg:      config.ErrorPageConfig{},
			expected: false,
		},
		{
			name: "配置特定页面",
			cfg: config.ErrorPageConfig{
				Pages: map[int]string{404: page404},
			},
			expected: true,
		},
		{
			name: "配置默认页面",
			cfg: config.ErrorPageConfig{
				Default: pageDefault,
			},
			expected: true,
		},
		{
			name: "配置两者",
			cfg: config.ErrorPageConfig{
				Pages:   map[int]string{404: page404},
				Default: pageDefault,
			},
			expected: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			manager, err := NewErrorPageManager(&tt.cfg)
			if err != nil {
				t.Fatalf("NewErrorPageManager() 失败: %v", err)
			}

			if got := manager.IsConfigured(); got != tt.expected {
				t.Errorf("IsConfigured() = %v, want %v", got, tt.expected)
			}
		})
	}
}

// TestErrorPageManager_SuccessfulLoad 测试成功加载场景
func TestErrorPageManager_SuccessfulLoad(t *testing.T) {
	tmpDir := t.TempDir()

	// 创建多个测试页面
	pages := map[int]string{
		404: filepath.Join(tmpDir, "404.html"),
		500: filepath.Join(tmpDir, "500.html"),
		403: filepath.Join(tmpDir, "403.html"),
	}
	defaultPage := filepath.Join(tmpDir, "default.html")

	for code, path := range pages {
		content := fmt.Appendf(nil, "Error %d page", code)
		if err := os.WriteFile(path, content, 0o644); err != nil {
			t.Fatalf("创建页面 %d 失败: %v", code, err)
		}
	}
	if err := os.WriteFile(defaultPage, []byte("Default error page"), 0o644); err != nil {
		t.Fatalf("创建默认页面失败: %v", err)
	}

	cfg := config.ErrorPageConfig{
		Pages: map[int]string{
			404: pages[404],
			500: pages[500],
			403: pages[403],
		},
		Default: defaultPage,
	}

	manager, err := NewErrorPageManager(&cfg)
	if err != nil {
		t.Fatalf("NewErrorPageManager() 失败: %v", err)
	}

	// 验证所有页面都能正常访问
	for code := range pages {
		content, found, responseCode := manager.GetPage(code)
		if !found {
			t.Errorf("GetPage(%d) 应返回 found=true", code)
		}
		if responseCode != code {
			t.Errorf("GetPage(%d) responseCode = %d, want %d", code, responseCode, code)
		}
		wantContent := fmt.Sprintf("Error %d page", code)
		if string(content) != wantContent {
			t.Errorf("GetPage(%d) content = %q, want %q", code, string(content), wantContent)
		}
	}

	// 验证未配置的状态码返回默认页面
	content, found, responseCode := manager.GetPage(503)
	if !found {
		t.Error("GetPage(503) 应返回 found=true (默认页面)")
	}
	if responseCode != 503 {
		t.Errorf("GetPage(503) responseCode = %d, want 503", responseCode)
	}
	if string(content) != "Default error page" {
		t.Errorf("GetPage(503) content = %q, want default page", string(content))
	}
}
