package config

import (
	"time"

	"github.com/tech/sendico/pkg/db"
	"github.com/tech/sendico/pkg/messaging"
)

const (
	defaultShutdownTimeoutSeconds = 15
	defaultMetricsAddress         = ":9420"
	defaultWorkerConcurrency      = 8
	defaultWorkerPollIntervalMS   = 200
	defaultLockTTLSeconds         = 30
	defaultRequestTimeoutMS       = 10000
	defaultMaxAttempts            = 8
	defaultMinDelayMS             = 1000
	defaultMaxDelayMS             = 300000
	defaultJitterRatio            = 0.20
	defaultDNSResolveTimeoutMS    = 2000
	defaultSecretsVaultField      = "value"
)

// Loader parses callbacks service configuration.
type Loader interface {
	Load(path string) (*Config, error)
}

// Config is the full callbacks service configuration.
type Config struct {
	Runtime   *RuntimeConfig    `yaml:"runtime"`
	Metrics   *MetricsConfig    `yaml:"metrics"`
	Database  *db.Config        `yaml:"database"`
	Messaging *messaging.Config `yaml:"messaging"`
	Delivery  DeliveryConfig    `yaml:"delivery"`
	Security  SecurityConfig    `yaml:"security"`
	Secrets   SecretsConfig     `yaml:"secrets"`
}

// RuntimeConfig contains process lifecycle settings.
type RuntimeConfig struct {
	ShutdownTimeoutSeconds int `yaml:"shutdown_timeout_seconds"`
}

func (c *RuntimeConfig) ShutdownTimeout() time.Duration {
	if c == nil || c.ShutdownTimeoutSeconds <= 0 {
		return defaultShutdownTimeoutSeconds * time.Second
	}
	return time.Duration(c.ShutdownTimeoutSeconds) * time.Second
}

// MetricsConfig configures observability endpoints.
type MetricsConfig struct {
	Address string `yaml:"address"`
}

func (c *MetricsConfig) ListenAddress() string {
	if c == nil || c.Address == "" {
		return defaultMetricsAddress
	}
	return c.Address
}

// DeliveryConfig controls dispatcher behavior.
type DeliveryConfig struct {
	WorkerConcurrency int     `yaml:"worker_concurrency"`
	WorkerPollMS      int     `yaml:"worker_poll_ms"`
	LockTTLSeconds    int     `yaml:"lock_ttl_seconds"`
	RequestTimeoutMS  int     `yaml:"request_timeout_ms"`
	MaxAttempts       int     `yaml:"max_attempts"`
	MinDelayMS        int     `yaml:"min_delay_ms"`
	MaxDelayMS        int     `yaml:"max_delay_ms"`
	JitterRatio       float64 `yaml:"jitter_ratio"`
}

func (c *DeliveryConfig) WorkerPollInterval() time.Duration {
	if c.WorkerPollMS <= 0 {
		return time.Duration(defaultWorkerPollIntervalMS) * time.Millisecond
	}
	return time.Duration(c.WorkerPollMS) * time.Millisecond
}

func (c *DeliveryConfig) LockTTL() time.Duration {
	if c.LockTTLSeconds <= 0 {
		return time.Duration(defaultLockTTLSeconds) * time.Second
	}
	return time.Duration(c.LockTTLSeconds) * time.Second
}

func (c *DeliveryConfig) RequestTimeout() time.Duration {
	if c.RequestTimeoutMS <= 0 {
		return time.Duration(defaultRequestTimeoutMS) * time.Millisecond
	}
	return time.Duration(c.RequestTimeoutMS) * time.Millisecond
}

func (c *DeliveryConfig) MinDelay() time.Duration {
	if c.MinDelayMS <= 0 {
		return time.Duration(defaultMinDelayMS) * time.Millisecond
	}
	return time.Duration(c.MinDelayMS) * time.Millisecond
}

func (c *DeliveryConfig) MaxDelay() time.Duration {
	if c.MaxDelayMS <= 0 {
		return time.Duration(defaultMaxDelayMS) * time.Millisecond
	}
	return time.Duration(c.MaxDelayMS) * time.Millisecond
}

// SecurityConfig controls outbound callback safety checks.
type SecurityConfig struct {
	RequireHTTPS      bool     `yaml:"require_https"`
	AllowedHosts      []string `yaml:"allowed_hosts"`
	AllowedPorts      []int    `yaml:"allowed_ports"`
	DNSResolveTimeout int      `yaml:"dns_resolve_timeout_ms"`
}

func (c *SecurityConfig) DNSResolveTimeoutMS() time.Duration {
	if c.DNSResolveTimeout <= 0 {
		return time.Duration(defaultDNSResolveTimeoutMS) * time.Millisecond
	}
	return time.Duration(c.DNSResolveTimeout) * time.Millisecond
}

// SecretsConfig controls secret lookup behavior.
type SecretsConfig struct {
	CacheTTLSeconds int                `yaml:"cache_ttl_seconds"`
	Static          map[string]string  `yaml:"static"`
	Vault           VaultSecretsConfig `yaml:"vault"`
}

// VaultSecretsConfig controls Vault KV secret resolution.
type VaultSecretsConfig struct {
	Address      string `yaml:"address"`
	TokenEnv     string `yaml:"token_env"`
	Namespace    string `yaml:"namespace"`
	MountPath    string `yaml:"mount_path"`
	DefaultField string `yaml:"default_field"`
}

func (c *SecretsConfig) CacheTTL() time.Duration {
	if c == nil || c.CacheTTLSeconds <= 0 {
		return 0
	}
	return time.Duration(c.CacheTTLSeconds) * time.Second
}
