package caasmmodel

import (
	"maps"

	coremodel "security-center-backend/internal/model"
)

// Config holds CAASM configuration stored as JSON.
type Config struct {
	coremodel.Base
	Data coremodel.JSONB `gorm:"type:json" json:"data"`
}

// ConfigData represents the structure of the config JSON data.
type ConfigData struct {
	TaggingRules         []TaggingRule         `json:"tagging_rules,omitempty"`
	DiscoveryIntervals   *DiscoveryIntervals   `json:"discovery_intervals,omitempty"`
	PortCatalog          *PortCatalog          `json:"port_catalog,omitempty"`
	EphemeralAssetPolicy *EphemeralAssetPolicy `json:"ephemeral_asset_policy,omitempty"`
	CollectionScope      *CollectionScope      `json:"collection_scope,omitempty"`
	Throttling           *ThrottlingConfig     `json:"throttling,omitempty"`
	SyncSettings         *SyncSettings         `json:"sync_settings,omitempty"`
}

// SyncSettings controls the data collection mode.
type SyncSettings struct {
	Mode                    string `json:"mode"`                                // "queue" or "serverless"
	LambdaFunctionName      string `json:"lambda_function_name,omitempty"`      // optional label for the serverless worker path
	KillSwitchEnabled       bool   `json:"kill_switch_enabled,omitempty"`       // global emergency stop for new collector execution
	ExecutionTimeoutMinutes int    `json:"execution_timeout_minutes,omitempty"` // actual execution timeout for sync jobs
	RunningTimeoutMinutes   int    `json:"running_timeout_minutes,omitempty"`   // zombie reaper timeout for running jobs
	QueuedTimeoutMinutes    int    `json:"queued_timeout_minutes,omitempty"`    // zombie reaper timeout for queued jobs
}

const (
	DefaultSyncJobExecutionTimeoutMinutes = 30
	DefaultSyncJobRunningTimeoutMinutes   = 60
	DefaultSyncJobQueuedTimeoutMinutes    = 30
)

type CollectionScopeMode string

const (
	CollectionScopeAll        CollectionScopeMode = "all"
	CollectionScopePublicOnly CollectionScopeMode = "public_only"
)

type CollectionScope struct {
	IPCollectionScope     CollectionScopeMode `json:"ip_collection_scope,omitempty"`
	PortCollectionScope   CollectionScopeMode `json:"port_collection_scope,omitempty"`
	DomainCollectionScope CollectionScopeMode `json:"domain_collection_scope,omitempty"`
}

const (
	DefaultThrottleTokenCapacity     = 20
	DefaultThrottleTokenRefillPerSec = 10
	DefaultThrottleAdaptiveThreshold = 3
	DefaultThrottleAdaptiveWindowSec = 60
	DefaultThrottleCoolOffSec        = 30
	DefaultThrottleMaxConcurrency    = 5
	DefaultThrottleMinConcurrency    = 2

	HardCapThrottleTokenCapacity     = 100
	HardCapThrottleTokenRefillPerSec = 50
	HardCapThrottleAdaptiveThreshold = 20
	HardCapThrottleAdaptiveWindowSec = 900
	HardCapThrottleCoolOffSec        = 900
	HardCapThrottleMaxConcurrency    = 10
	HardCapThrottleMinConcurrency    = 10
)

// ThrottlingConfig defines global throttling defaults for collectors.
type ThrottlingConfig struct {
	Enabled           bool                             `json:"enabled"`
	TokenCapacity     int                              `json:"token_capacity,omitempty"`       // default tokens per bucket
	TokenRefillPerSec float64                          `json:"token_refill_per_sec,omitempty"` // refill rate
	AdaptiveThreshold int                              `json:"adaptive_threshold,omitempty"`   // throttle events to trigger drop
	AdaptiveWindowSec int                              `json:"adaptive_window_sec,omitempty"`  // rolling window seconds
	CoolOffSec        int                              `json:"cool_off_sec,omitempty"`         // cool-off duration seconds
	MaxConcurrency    int                              `json:"max_concurrency,omitempty"`      // default per-region concurrency
	MinConcurrency    int                              `json:"min_concurrency,omitempty"`      // floor when throttled
	CircuitBreaker    *CircuitBreakerConfig            `json:"circuit_breaker,omitempty"`
	ServiceLimits     map[string]ThrottlingServiceSpec `json:"service_limits,omitempty"`
}

type CircuitBreakerConfig struct {
	Threshold  int `json:"threshold,omitempty"`
	CoolOffSec int `json:"cool_off_sec,omitempty"`
}

type ThrottlingServiceSpec struct {
	TokenCapacity     int     `json:"token_capacity,omitempty"`
	TokenRefillPerSec float64 `json:"token_refill_per_sec,omitempty"`
	MaxConcurrency    int     `json:"max_concurrency,omitempty"`
	MinConcurrency    int     `json:"min_concurrency,omitempty"`
}

type ThrottlingPreset struct {
	Label       string           `json:"label"`
	Description string           `json:"description,omitempty"`
	Config      ThrottlingConfig `json:"config"`
}

