package config

import (
	"encoding/json"
	"os"
)

// Config holds the heuristic service configuration
type Config struct {
	Port      string `json:"port"`
	RedisURL  string `json:"redis_url"`
	JWTSecret string `json:"jwt_secret"`

	// Heuristic thresholds
	Thresholds ThresholdConfig `json:"thresholds"`

	// Heuristic weights
	Weights WeightConfig `json:"weights"`

	// Step-up configuration
	StepUp StepUpConfig `json:"step_up"`

	// Tick configuration
	Tick TickConfig `json:"tick"`

	// Compliance settings
	Compliance ComplianceConfig `json:"compliance"`
}

// ThresholdConfig defines score thresholds
type ThresholdConfig struct {
	ScorePass      float64 `json:"score_pass"`      // Score to pass without step-up (e.g., 0.7)
	ScoreChallenge float64 `json:"score_challenge"` // Score below which step-up is required (e.g., 0.4)
}

// WeightConfig defines weights for each heuristic
type WeightConfig struct {
	DwellRatio      float64 `json:"dwell_ratio"`      // Weight for dwell time ratio
	ScrollScore     float64 `json:"scroll_score"`     // Weight for scroll depth
	PointerVariance float64 `json:"pointer_variance"` // Weight for mouse movement patterns
	ClickRate       float64 `json:"click_rate"`       // Weight for click interactions
}

// StepUpConfig defines step-up verification methods
type StepUpConfig struct {
	Methods  []string       `json:"methods"` // ["webauthn", "pow"]
	Primary  string         `json:"primary"` // Preferred method
	WebAuthn WebAuthnConfig `json:"webauthn"`
	PoW      PoWConfig      `json:"pow"`
}

// WebAuthnConfig for WebAuthn step-up
type WebAuthnConfig struct {
	Enabled           bool   `json:"enabled"`
	UserVerification  string `json:"userVerification"` // "preferred", "required", "discouraged"
	TimeoutMs         int    `json:"timeout_ms"`
	ChallengeEndpoint string `json:"challenge_endpoint"`
}

// PoWConfig for Proof-of-Work step-up
type PoWConfig struct {
	Enabled       bool `json:"enabled"`
	Difficulty    int  `json:"difficulty"`      // Number of leading zero bits required
	MaxDurationMs int  `json:"max_duration_ms"` // Max time for PoW computation
}

// TickConfig for periodic tick submissions
type TickConfig struct {
	Endpoint   string `json:"endpoint"`
	IntervalMs int    `json:"interval_ms"`
}

// ComplianceConfig for privacy compliance
type ComplianceConfig struct {
	GDPR        bool `json:"gdpr"`
	AnonymizeIP bool `json:"anonymize_ip"`
	NoCookies   bool `json:"no_cookies"`
	NoPII       bool `json:"no_pii"`
}

// PathConfig for path-specific rules
type PathConfig struct {
	MinScore     float64 `json:"min_score"`
	StepUpMethod *string `json:"step_up_method"` // nil means no step-up
}

// DefaultConfig returns a default configuration
func DefaultConfig() *Config {
	return &Config{
		Port:      getEnv("PORT", "8085"),
		RedisURL:  getEnv("REDIS_URL", "redis://localhost:6379"),
		JWTSecret: getEnv("JWT_SECRET", "pca-secret-change-me"),
		Thresholds: ThresholdConfig{
			ScorePass:      0.7,
			ScoreChallenge: 0.4,
		},
		Weights: WeightConfig{
			DwellRatio:      0.30,
			ScrollScore:     0.25,
			PointerVariance: 0.20,
			ClickRate:       0.25,
		},
		StepUp: StepUpConfig{
			Methods: []string{"webauthn", "pow"},
			Primary: "webauthn",
			WebAuthn: WebAuthnConfig{
				Enabled:           true,
				UserVerification:  "preferred",
				TimeoutMs:         60000,
				ChallengeEndpoint: "/pca/v1/webauthn-challenge",
			},
			PoW: PoWConfig{
				Enabled:       true,
				Difficulty:    4,
				MaxDurationMs: 5000,
			},
		},
		Tick: TickConfig{
			Endpoint:   "/pca/v1/tick",
			IntervalMs: 5000,
		},
		Compliance: ComplianceConfig{
			GDPR:        true,
			AnonymizeIP: true,
			NoCookies:   true,
			NoPII:       true,
		},
	}
}

// LoadFromFile loads configuration from a JSON file
func LoadFromFile(path string) (*Config, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return DefaultConfig(), nil // Return default if file not found
	}

	config := DefaultConfig()
	if err := json.Unmarshal(data, config); err != nil {
		return nil, err
	}

	return config, nil
}

func getEnv(key, defaultValue string) string {
	if value := os.Getenv(key); value != "" {
		return value
	}
	return defaultValue
}
