package handlers

import (
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"github.com/gin-gonic/gin"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/Wikid82/charon/backend/internal/config"
	"github.com/Wikid82/charon/backend/internal/models"
)

// TestSecurityHandler_Priority_SettingsOverSecurityConfig verifies the three-tier priority system:
// 1. Settings table (highest)
// 2. SecurityConfig DB (middle)
// 3. Static config (lowest)
func TestSecurityHandler_Priority_SettingsOverSecurityConfig(t *testing.T) {
	gin.SetMode(gin.TestMode)

	tests := []struct {
		name              string
		staticCfg         config.SecurityConfig
		dbSecurityConfig  *models.SecurityConfig
		settings          []models.Setting
		expectedWAFMode   string
		expectedWAFEnable bool
	}{
		{
			name: "Settings table overrides SecurityConfig DB",
			staticCfg: config.SecurityConfig{
				CerberusEnabled: true,
				WAFMode:         "disabled",
			},
			dbSecurityConfig: &models.SecurityConfig{
				Name:    "default",
				Enabled: true,
				WAFMode: "enabled",
			},
			settings: []models.Setting{
				{Key: "security.waf.enabled", Value: "false"},
			},
			expectedWAFMode:   "disabled",
			expectedWAFEnable: false,
		},
		{
			name: "SecurityConfig DB overrides static config",
			staticCfg: config.SecurityConfig{
				CerberusEnabled: true,
				WAFMode:         "disabled",
			},
			dbSecurityConfig: &models.SecurityConfig{
				Name:    "default",
				Enabled: true,
				WAFMode: "enabled",
			},
			settings:          []models.Setting{}, // No settings override
			expectedWAFMode:   "enabled",
			expectedWAFEnable: true,
		},
		{
			name: "Static config used when no DB overrides",
			staticCfg: config.SecurityConfig{
				CerberusEnabled: true,
				WAFMode:         "enabled",
			},
			dbSecurityConfig:  nil, // No DB config
			settings:          []models.Setting{},
			expectedWAFMode:   "enabled",
			expectedWAFEnable: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			db := setupTestDB(t)
			require.NoError(t, db.AutoMigrate(&models.Setting{}, &models.SecurityConfig{}))

			// Insert DB SecurityConfig if provided
			if tt.dbSecurityConfig != nil {
				require.NoError(t, db.Create(tt.dbSecurityConfig).Error)
			}

			// Insert settings
			for _, s := range tt.settings {
				require.NoError(t, db.Create(&s).Error)
			}

			handler := NewSecurityHandler(tt.staticCfg, db, nil)
			router := gin.New()
			router.GET("/security/status", handler.GetStatus)

			w := httptest.NewRecorder()
			req, _ := http.NewRequest("GET", "/security/status", http.NoBody)
			router.ServeHTTP(w, req)

			assert.Equal(t, http.StatusOK, w.Code)

			var response map[string]interface{}
			err := json.Unmarshal(w.Body.Bytes(), &response)
			require.NoError(t, err)

			waf := response["waf"].(map[string]interface{})
			assert.Equal(t, tt.expectedWAFMode, waf["mode"].(string), "WAF mode mismatch")
			assert.Equal(t, tt.expectedWAFEnable, waf["enabled"].(bool), "WAF enabled mismatch")
		})
	}
}

// TestSecurityHandler_Priority_AllModules verifies priority system works for all security modules
func TestSecurityHandler_Priority_AllModules(t *testing.T) {
	gin.SetMode(gin.TestMode)
	db := setupTestDB(t)
	require.NoError(t, db.AutoMigrate(&models.Setting{}, &models.SecurityConfig{}))

	// Static config has everything disabled
	staticCfg := config.SecurityConfig{
		CerberusEnabled: true,
		WAFMode:         "disabled",
		RateLimitMode:   "disabled",
		CrowdSecMode:    "disabled",
		ACLMode:         "disabled",
	}

	// DB SecurityConfig enables everything
	dbSecurityConfig := models.SecurityConfig{
		Name:          "default",
		Enabled:       true,
		WAFMode:       "enabled",
		RateLimitMode: "enabled",
		CrowdSecMode:  "local",
	}
	require.NoError(t, db.Create(&dbSecurityConfig).Error)

	// Settings table selectively overrides (WAF and ACL enabled, Rate Limit disabled)
	settings := []models.Setting{
		{Key: "security.waf.enabled", Value: "true"},
		{Key: "security.rate_limit.enabled", Value: "false"},
		{Key: "security.crowdsec.mode", Value: "disabled"},
		{Key: "security.acl.enabled", Value: "true"},
	}
	for _, s := range settings {
		require.NoError(t, db.Create(&s).Error)
	}

	handler := NewSecurityHandler(staticCfg, db, nil)
	router := gin.New()
	router.GET("/security/status", handler.GetStatus)

	w := httptest.NewRecorder()
	req, _ := http.NewRequest("GET", "/security/status", http.NoBody)
	router.ServeHTTP(w, req)

	assert.Equal(t, http.StatusOK, w.Code)

	var response map[string]interface{}
	err := json.Unmarshal(w.Body.Bytes(), &response)
	require.NoError(t, err)

	// Verify Settings table took precedence
	waf := response["waf"].(map[string]interface{})
	assert.True(t, waf["enabled"].(bool), "WAF should be enabled via settings")

	rateLimit := response["rate_limit"].(map[string]interface{})
	assert.False(t, rateLimit["enabled"].(bool), "Rate Limit should be disabled via settings")

	crowdsec := response["crowdsec"].(map[string]interface{})
	assert.Equal(t, "disabled", crowdsec["mode"].(string), "CrowdSec should be disabled via settings")
	assert.False(t, crowdsec["enabled"].(bool))

	acl := response["acl"].(map[string]interface{})
	assert.True(t, acl["enabled"].(bool), "ACL should be enabled via settings")
}
