package config

import (
	"encoding/json"
	"fmt"
	"os"
	"strconv"
	"sync"
)

type Config struct {
	DatabaseURL          string
	JWTSecret            string
	Port                 string
	AllowedOrigins       string
	SMTPHost             string
	SMTPPort             string
	SMTPUser             string
	SMTPPass             string
	SMTPFromEmail        string
	SMTPFromName         string
	MidtransServerKey    string
	MidtransClientKey    string
	MidtransIsProduction bool
	GoogleClientID       string
	GoogleClientSecret   string
	GoogleCallbackURL    string
	AppURL               string
	UploadDir            string
	AppSettings          *AppSettings
}

type AppSettings struct {
	mu sync.RWMutex

	RegistrationEnabled    bool     `json:"registration_enabled"`
	LoginPasswordEnabled   bool     `json:"login_password_enabled"`
	LoginGoogleEnabled     bool     `json:"login_google_enabled"`
	GoogleRegisteredOnly   bool     `json:"google_login_registered_only"`
	PaymentGatewayEnabled  bool     `json:"payment_gateway_enabled"`
	PaymentMethodsEnabled  []string `json:"payment_methods_enabled"`
	VisitorRedirectURL     string   `json:"visitor_redirect_url"`
	SchoolModeEnabled      bool     `json:"school_mode_enabled"`
	QueueMaxActiveSessions int      `json:"queue_max_active_sessions"`
	QueueSessionDuration   int      `json:"queue_session_duration"`
	DefaultLockDuration    int      `json:"default_lock_duration"`
	MaxFileSizeMB          int      `json:"max_file_size_mb"`
	AllowedUploadExts      []string `json:"allowed_upload_extensions"`
}

func defaultAppSettings() *AppSettings {
	return &AppSettings{
		RegistrationEnabled:    true,
		LoginPasswordEnabled:   true,
		LoginGoogleEnabled:     true,
		GoogleRegisteredOnly:   true,
		PaymentGatewayEnabled:  true,
		PaymentMethodsEnabled:  []string{"qris", "gopay", "shopeepay", "bank_transfer", "credit_card"},
		VisitorRedirectURL:     "/visitor/events",
		SchoolModeEnabled:      true,
		QueueMaxActiveSessions: 50,
		QueueSessionDuration:   10,
		DefaultLockDuration:    10,
		MaxFileSizeMB:          10,
		AllowedUploadExts:      []string{".jpg", ".jpeg", ".png", ".gif", ".webp"},
	}
}

func LoadAppSettings(path string) *AppSettings {
	settings := defaultAppSettings()

	data, err := os.ReadFile(path)
	if err != nil {
		fmt.Printf("[config] No config file at %s, using defaults: %v\n", path, err)
		return settings
	}

	var raw map[string]interface{}
	if err := json.Unmarshal(data, &raw); err != nil {
		fmt.Printf("[config] Failed to parse config file: %v\n", err)
		return settings
	}

	if app, ok := raw["app"].(map[string]interface{}); ok {
		// app-level settings (currently none that overlap)
		_ = app
	}
	if auth, ok := raw["auth"].(map[string]interface{}); ok {
		if v, ok := auth["registrationEnabled"].(bool); ok {
			settings.RegistrationEnabled = v
		}
		if v, ok := auth["loginPasswordEnabled"].(bool); ok {
			settings.LoginPasswordEnabled = v
		}
		if v, ok := auth["loginGoogleEnabled"].(bool); ok {
			settings.LoginGoogleEnabled = v
		}
		if v, ok := auth["googleLoginRegisteredOnly"].(bool); ok {
			settings.GoogleRegisteredOnly = v
		}
	}
	if payment, ok := raw["payment"].(map[string]interface{}); ok {
		if v, ok := payment["gatewayEnabled"].(bool); ok {
			settings.PaymentGatewayEnabled = v
		}
		if methods, ok := payment["methodsEnabled"].([]interface{}); ok {
			strMethods := make([]string, 0, len(methods))
			for _, m := range methods {
				if s, ok := m.(string); ok {
					strMethods = append(strMethods, s)
				}
			}
			if len(strMethods) > 0 {
				settings.PaymentMethodsEnabled = strMethods
			}
		}
	}
	if queue, ok := raw["queue"].(map[string]interface{}); ok {
		if v, ok := queue["maxConcurrentActiveSessions"].(float64); ok {
			settings.QueueMaxActiveSessions = int(v)
		}
		if v, ok := queue["activeSessionDurationMinutes"].(float64); ok {
			settings.QueueSessionDuration = int(v)
		}
		if v, ok := queue["defaultLockDurationMinutes"].(float64); ok {
			settings.DefaultLockDuration = int(v)
		}
	}
	if ui, ok := raw["ui"].(map[string]interface{}); ok {
		if v, ok := ui["visitorRedirectUrl"].(string); ok {
			settings.VisitorRedirectURL = v
		}
	}
	if school, ok := raw["school"].(map[string]interface{}); ok {
		if v, ok := school["modeEnabled"].(bool); ok {
			settings.SchoolModeEnabled = v
		}
	}
	if upload, ok := raw["upload"].(map[string]interface{}); ok {
		if v, ok := upload["maxFileSizeMB"].(float64); ok {
			settings.MaxFileSizeMB = int(v)
		}
		if exts, ok := upload["allowedExtensions"].([]interface{}); ok {
			strExts := make([]string, 0, len(exts))
			for _, e := range exts {
				if s, ok := e.(string); ok {
					strExts = append(strExts, s)
				}
			}
			if len(strExts) > 0 {
				settings.AllowedUploadExts = strExts
			}
		}
	}

	fmt.Println("[config] App settings loaded from config.json")
	return settings
}

