package httpx

import (
	"net/http"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"senlinai-agent/backend/internal/config"
	"senlinai-agent/backend/internal/logic/auth"
)

type RouteRegistrar interface {
	Register(router gin.IRouter)
}

// NewRouter 创建仅暴露 /api/v1 业务契约的公开路由。
func NewRouter(cfg config.Config, registrars ...RouteRegistrar) *gin.Engine {
	return newRouter(cfg, nil, registrars...)
}

// NewProtectedRouter 为 /api/v1 业务路由启用签名 session 校验。
func NewProtectedRouter(cfg config.Config, tokenVerifier func(string) (uint, error), registrars ...RouteRegistrar) *gin.Engine {
	return newRouter(cfg, tokenVerifier, registrars...)
}

func newRouter(cfg config.Config, tokenVerifier func(string) (uint, error), registrars ...RouteRegistrar) *gin.Engine {
	if cfg.Env == "test" {
		gin.SetMode(gin.TestMode)
	}

	router := gin.New()
	router.Use(gin.Recovery())
	router.Use(cors(cfg))

	router.GET("/healthz", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"status": "ok"})
	})
	api := router.Group("/api/v1")
	api.GET("/status", func(c *gin.Context) {
		c.JSON(http.StatusOK, gin.H{"timestamp": time.Now().UTC().Format(time.RFC3339Nano)})
	})
	if tokenVerifier != nil {
		api.Use(auth.RequireUser(tokenVerifier))
	}
	for _, registrar := range registrars {
		registrar.Register(api)
	}

	return router
}

func cors(cfg config.Config) gin.HandlerFunc {
	origins := cfg.AllowedOrigins
	if len(origins) == 0 && (cfg.Env == "development" || cfg.Env == "dev" || cfg.Env == "test") {
		origins = []string{
			"http://localhost:5173",
			"http://127.0.0.1:5173",
			"http://tauri.localhost",
		}
	}

	// 非开发环境在未配置来源时默认拒绝跨域，防止意外开放浏览器访问。
	allowedOrigins := make(map[string]struct{}, len(origins))
	for _, origin := range origins {
		if origin = strings.TrimSpace(origin); origin != "" {
			allowedOrigins[origin] = struct{}{}
		}
	}

	return func(c *gin.Context) {
		origin := c.GetHeader("Origin")
		if _, ok := allowedOrigins[origin]; ok {
			c.Header("Access-Control-Allow-Origin", origin)
			c.Header("Vary", "Origin")
			c.Header("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE, OPTIONS")
			c.Header("Access-Control-Allow-Headers", "Authorization, Content-Type")
			c.Header("Access-Control-Max-Age", "86400")
		}

		if c.Request.Method == http.MethodOptions {
			c.AbortWithStatus(http.StatusNoContent)
			return
		}

		c.Next()
	}
}
