package handler

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	coremodel "security-center-backend/internal/model"
	caasmmodel "security-center-backend/internal/modules/caasm/model"
	"security-center-backend/internal/modules/caasm/repository"
)

func TestToCaasmThrottlingContractDTOIncludesLargeAccountPreset(t *testing.T) {
	contract := toCaasmThrottlingContractDTO()

	require.NotNil(t, contract.Presets)
	preset, ok := contract.Presets["large_aws_account_safe"]
	require.True(t, ok)
	assert.Equal(t, "Large AWS account (Safest)", preset.Label)
	assert.Contains(t, preset.Description, "large AWS accounts")
	assert.Equal(t, 6, preset.Config.TokenCapacity)
	assert.Equal(t, 2.0, preset.Config.TokenRefillPerSec)
	assert.Equal(t, 2, preset.Config.MaxConcurrency)
	assert.Equal(t, 1, preset.Config.MinConcurrency)
	if assert.NotNil(t, preset.Config.CircuitBreaker) {
		assert.Equal(t, 4, preset.Config.CircuitBreaker.Threshold)
		assert.Equal(t, 180, preset.Config.CircuitBreaker.CoolOffSec)
	}
	require.Contains(t, preset.Config.ServiceLimits, "route53")
	assert.Equal(t, 1, preset.Config.ServiceLimits["route53"].MaxConcurrency)
	assert.Equal(t, 20, contract.Defaults.TokenCapacity)
	assert.Equal(t, float64(caasmmodel.DefaultThrottleTokenRefillPerSec), contract.Defaults.TokenRefillPerSec)
}

func TestToCaasmAssetListItemDTOIncludesIPAddresses(t *testing.T) {
	dto := toCaasmAssetListItemDTO(caasmmodel.Asset{
		NativeID: "i-0123456789abcdef0",
		IPAssets: []caasmmodel.IPAsset{
			{IPAddress: " 203.0.113.10 "},
			{IPAddress: ""},
			{IPAddress: "203.0.113.10"},
			{IPAddress: "10.0.0.5"},
		},
	})

	assert.Equal(t, "i-0123456789abcdef0", dto.NativeID)
	assert.Equal(t, []string{"203.0.113.10", "10.0.0.5"}, dto.IPAddresses)
}

func TestToCaasmPortListItemDTOAddsEndpointContract(t *testing.T) {
	tests := []struct {
		name             string
		ipAddress        string
		wantIPAddress    string
		wantEndpointType string
	}{
		{name: "ipv4", ipAddress: "10.0.0.1", wantIPAddress: "10.0.0.1", wantEndpointType: "ip"},
		{name: "ipv6", ipAddress: "2001:db8::10", wantIPAddress: "2001:db8::10", wantEndpointType: "ip"},
		{name: "hostname", ipAddress: "internal-web.example.com", wantIPAddress: "", wantEndpointType: "hostname"},
		{name: "empty", ipAddress: "", wantIPAddress: "", wantEndpointType: ""},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			dto := toCaasmPortListItemDTO(caasmmodel.IPPortIndex{
				IPAddress: tt.ipAddress,
			})

			assert.Equal(t, tt.wantIPAddress, dto.IPAddress)
			assert.Equal(t, tt.ipAddress, dto.Endpoint)
			assert.Equal(t, tt.wantEndpointType, dto.EndpointType)
		})
	}
}

func TestToCaasmPortDetailDTOExposesPartialEvidenceHonestly(t *testing.T) {
	detail := &repository.PortDetail{
		Port: caasmmodel.IPPortIndex{
			AssetID:           1,
			Asset:             caasmmodel.Asset{Metadata: coremodel.JSONB{"security_groups": []interface{}{"sg-1", "sg-2"}}},
			IPAddress:         "203.0.113.10",
			Port:              443,
			Protocol:          "tcp",
			ObservationSource: caasmmodel.PortObservationSourceSecurityGroup,
			Exposure:          "public",
			Status:            "open",
		},
	}

	dto := toCaasmPortDetailDTO(detail)

	assert.Equal(t, "Security group rule inferred this endpoint and port as open.", dto.Evidence.ExposureReason)
	assert.True(t, dto.Evidence.SecurityGroup.Available)
	assert.Contains(t, dto.Evidence.SecurityGroup.Summary, "Exact rule CIDR/source detail is not persisted yet")
	assert.Equal(t, []string{"sg-1", "sg-2"}, dto.Evidence.SecurityGroup.Metadata["security_groups"])
	assert.False(t, dto.Evidence.Route.Available)
	assert.Contains(t, dto.Evidence.Route.Summary, "not collected")
	assert.Nil(t, dto.Evidence.ScannerResult)
	require.NotEmpty(t, dto.Evidence.Warnings)
}
