package httpx

import (
	"net/http"
	"time"

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

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

func NewRouter(cfg config.Config, registrars ...RouteRegistrar) *gin.Engine {
	return newRouter(cfg, nil, registrars...)
}

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())

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

	return router
}

func cors() gin.HandlerFunc {
	allowedOrigins := map[string]bool{
		"http://localhost:5173":  true,
		"http://127.0.0.1:5173":  true,
		"http://localhost:4173":  true,
		"http://127.0.0.1:4173":  true,
		"http://localhost:4174":  true,
		"http://127.0.0.1:4174":  true,
		"http://localhost:4175":  true,
		"http://127.0.0.1:4175":  true,
		"http://tauri.localhost": true,
	}

	return func(c *gin.Context) {
		origin := c.GetHeader("Origin")
		if allowedOrigins[origin] {
			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()
	}
}
