package caddy

import (
	"encoding/json"
	"testing"

	"github.com/Wikid82/charon/backend/internal/models"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestBuildCrowdSecHandler_Disabled(t *testing.T) {
	// When crowdsecEnabled is false, should return nil
	h, err := buildCrowdSecHandler(nil, nil, false)
	require.NoError(t, err)
	assert.Nil(t, h)
}

func TestBuildCrowdSecHandler_EnabledWithoutConfig(t *testing.T) {
	// When crowdsecEnabled is true but no secCfg, should use default localhost URL
	// Default port is 8085 to avoid conflict with Charon management API on port 8080
	h, err := buildCrowdSecHandler(nil, nil, true)
	require.NoError(t, err)
	require.NotNil(t, h)

	assert.Equal(t, "crowdsec", h["handler"])
	assert.Equal(t, "http://127.0.0.1:8085", h["api_url"])
}

func TestBuildCrowdSecHandler_EnabledWithEmptyAPIURL(t *testing.T) {
	// When crowdsecEnabled is true but CrowdSecAPIURL is empty, should use default
	// Default port is 8085 to avoid conflict with Charon management API on port 8080
	secCfg := &models.SecurityConfig{
		CrowdSecAPIURL: "",
	}
	h, err := buildCrowdSecHandler(nil, secCfg, true)
	require.NoError(t, err)
	require.NotNil(t, h)

	assert.Equal(t, "crowdsec", h["handler"])
	assert.Equal(t, "http://127.0.0.1:8085", h["api_url"])
}

func TestBuildCrowdSecHandler_EnabledWithCustomAPIURL(t *testing.T) {
	// When crowdsecEnabled is true and CrowdSecAPIURL is set, should use custom URL
	secCfg := &models.SecurityConfig{
		CrowdSecAPIURL: "http://crowdsec-lapi:8081",
	}
	h, err := buildCrowdSecHandler(nil, secCfg, true)
	require.NoError(t, err)
	require.NotNil(t, h)

	assert.Equal(t, "crowdsec", h["handler"])
	assert.Equal(t, "http://crowdsec-lapi:8081", h["api_url"])
}

func TestBuildCrowdSecHandler_JSONFormat(t *testing.T) {
	// Test that the handler produces valid JSON matching caddy-crowdsec-bouncer schema
	secCfg := &models.SecurityConfig{
		CrowdSecAPIURL: "http://localhost:8080",
	}
	h, err := buildCrowdSecHandler(nil, secCfg, true)
	require.NoError(t, err)
	require.NotNil(t, h)

	// Marshal to JSON and verify structure
	b, err := json.Marshal(h)
	require.NoError(t, err)
	s := string(b)

	// Verify expected JSON content
	assert.Contains(t, s, `"handler":"crowdsec"`)
	assert.Contains(t, s, `"api_url":"http://localhost:8080"`)
	// Should NOT contain old "mode" field
	assert.NotContains(t, s, `"mode"`)
}

func TestBuildCrowdSecHandler_WithHost(t *testing.T) {
	// Test that host parameter is accepted (even if not currently used)
	host := &models.ProxyHost{
		UUID:        "test-uuid",
		DomainNames: "example.com",
	}
	secCfg := &models.SecurityConfig{
		CrowdSecAPIURL: "http://custom-crowdsec:8080",
	}

	h, err := buildCrowdSecHandler(host, secCfg, true)
	require.NoError(t, err)
	require.NotNil(t, h)

	assert.Equal(t, "crowdsec", h["handler"])
	assert.Equal(t, "http://custom-crowdsec:8080", h["api_url"])
}

func TestGenerateConfig_WithCrowdSec(t *testing.T) {
	// Test that CrowdSec handler is included in generated config when enabled
	hosts := []models.ProxyHost{
		{
			UUID:        "test-uuid",
			DomainNames: "example.com",
			ForwardHost: "app",
			ForwardPort: 8080,
			Enabled:     true,
		},
	}

	secCfg := &models.SecurityConfig{
		CrowdSecMode:   "local",
		CrowdSecAPIURL: "http://localhost:8080",
	}

	// crowdsecEnabled=true should include the handler
	config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "", "", false, true, false, false, false, "", nil, nil, nil, secCfg)
	require.NoError(t, err)
	require.NotNil(t, config.Apps.HTTP)

	server := config.Apps.HTTP.Servers["charon_server"]
	require.NotNil(t, server)
	require.Len(t, server.Routes, 1)

	route := server.Routes[0]
	// Handlers should include crowdsec + reverse_proxy
	require.GreaterOrEqual(t, len(route.Handle), 2)

	// Find the crowdsec handler
	var foundCrowdSec bool
	for _, h := range route.Handle {
		if h["handler"] == "crowdsec" {
			foundCrowdSec = true
			// Verify it has api_url
			assert.Equal(t, "http://localhost:8080", h["api_url"])
			break
		}
	}
	require.True(t, foundCrowdSec, "crowdsec handler should be present")
}

func TestGenerateConfig_CrowdSecDisabled(t *testing.T) {
	// Test that CrowdSec handler is NOT included when disabled
	hosts := []models.ProxyHost{
		{
			UUID:        "test-uuid",
			DomainNames: "example.com",
			ForwardHost: "app",
			ForwardPort: 8080,
			Enabled:     true,
		},
	}

	// crowdsecEnabled=false should NOT include the handler
	config, err := GenerateConfig(hosts, "/tmp/caddy-data", "admin@example.com", "", "", false, false, false, false, false, "", nil, nil, nil, nil)
	require.NoError(t, err)
	require.NotNil(t, config.Apps.HTTP)

	server := config.Apps.HTTP.Servers["charon_server"]
	require.NotNil(t, server)
	require.Len(t, server.Routes, 1)

	route := server.Routes[0]

	// Verify no crowdsec handler
	for _, h := range route.Handle {
		assert.NotEqual(t, "crowdsec", h["handler"], "crowdsec handler should not be present when disabled")
	}
}