func DefaultThrottleServiceLimits() map[string]ThrottlingServiceSpec {
	return map[string]ThrottlingServiceSpec{
		// Route53 is a global service and its zone-level fan-out can spike quickly on
		// accounts with many hosted zones, so keep the default conservative.
		"route53": {
			TokenCapacity:     2,
			TokenRefillPerSec: 1,
			MaxConcurrency:    2,
			MinConcurrency:    1,
		},
	}
}

func DefaultThrottleLargeAWSAccountSafeConfig() ThrottlingConfig {
	return ThrottlingConfig{
		Enabled:           true,
		TokenCapacity:     6,
		TokenRefillPerSec: 2,
		AdaptiveThreshold: 2,
		AdaptiveWindowSec: 120,
		CoolOffSec:        90,
		MaxConcurrency:    2,
		MinConcurrency:    1,
		CircuitBreaker: &CircuitBreakerConfig{
			Threshold:  4,
			CoolOffSec: 180,
		},
		ServiceLimits: map[string]ThrottlingServiceSpec{
			"apigateway": {
				TokenCapacity:     1,
				TokenRefillPerSec: 0.5,
				MaxConcurrency:    1,
				MinConcurrency:    1,
			},
			"cloudfront": {
				TokenCapacity:     1,
				TokenRefillPerSec: 0.5,
				MaxConcurrency:    1,
				MinConcurrency:    1,
			},
			"ec2": {
				TokenCapacity:     2,
				TokenRefillPerSec: 1,
				MaxConcurrency:    1,
				MinConcurrency:    1,
			},
			"ecs": {
				TokenCapacity:     1,
				TokenRefillPerSec: 1,
				MaxConcurrency:    1,
				MinConcurrency:    1,
			},
			"eks": {
				TokenCapacity:     1,
				TokenRefillPerSec: 0.5,
				MaxConcurrency:    1,
				MinConcurrency:    1,
			},
			"elasticache": {
				TokenCapacity:     1,
				TokenRefillPerSec: 0.5,
				MaxConcurrency:    1,
				MinConcurrency:    1,
			},
			"elasticloadbalancing": {
				TokenCapacity:     1,
				TokenRefillPerSec: 1,
				MaxConcurrency:    1,
				MinConcurrency:    1,
			},
			"rds": {
				TokenCapacity:     1,
				TokenRefillPerSec: 0.5,
				MaxConcurrency:    1,
				MinConcurrency:    1,
			},
			"redshift": {
				TokenCapacity:     1,
				TokenRefillPerSec: 0.5,
				MaxConcurrency:    1,
				MinConcurrency:    1,
			},
			"route53": {
				TokenCapacity:     1,
				TokenRefillPerSec: 0.5,
				MaxConcurrency:    1,
				MinConcurrency:    1,
			},
			"s3": {
				TokenCapacity:     2,
				TokenRefillPerSec: 1,
				MaxConcurrency:    1,
				MinConcurrency:    1,
			},
		},
	}
}

func DefaultThrottlePresets() map[string]ThrottlingPreset {
	return map[string]ThrottlingPreset{
		"large_aws_account_safe": {
			Label:       "Large AWS account (Safest)",
			Description: "Conservative preset for large AWS accounts. Minimizes Route53 and control-plane throttling risk at the cost of slower sync throughput.",
			Config:      DefaultThrottleLargeAWSAccountSafeConfig(),
		},
	}
}

// DiscoveryIntervals holds sync intervals for each provider.
type DiscoveryIntervals struct {
	AWS   int `json:"aws,omitempty"`
	GCP   int `json:"gcp,omitempty"`
	Azure int `json:"azure,omitempty"`
}

// TaggingRule defines an automated tagging rule with complex conditions.
type TaggingRule struct {
	Name       string            `json:"name"`
	Enabled    bool              `json:"enabled"`
	Conditions RuleConditions    `json:"conditions"`
	Tags       map[string]string `json:"tags"`
	Priority   int               `json:"priority,omitempty"`
}

// RuleConditions supports AND/OR/NOT logic for rule evaluation.
type RuleConditions struct {
	AllOf  []Condition `json:"all_of,omitempty"`  // AND - all conditions must match
	AnyOf  []Condition `json:"any_of,omitempty"`  // OR - at least one condition must match
	NoneOf []Condition `json:"none_of,omitempty"` // NOT - no conditions should match
}

// Condition represents a single evaluation condition.
type Condition struct {
	Field    string      `json:"field"`    // e.g., "source_service", "environment", "public_exposure"
	Operator string      `json:"operator"` // "equals", "in", "contains", "regex", "greater_than", "less_than", "exists"
	Value    interface{} `json:"value"`
}

// PortCatalog manages port classification and risk definitions.
type PortCatalog struct {
	HighRiskPorts  []RiskPortDefinition `json:"high_risk_ports"`
	CustomServices []CustomServicePort  `json:"custom_services,omitempty"`
}

