package server

import (
	"fmt"
	"net/http"
	"path/filepath"
	"time"

	"agent/internal/agent"

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

// NewRouter 组装全部路由：静态资源、会话直达、/api/v1 REST、/ws WebSocket。
// 返回 (gin.Engine, *Server)：*Server 供 main.go 在托管模式下调用 StartBenchmark 自动触发评测。
func NewRouter(cfg agent.Config, store *agent.SessionStore, dockerCfg *agent.DockerConfigStore, apiCfg *agent.APIConfigStore) (*gin.Engine, *Server) {
	s := &Server{
		cfg:       cfg,
		store:     store,
		agent:     agent.NewAgent(cfg, store, dockerCfg, apiCfg),
		dockerCfg: dockerCfg,
		apiCfg:    apiCfg,
	}

	gin.SetMode(gin.ReleaseMode)
	r := gin.New()
	r.Use(gin.Recovery(), requestLogger())

	staticDir := filepath.Join(cfg.Workspace, "web", "static")
	indexFile := filepath.Join(staticDir, "index.html")
	r.Static("/static", staticDir)
	r.StaticFile("/", indexFile)

	// 会话直达：/<sessionId> 返回前端页面，由前端 JS 从路径解析会话 ID
	r.GET("/:sessionId", func(c *gin.Context) {
		if !sessionIDPattern.MatchString(c.Param("sessionId")) {
			c.Status(http.StatusNotFound)
			return
		}
		c.File(indexFile)
	})

	v1 := r.Group("/api/v1")
	v1.GET("/health", s.health)
	// 授权相关接口始终放行：前端据此判断是否需要授权 / 提交授权码。
	// 其余 API 与 WebSocket 统一挂 authRequired（未启用授权时自动放行）。
	auth := v1.Group("/auth")
	auth.GET("/status", s.authStatus)
	auth.POST("/login", s.authLogin)

	authed := v1.Group("")
	authed.Use(s.authRequired)
	authed.GET("/config", s.config)
	authed.GET("/docker/config", s.dockerConfig)
	authed.PUT("/docker/config", s.setDockerConfig)
	authed.GET("/llm/config", s.llmConfig)
	authed.PUT("/llm/config", s.setLLMConfig)
	authed.GET("/sessions", s.listSessions)
	authed.POST("/sessions", s.createSession)
	authed.GET("/sessions/:id", s.getSession)
	authed.GET("/sessions/:id/messages", s.sessionMessages)
	authed.DELETE("/sessions/:id", s.deleteSession)
	authed.DELETE("/sessions/:id/messages", s.clearSession)
	authed.GET("/coop/tasks", s.coopTasks)

	// WebSocket 实时通道：Agent 流式输出 / 状态 / 协作通知（同样受授权保护）
	r.GET("/ws", s.authRequired, s.ws)

	return r, s
}

// requestLogger 轻量请求日志中间件：统一 [http] 前缀，便于与 [coop] 等日志区分。
func requestLogger() gin.HandlerFunc {
	return func(c *gin.Context) {
		start := time.Now()
		c.Next()
		gin.DefaultWriter.Write([]byte(fmt.Sprintf(
			"[http] %s | %s %s | %s | %d\n",
			time.Now().Format("2006/01/02 15:04:05"),
			c.Request.Method,
			c.Request.URL.Path,
			time.Since(start).Round(time.Millisecond).String(),
			c.Writer.Status(),
		)))
	}
}
