// Package config provides KMS configuration types shared across KMS providers.
package config

import (
	"fmt"
	"time"
)

// ProviderType identifies the KMS provider implementation.
type ProviderType string

const (
	ProviderTypeVault  ProviderType = "vault"
	ProviderTypeAWS    ProviderType = "aws"
	ProviderTypeMemory ProviderType = "memory" // Development only
)

// IsValid returns true if the provider type is valid.
func (t ProviderType) IsValid() bool {
	switch t {
	case ProviderTypeVault, ProviderTypeAWS, ProviderTypeMemory:
		return true
	}
	return false
}

// Config holds KMS provider configuration.
type Config struct {
	Provider ProviderType `yaml:"provider"`
	Vault    VaultConfig  `yaml:"vault,omitempty"`
	AWS      AWSConfig    `yaml:"aws,omitempty"`
	Cache    CacheConfig  `yaml:"cache,omitempty"`
}

// VaultConfig holds HashiCorp Vault-specific configuration.
type VaultConfig struct {
	Address      string        `yaml:"address"`
	AuthMethod   string        `yaml:"auth_method"`
	RoleID       string        `yaml:"role_id"`
	SecretID     string        `yaml:"secret_id"`
	Token        string        `yaml:"token"`
	TransitMount string        `yaml:"transit_mount"`
	KeyPrefix    string        `yaml:"key_prefix"`
	Region       string        `yaml:"region"`
	Timeout      time.Duration `yaml:"timeout"`
}

// AWSConfig holds AWS KMS-specific configuration.
type AWSConfig struct {
	Region         string `yaml:"region"`
	KeyAliasPrefix string `yaml:"key_alias_prefix"`
	RoleARN        string `yaml:"role_arn,omitempty"`
	Endpoint       string `yaml:"endpoint,omitempty"`
}

// CacheConfig holds DEK cache configuration per ADR-012.
type CacheConfig struct {
	TTL         time.Duration `yaml:"ttl_minutes"`
	MaxEntries  int           `yaml:"max_entries"`
	GraceWindow time.Duration `yaml:"grace_window_minutes"`
}

// DefaultCacheConfig returns the default cache configuration per ADR-012/013.
func DefaultCacheConfig() CacheConfig {
	return CacheConfig{
		TTL:         15 * time.Minute,
		MaxEntries:  1000,
		GraceWindow: 1 * time.Hour,
	}
}

// Validate checks the configuration for errors.
func (c *Config) Validate() error {
	if !c.Provider.IsValid() {
		return fmt.Errorf("invalid KMS provider: %s", c.Provider)
	}

	switch c.Provider {
	case ProviderTypeVault:
		if err := c.Vault.Validate(); err != nil {
			return fmt.Errorf("vault config: %w", err)
		}
	case ProviderTypeAWS:
		if err := c.AWS.Validate(); err != nil {
			return fmt.Errorf("aws config: %w", err)
		}
	}

	// Apply defaults for cache config
	if c.Cache.TTL == 0 {
		c.Cache.TTL = DefaultCacheConfig().TTL
	}
	if c.Cache.MaxEntries == 0 {
		c.Cache.MaxEntries = DefaultCacheConfig().MaxEntries
	}
	if c.Cache.GraceWindow == 0 {
		c.Cache.GraceWindow = DefaultCacheConfig().GraceWindow
	}

	return nil
}

// Validate checks Vault configuration.
func (v *VaultConfig) Validate() error {
	if v.Address == "" {
		return fmt.Errorf("vault address is required")
	}

	switch v.AuthMethod {
	case "approle":
		if v.RoleID == "" || v.SecretID == "" {
			return fmt.Errorf("approle auth requires role_id and secret_id")
		}
	case "kubernetes":
		// Kubernetes auth uses service account token
	case "token":
		if v.Token == "" {
			return fmt.Errorf("token auth requires token")
		}
	default:
		return fmt.Errorf("invalid auth_method: %s", v.AuthMethod)
	}

	// Apply defaults
	if v.TransitMount == "" {
		v.TransitMount = "transit"
	}
	if v.KeyPrefix == "" {
		v.KeyPrefix = "fetchml-tenant"
	}
	if v.Timeout == 0 {
		v.Timeout = 30 * time.Second
	}

	return nil
}

// Validate checks AWS configuration.
func (a *AWSConfig) Validate() error {
	if a.Region == "" {
		return fmt.Errorf("AWS region is required")
	}

	// Apply defaults
	if a.KeyAliasPrefix == "" {
		a.KeyAliasPrefix = "alias/fetchml"
	}

	return nil
}

// KeyIDForTenant generates a KMS key ID for a tenant based on the provider config.
func (c *Config) KeyIDForTenant(tenantID string) string {
	switch c.Provider {
	case ProviderTypeVault:
		if c.Vault.Region != "" {
			return fmt.Sprintf("%s-%s-%s", c.Vault.KeyPrefix, c.Vault.Region, tenantID)
		}
		return fmt.Sprintf("%s-%s", c.Vault.KeyPrefix, tenantID)
	case ProviderTypeAWS:
		if c.AWS.Region != "" {
			return fmt.Sprintf("%s-%s-%s", c.AWS.KeyAliasPrefix, c.AWS.Region, tenantID)
		}
		return fmt.Sprintf("%s-%s", c.AWS.KeyAliasPrefix, tenantID)
	default:
		return tenantID
	}
}