// AppSettings getters (thread-safe if needed in future)
func (s *AppSettings) IsRegistrationEnabled() bool       { s.mu.RLock(); defer s.mu.RUnlock(); return s.RegistrationEnabled }
func (s *AppSettings) IsLoginPasswordEnabled() bool       { s.mu.RLock(); defer s.mu.RUnlock(); return s.LoginPasswordEnabled }
func (s *AppSettings) IsLoginGoogleEnabled() bool         { s.mu.RLock(); defer s.mu.RUnlock(); return s.LoginGoogleEnabled }
func (s *AppSettings) IsGoogleRegisteredOnly() bool       { s.mu.RLock(); defer s.mu.RUnlock(); return s.GoogleRegisteredOnly }
func (s *AppSettings) IsPaymentGatewayEnabled() bool      { s.mu.RLock(); defer s.mu.RUnlock(); return s.PaymentGatewayEnabled }
func (s *AppSettings) GetPaymentMethods() []string        { s.mu.RLock(); defer s.mu.RUnlock(); return s.PaymentMethodsEnabled }
func (s *AppSettings) GetVisitorRedirectURL() string      { s.mu.RLock(); defer s.mu.RUnlock(); return s.VisitorRedirectURL }
func (s *AppSettings) GetQueueMaxActiveSessions() int     { s.mu.RLock(); defer s.mu.RUnlock(); return s.QueueMaxActiveSessions }
func (s *AppSettings) GetQueueSessionDuration() int       { s.mu.RLock(); defer s.mu.RUnlock(); return s.QueueSessionDuration }
func (s *AppSettings) GetDefaultLockDuration() int        { s.mu.RLock(); defer s.mu.RUnlock(); return s.DefaultLockDuration }

func Load() *Config {
	appSettings := LoadAppSettings("config.json")

	return &Config{
		DatabaseURL:          getEnv("DATABASE_URL", ""),
		JWTSecret:            getEnv("JWT_SECRET", "dev-secret-key-change-in-production"),
		Port:                 getEnv("PORT", "8080"),
		AllowedOrigins:       getEnv("ALLOWED_ORIGINS", "http://localhost:5173,http://localhost:3000"),
		SMTPHost:             getEnv("SMTP_HOST", ""),
		SMTPPort:             getEnv("SMTP_PORT", "587"),
		SMTPUser:             getEnv("SMTP_USER", ""),
		SMTPPass:             getEnv("SMTP_PASS", ""),
		SMTPFromEmail:        getEnv("SMTP_FROM_EMAIL", ""),
		SMTPFromName:         getEnv("SMTP_FROM_NAME", "SMA Katolik St. Louis 1 Surabaya Ticketing"),
		MidtransServerKey:    getEnv("MIDTRANS_SERVER_KEY", ""),
		MidtransClientKey:    getEnv("MIDTRANS_CLIENT_KEY", ""),
		MidtransIsProduction: getEnv("MIDTRANS_IS_PRODUCTION", "false") == "true",
		GoogleClientID:       getEnv("GOOGLE_CLIENT_ID", ""),
		GoogleClientSecret:   getEnv("GOOGLE_CLIENT_SECRET", ""),
		GoogleCallbackURL:    getEnv("GOOGLE_CALLBACK_URL", ""),
		AppURL:               getEnv("APP_URL", "http://localhost:5173"),
		UploadDir:            getEnv("UPLOAD_DIR", "./uploads"),
		AppSettings:          appSettings,
	}
}

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

func getEnvInt(key string, fallback int) int {
	if v := os.Getenv(key); v != "" {
		if i, err := strconv.Atoi(v); err == nil {
			return i
		}
	}
	return fallback
}
