package middleware

import (
	"crypto/rand"
	"encoding/base64"

	"metazone.cc/metalab/internal/config"

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

// generateNonce 生成 16 字节随机 nonce（base64 编码）
func generateNonce() string {
	b := make([]byte, 16)
	if _, err := rand.Read(b); err != nil {
		// 降级：使用固定长度回退（极度罕见，仅 /dev/urandom 故障时）
		panic("failed to generate CSP nonce: " + err.Error())
	}
	return base64.StdEncoding.EncodeToString(b)
}

// SecurityHeaders 添加安全相关 HTTP 响应头
// 作为纵深防御，不影响业务逻辑，纯附加
func SecurityHeaders() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 生成一次性 nonce，用于 CSP 策略和模板内 <script>/<style> 标签
		nonce := generateNonce()
		c.Set("csp_nonce", nonce)

		// Content-Security-Policy
		// script-src/style-src: 本站 + nonce（替代 unsafe-inline）
		// img-src: 本站 + data: URI（头像裁切）+ blob:（粘贴图片）
		c.Header("Content-Security-Policy",
			"default-src 'self'; "+
				"script-src 'self' 'unsafe-inline' 'unsafe-eval'; "+
				"style-src 'self' 'unsafe-inline'; "+
				"img-src 'self' data: blob:; "+
				"connect-src 'self'")

		// 禁止 MIME 类型嗅探
		c.Header("X-Content-Type-Options", "nosniff")

		// 禁止被 frame 嵌入（防点击劫持）
		c.Header("X-Frame-Options", "DENY")

		// 引用策略
		c.Header("Referrer-Policy", "strict-origin-when-cross-origin")

		// HSTS：仅在 release 模式启用，避免开发环境 localhost 证书问题
		if config.App != nil && config.App.Server.Mode == "release" {
			c.Header("Strict-Transport-Security", "max-age=31536000; includeSubDomains; preload")
		}

		c.Next()
	}
}