// RiskPortDefinition defines a port with its associated risk level.
type RiskPortDefinition struct {
	Port      int    `json:"port"`
	Protocol  string `json:"protocol"` // tcp, udp
	Service   string `json:"service"`
	RiskLevel string `json:"risk_level"` // critical, high, medium, low
	Reason    string `json:"reason"`
	Enabled   bool   `json:"enabled"`
}

// CustomServicePort allows users to define custom port-to-service mappings.
type CustomServicePort struct {
	Port        int    `json:"port"`
	Service     string `json:"service"`
	Description string `json:"description,omitempty"`
	Environment string `json:"environment,omitempty"`
}

// EphemeralAssetPolicy controls TTL and cleanup for short-lived assets.
type EphemeralAssetPolicy struct {
	TTLHours            int    `json:"ttl_hours"`                       // Hours before asset is considered stale
	EnableAutoCleanup   bool   `json:"enable_auto_cleanup"`             // Auto-delete stale assets
	PreserveHistory     bool   `json:"preserve_history"`                // Keep in asset_history table
	CleanupCronSchedule string `json:"cleanup_cron_schedule,omitempty"` // Cron schedule for cleanup job
}

// ConfigDefaults returns a default config payload with sensible defaults.
func ConfigDefaults() ConfigData {
	return ConfigData{
		TaggingRules: []TaggingRule{
			{
				Name:    "Production Critical Assets",
				Enabled: true,
				Conditions: RuleConditions{
					AllOf: []Condition{
						{Field: "environment", Operator: "equals", Value: "prod"},
						{Field: "public_exposure", Operator: "equals", Value: true},
					},
				},
				Tags: map[string]string{
					"criticality":  "high",
					"auto_monitor": "enabled",
				},
				Priority: 1,
			},
		},
		DiscoveryIntervals: &DiscoveryIntervals{
			AWS:   60,
			GCP:   120,
			Azure: 120,
		},
		PortCatalog: &PortCatalog{
			HighRiskPorts: []RiskPortDefinition{
				{Port: 22, Protocol: "tcp", Service: "SSH", RiskLevel: "critical", Reason: "Remote shell access", Enabled: true},
				{Port: 3389, Protocol: "tcp", Service: "RDP", RiskLevel: "critical", Reason: "Windows remote desktop", Enabled: true},
				{Port: 3306, Protocol: "tcp", Service: "MySQL", RiskLevel: "high", Reason: "Database exposure", Enabled: true},
				{Port: 5432, Protocol: "tcp", Service: "PostgreSQL", RiskLevel: "high", Reason: "Database exposure", Enabled: true},
				{Port: 6379, Protocol: "tcp", Service: "Redis", RiskLevel: "high", Reason: "Cache/data store exposure", Enabled: true},
				{Port: 27017, Protocol: "tcp", Service: "MongoDB", RiskLevel: "high", Reason: "NoSQL database exposure", Enabled: true},
				{Port: 9200, Protocol: "tcp", Service: "Elasticsearch", RiskLevel: "medium", Reason: "Search engine API", Enabled: true},
			},
			CustomServices: []CustomServicePort{},
		},
		EphemeralAssetPolicy: &EphemeralAssetPolicy{
			TTLHours:            6,
			EnableAutoCleanup:   false,
			PreserveHistory:     true,
			CleanupCronSchedule: "0 */6 * * *",
		},
		CollectionScope: &CollectionScope{
			IPCollectionScope:     CollectionScopeAll,
			PortCollectionScope:   CollectionScopeAll,
			DomainCollectionScope: CollectionScopeAll,
		},
		Throttling: &ThrottlingConfig{
			Enabled:           true,
			TokenCapacity:     DefaultThrottleTokenCapacity,
			TokenRefillPerSec: DefaultThrottleTokenRefillPerSec,
			AdaptiveThreshold: DefaultThrottleAdaptiveThreshold,
			AdaptiveWindowSec: DefaultThrottleAdaptiveWindowSec,
			CoolOffSec:        DefaultThrottleCoolOffSec,
			MaxConcurrency:    DefaultThrottleMaxConcurrency,
			MinConcurrency:    DefaultThrottleMinConcurrency,
			CircuitBreaker: &CircuitBreakerConfig{
				Threshold:  DefaultThrottleAdaptiveThreshold * 2,
				CoolOffSec: DefaultThrottleCoolOffSec * 2,
			},
			ServiceLimits: maps.Clone(DefaultThrottleServiceLimits()),
		},
		SyncSettings: &SyncSettings{
			Mode:                    "serverless",
			LambdaFunctionName:      "caasm-collector",
			KillSwitchEnabled:       false,
			ExecutionTimeoutMinutes: DefaultSyncJobExecutionTimeoutMinutes,
			RunningTimeoutMinutes:   DefaultSyncJobRunningTimeoutMinutes,
			QueuedTimeoutMinutes:    DefaultSyncJobQueuedTimeoutMinutes,
		},
	}
}

// TableName specifies the table name for Config model.
func (Config) TableName() string {
	return "caasm_config"
}
