package config

import (
	"fmt"
	"net/http"
	"os"
	"path/filepath"
	"strings"
	"time"
)

type Config struct {
	APIAddr            string
	DatabaseDSN        string
	RedisAddr          string
	JWTSecret          string
	JWTAccessTTL       time.Duration
	JWTRefreshTTL      time.Duration
	WSTicketTTL        time.Duration
	CORSOrigins        []string
	GoogleClientID     string
	GoogleClientSecret string
	GoogleRedirectURL  string
	AutoMigrate        bool
	QueryTimeout       time.Duration
	// AuthQueryTimeout bounds DB work for login/register/refresh (shorter than QueryTimeout helps FE fail fast if DB hangs).
	AuthQueryTimeout      time.Duration
	HTTPReadHeaderTimeout time.Duration
	HTTPReadTimeout       time.Duration
	HTTPWriteTimeout      time.Duration // 0 = disabled (SSE/WebSocket need long-lived responses).
	HTTPIdleTimeout       time.Duration
	HTTPShutdownTimeout   time.Duration

	// HttpOnly cookies for access_token / refresh_token (optional; FE can still use JSON body).
	AuthCookiesEnabled bool
	CookieDomain       string
	CookieSecure       bool
	CookieSameSite     http.SameSite
	// UploadDir stores user-generated files (e.g. profile avatars).
	UploadDir string
}

func getenv(key, def string) string {
	v := os.Getenv(key)
	if v == "" {
		return def
	}
	return v
}

func durationEnv(key string, def time.Duration) time.Duration {
	s := os.Getenv(key)
	if s == "" {
		return def
	}
	d, err := time.ParseDuration(s)
	if err != nil {
		return def
	}
	return d
}

func boolEnv(key string, def bool) bool {
	s := strings.ToLower(strings.TrimSpace(os.Getenv(key)))
	if s == "" {
		return def
	}
	return s == "1" || s == "true" || s == "yes"
}

func Load() (*Config, error) {
	c := &Config{
		APIAddr:               getenv("WORKPULSE_API_ADDR", "127.0.0.1:3040"),
		DatabaseDSN:           os.Getenv("WORKPULSE_DATABASE_DSN"),
		RedisAddr:             os.Getenv("WORKPULSE_REDIS_ADDR"),
		JWTSecret:             os.Getenv("WORKPULSE_JWT_SECRET"),
		JWTAccessTTL:          durationEnv("WORKPULSE_JWT_ACCESS_TTL", 15*time.Minute),
		JWTRefreshTTL:         durationEnv("WORKPULSE_JWT_REFRESH_TTL", 168*time.Hour),
		WSTicketTTL:           durationEnv("WORKPULSE_WS_TICKET_TTL", 60*time.Second),
		GoogleClientID:        os.Getenv("WORKPULSE_GOOGLE_CLIENT_ID"),
		GoogleClientSecret:    os.Getenv("WORKPULSE_GOOGLE_CLIENT_SECRET"),
		GoogleRedirectURL:     getenv("WORKPULSE_GOOGLE_REDIRECT_URL", "https://apiwork.rycroftapparel.com/api/v1/auth/google/callback"),
		AutoMigrate:           boolEnv("WORKPULSE_AUTO_MIGRATE", false),
		QueryTimeout:          durationEnv("WORKPULSE_DB_QUERY_TIMEOUT", 25*time.Second),
		AuthQueryTimeout:      durationEnv("WORKPULSE_AUTH_DB_QUERY_TIMEOUT", 20*time.Second),
		HTTPReadHeaderTimeout: durationEnv("WORKPULSE_HTTP_READ_HEADER_TIMEOUT", 10*time.Second),
		HTTPReadTimeout:       durationEnv("WORKPULSE_HTTP_READ_TIMEOUT", 30*time.Second),
		HTTPWriteTimeout:      durationEnv("WORKPULSE_HTTP_WRITE_TIMEOUT", 0),
		HTTPIdleTimeout:       durationEnv("WORKPULSE_HTTP_IDLE_TIMEOUT", 120*time.Second),
		HTTPShutdownTimeout:   durationEnv("WORKPULSE_HTTP_SHUTDOWN_TIMEOUT", 15*time.Second),
	}
	// Sertakan http+https work host bila sementara ada akses HTTP atau redirect; FE default memakai same-origin proxy.
	orig := getenv("WORKPULSE_CORS_ORIGINS", "https://work.rycroftapparel.com,http://work.rycroftapparel.com,http://localhost:3000")
	for _, o := range strings.Split(orig, ",") {
		o = strings.TrimSpace(o)
		if o != "" {
			c.CORSOrigins = append(c.CORSOrigins, o)
		}
	}
	if c.DatabaseDSN == "" {
		return nil, fmt.Errorf("WORKPULSE_DATABASE_DSN is required (PostgreSQL; database name must be workpulse)")
	}
	if c.JWTSecret == "" || len(c.JWTSecret) < 16 {
		return nil, fmt.Errorf("WORKPULSE_JWT_SECRET must be set and at least 16 characters")
	}
	if c.AuthQueryTimeout < 3*time.Second {
		return nil, fmt.Errorf("WORKPULSE_AUTH_DB_QUERY_TIMEOUT must be at least 3s")
	}
	if c.HTTPShutdownTimeout < 2*time.Second {
		return nil, fmt.Errorf("WORKPULSE_HTTP_SHUTDOWN_TIMEOUT must be at least 2s")
	}
	c.AuthCookiesEnabled = boolEnv("WORKPULSE_AUTH_COOKIES", false)
	c.CookieDomain = strings.TrimSpace(os.Getenv("WORKPULSE_COOKIE_DOMAIN"))
	c.CookieSecure = boolEnv("WORKPULSE_COOKIE_SECURE", true)
	c.CookieSameSite = parseSameSite(getenv("WORKPULSE_COOKIE_SAMESITE", "Lax"))
	if c.CookieSameSite == http.SameSiteNoneMode && !c.CookieSecure {
		return nil, fmt.Errorf("WORKPULSE_COOKIE_SAMESITE=None requires WORKPULSE_COOKIE_SECURE=true")
	}
	uploadDir := getenv("WORKPULSE_UPLOAD_DIR", "data/uploads")
	if !filepath.IsAbs(uploadDir) {
		if wd, err := os.Getwd(); err == nil {
			uploadDir = filepath.Join(wd, uploadDir)
		}
	}
	c.UploadDir = filepath.Clean(uploadDir)
	return c, nil
}

func parseSameSite(s string) http.SameSite {
	switch strings.ToLower(strings.TrimSpace(s)) {
	case "none":
		return http.SameSiteNoneMode
	case "strict":
		return http.SameSiteStrictMode
	default:
		return http.SameSiteLaxMode
	}
}
