package main

import (
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"github.com/gin-gonic/gin"
)

func TestSetupStaticFiles(t *testing.T) {
	gin.SetMode(gin.TestMode)

	distFS, err := frontendDistFS()
	if err != nil {
		t.Skipf("跳过测试: 前端资源未构建: %v", err)
		return
	}

	r := gin.New()
	setupStaticFilesWithFS(r, distFS)

	t.Run("API 404", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/api/test", nil)
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		if w.Code != 404 {
			t.Errorf("期望状态码 404, 实际 %d", w.Code)
		}
	})

	t.Run("OpenAI proxy prefix 404", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/openai/", nil)
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		if w.Code != http.StatusNotFound {
			t.Errorf("期望状态码 404, 实际 %d", w.Code)
		}
		if !strings.Contains(w.Body.String(), "not found") {
			t.Errorf("期望返回 API 风格错误，实际 %s", w.Body.String())
		}
	})

	t.Run("Anthropic proxy prefix 404", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/anthropic/", nil)
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		if w.Code != http.StatusNotFound {
			t.Errorf("期望状态码 404, 实际 %d", w.Code)
		}
		if !strings.Contains(w.Body.String(), "not found") {
			t.Errorf("期望返回 API 风格错误，实际 %s", w.Body.String())
		}
	})

	t.Run("SPA fallback", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/providers", nil)
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		if w.Code != 200 {
			t.Errorf("期望状态码 200, 实际 %d", w.Code)
		}
	})

	t.Run("MIME type for JS", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/assets/test.js", nil)
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		if w.Code == 200 {
			expected := "application/javascript"
			if w.Header().Get("Content-Type") != expected {
				t.Errorf("期望 Content-Type %s, 实际 %s", expected, w.Header().Get("Content-Type"))
			}
		} else {
			t.Log("文件不存在，跳过 MIME 类型验证")
		}
	})

	t.Run("MIME type for CSS", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/assets/test.css", nil)
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		if w.Code == 200 {
			expected := "text/css"
			if w.Header().Get("Content-Type") != expected {
				t.Errorf("期望 Content-Type %s, 实际 %s", expected, w.Header().Get("Content-Type"))
			}
		} else {
			t.Log("文件不存在，跳过 MIME 类型验证")
		}
	})

	t.Log("静态文件服务测试通过")
}

func TestWithProtocolAndStaticRoutes(t *testing.T) {
	gin.SetMode(gin.TestMode)

	distFS, err := frontendDistFS()
	if err != nil {
		t.Skipf("跳过测试: 前端资源未构建: %v", err)
		return
	}

	r := gin.New()

	var gotProtocol string
	var gotPath string
	r.Any("/openai/*path", withProtocol("openai", func(c *gin.Context) {
		gotProtocol = c.Param("protocol")
		gotPath = c.Param("path")
		c.JSON(http.StatusOK, gin.H{"protocol": gotProtocol, "path": gotPath})
	}))
	r.Any("/anthropic/*path", withProtocol("anthropic", func(c *gin.Context) {
		gotProtocol = c.Param("protocol")
		gotPath = c.Param("path")
		c.JSON(http.StatusOK, gin.H{"protocol": gotProtocol, "path": gotPath})
	}))
	setupStaticFilesWithFS(r, distFS)

	t.Run("OpenAI route enters proxy handler wrapper", func(t *testing.T) {
		gotProtocol = ""
		gotPath = ""

		req := httptest.NewRequest("POST", "/openai/v1/chat/completions", nil)
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		if w.Code != http.StatusOK {
			t.Errorf("期望状态码 200, 实际 %d", w.Code)
		}
		if gotProtocol != "openai" {
			t.Errorf("期望 protocol=openai, 实际 %s", gotProtocol)
		}
		if gotPath != "/v1/chat/completions" {
			t.Errorf("期望 path=/v1/chat/completions, 实际 %s", gotPath)
		}
	})

	t.Run("Anthropic route enters proxy handler wrapper", func(t *testing.T) {
		gotProtocol = ""
		gotPath = ""

		req := httptest.NewRequest("POST", "/anthropic/v1/messages", nil)
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		if w.Code != http.StatusOK {
			t.Errorf("期望状态码 200, 实际 %d", w.Code)
		}
		if gotProtocol != "anthropic" {
			t.Errorf("期望 protocol=anthropic, 实际 %s", gotProtocol)
		}
		if gotPath != "/v1/messages" {
			t.Errorf("期望 path=/v1/messages, 实际 %s", gotPath)
		}
	})

	t.Run("Static assets are not hijacked", func(t *testing.T) {
		gotProtocol = ""
		gotPath = ""

		req := httptest.NewRequest("GET", "/assets/test.js", nil)
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		if gotProtocol != "" || gotPath != "" {
			t.Errorf("静态资源不应进入代理包装器，实际 protocol=%s path=%s", gotProtocol, gotPath)
		}
		if w.Code == http.StatusOK {
			if !strings.HasPrefix(w.Header().Get("Content-Type"), "application/javascript") {
				t.Errorf("期望 JS Content-Type, 实际 %s", w.Header().Get("Content-Type"))
			}
			return
		}
		if w.Code != http.StatusNotFound {
			t.Errorf("期望静态资源返回 200 或 404, 实际 %d", w.Code)
		}
	})

	t.Run("SPA path keeps fallback", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/providers", nil)
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		if w.Code != http.StatusOK {
			t.Errorf("期望状态码 200, 实际 %d", w.Code)
		}
		if !strings.Contains(w.Header().Get("Content-Type"), "text/html") {
			t.Errorf("期望返回 HTML，实际 %s", w.Header().Get("Content-Type"))
		}
	})

	t.Run("Unknown proxy-like path does not return index html", func(t *testing.T) {
		req := httptest.NewRequest("GET", "/openai/unknown", nil)
		w := httptest.NewRecorder()
		r.ServeHTTP(w, req)

		if w.Code != http.StatusOK {
			t.Errorf("显式代理路由应进入代理包装器，实际状态码 %d", w.Code)
		}
		if gotProtocol != "openai" || gotPath != "/unknown" {
			t.Errorf("期望 unknown 代理路径进入 openai 包装器，实际 protocol=%s path=%s", gotProtocol, gotPath)
		}
	})
}
