package middleware

import (
	"log/slog"
	"net/http"
	"strconv"
	"strings"

	"github.com/edu-cloud/api-gateway/internal/config"
	"github.com/gin-gonic/gin"
)

// corsMaxAge 预检缓存时长：12 小时
const corsMaxAge = 12 * 60 * 60

// devCORSOrigins 是未配置 CORS_ORIGINS 时的开发环境默认白名单
const devCORSOrigins = "http://localhost:3000,http://localhost:3001"

// CORS 返回跨域资源共享中间件（从 Config 读取白名单，W3 裁决：slog 结构化日志）。
// 允许来源从 cfg.CORSOrigins 读取（逗号分隔）；
// 未配置时使用开发环境白名单（localhost:3000/3001）并打印 warning。
// 允许方法：GET POST PUT DELETE OPTIONS PATCH
// 允许头：Authorization Content-Type X-Request-Id X-Trace-Id
// 暴露头：X-Request-Id X-Trace-Id
func CORS(cfg *config.Config) gin.HandlerFunc {
	allowed := parseCORSOrigins(cfg.CORSOrigins)
	if len(allowed) == 0 {
		slog.Warn("CORS_ORIGINS not set, using dev default whitelist")
		allowed = parseCORSOrigins(devCORSOrigins)
	}

	return func(c *gin.Context) {
		origin := c.GetHeader("Origin")
		allowOrigin := ""
		if allowed[origin] {
			allowOrigin = origin
		}

		if allowOrigin != "" {
			h := c.Writer.Header()
			h.Set("Access-Control-Allow-Origin", allowOrigin)
			h.Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, PATCH")
			h.Set("Access-Control-Allow-Headers", "Authorization, Content-Type, X-Request-Id, X-Trace-Id")
			h.Set("Access-Control-Expose-Headers", "X-Request-Id, X-Trace-Id")
			h.Set("Access-Control-Max-Age", strconv.Itoa(corsMaxAge))
			// 非通配来源需标注 Vary，便于缓存正确区分
			h.Add("Vary", "Origin")
		}

		// 预检请求直接返回 204
		if c.Request.Method == http.MethodOptions {
			c.AbortWithStatus(http.StatusNoContent)
			return
		}
		c.Next()
	}
}

// parseCORSOrigins 解析逗号分隔的来源列表为集合，空字符串返回空 map
func parseCORSOrigins(raw string) map[string]bool {
	allowed := map[string]bool{}
	if raw == "" {
		return allowed
	}
	for _, o := range strings.Split(raw, ",") {
		o = strings.TrimSpace(o)
		if o != "" {
			allowed[o] = true
		}
	}
	return allowed
}
