package middleware

import (
	"os"
	"strconv"
	"strings"

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

// SecurityHeadersConfig holds configuration for security headers.
type SecurityHeadersConfig struct {
	// X-Content-Type-Options
	ContentTypeOptions string

	// X-Frame-Options
	FrameOptions string

	// X-XSS-Protection (legacy but useful for older browsers)
	XSSProtection string

	// Strict-Transport-Security
	HSTSEnabled           bool
	HSTSMaxAge            int
	HSTSIncludeSubdomains bool
	HSTSPreload           bool

	// Content-Security-Policy
	CSPEnabled bool
	CSPPolicy  string

	// Referrer-Policy
	ReferrerPolicy string

	// Permissions-Policy
	PermissionsPolicy string

	// Cross-Origin headers
	CrossOriginOpenerPolicy   string
	CrossOriginResourcePolicy string

	// Development mode (relaxes some restrictions)
	DevelopmentMode bool

	// Excluded paths (e.g., health checks)
	ExcludedPaths []string
}

// DefaultSecurityHeadersConfig returns sensible default configuration.
func DefaultSecurityHeadersConfig() SecurityHeadersConfig {
	env := os.Getenv("ENVIRONMENT")
	isDev := env == "" || strings.ToLower(env) == "development" || strings.ToLower(env) == "dev"

	return SecurityHeadersConfig{
		ContentTypeOptions:        "nosniff",
		FrameOptions:              "DENY",
		XSSProtection:             "1; mode=block",
		HSTSEnabled:               true,
		HSTSMaxAge:                31536000, // 1 year
		HSTSIncludeSubdomains:     true,
		HSTSPreload:               false,
		CSPEnabled:                true,
		CSPPolicy:                 getDefaultCSP(isDev),
		ReferrerPolicy:            "strict-origin-when-cross-origin",
		PermissionsPolicy:         "geolocation=(), microphone=(), camera=()",
		CrossOriginOpenerPolicy:   "same-origin",
		CrossOriginResourcePolicy: "same-origin",
		DevelopmentMode:           isDev,
		ExcludedPaths:             []string{"/health", "/metrics", "/api/v1/health"},
	}
}

// getDefaultCSP returns a sensible default CSP for the environment.
func getDefaultCSP(isDevelopment bool) string {
	if isDevelopment {
		return "default-src 'self' localhost:* ws://localhost:*; " +
			"script-src 'self' 'unsafe-inline' 'unsafe-eval'; " +
			"style-src 'self' 'unsafe-inline'; " +
			"img-src 'self' data: https: blob:; " +
			"font-src 'self' data:; " +
			"connect-src 'self' localhost:* ws://localhost:* https:; " +
			"frame-ancestors 'self'"
	}
	return "default-src 'self'; " +
		"script-src 'self' 'unsafe-inline'; " +
		"style-src 'self' 'unsafe-inline'; " +
		"img-src 'self' data: https:; " +
		"font-src 'self' data:; " +
		"connect-src 'self' https://breakpilot.app https://*.breakpilot.app; " +
		"frame-ancestors 'none'"
}

// buildHSTSHeader builds the Strict-Transport-Security header value.
func (c *SecurityHeadersConfig) buildHSTSHeader() string {
	parts := []string{"max-age=" + strconv.Itoa(c.HSTSMaxAge)}
	if c.HSTSIncludeSubdomains {
		parts = append(parts, "includeSubDomains")
	}
	if c.HSTSPreload {
		parts = append(parts, "preload")
	}
	return strings.Join(parts, "; ")
}

// isExcludedPath checks if the path should be excluded from security headers.
func (c *SecurityHeadersConfig) isExcludedPath(path string) bool {
	for _, excluded := range c.ExcludedPaths {
		if path == excluded {
			return true
		}
	}
	return false
}

// SecurityHeaders returns a middleware that adds security headers to all responses.
//
// Usage:
//
//	r.Use(middleware.SecurityHeaders())
//
//	// Or with custom config:
//	config := middleware.DefaultSecurityHeadersConfig()
//	config.CSPPolicy = "default-src 'self'"
//	r.Use(middleware.SecurityHeadersWithConfig(config))
func SecurityHeaders() gin.HandlerFunc {
	return SecurityHeadersWithConfig(DefaultSecurityHeadersConfig())
}

// SecurityHeadersWithConfig returns a security headers middleware with custom configuration.
func SecurityHeadersWithConfig(config SecurityHeadersConfig) gin.HandlerFunc {
	return func(c *gin.Context) {
		// Skip for excluded paths
		if config.isExcludedPath(c.Request.URL.Path) {
			c.Next()
			return
		}

		// Always add these headers
		c.Header("X-Content-Type-Options", config.ContentTypeOptions)
		c.Header("X-Frame-Options", config.FrameOptions)
		c.Header("X-XSS-Protection", config.XSSProtection)
		c.Header("Referrer-Policy", config.ReferrerPolicy)

		// HSTS (only in production or if explicitly enabled)
		if config.HSTSEnabled && !config.DevelopmentMode {
			c.Header("Strict-Transport-Security", config.buildHSTSHeader())
		}

		// Content-Security-Policy
		if config.CSPEnabled && config.CSPPolicy != "" {
			c.Header("Content-Security-Policy", config.CSPPolicy)
		}

		// Permissions-Policy
		if config.PermissionsPolicy != "" {
			c.Header("Permissions-Policy", config.PermissionsPolicy)
		}

		// Cross-Origin headers (only in production)
		if !config.DevelopmentMode {
			c.Header("Cross-Origin-Opener-Policy", config.CrossOriginOpenerPolicy)
			c.Header("Cross-Origin-Resource-Policy", config.CrossOriginResourcePolicy)
		}

		c.Next()
	}
}
