// Package config provides centralized configuration management for RouteWatch
package config

import (
	"fmt"
	"os"
	"path/filepath"
	"runtime"
	"time"
)

const (
	// AppIdentifier is the reverse domain name identifier for the app
	AppIdentifier = "berlin.sneak.app.routewatch"

	// dirPermissions for creating directories
	dirPermissions = 0750 // rwxr-x---

	// defaultRouteExpirationMinutes is the default route expiration timeout in minutes
	defaultRouteExpirationMinutes = 5
)

// Config holds configuration for the entire application
type Config struct {
	// StateDir is the directory for all application state (database, snapshots)
	StateDir string

	// MaxRuntime is the maximum runtime (0 = run forever)
	MaxRuntime time.Duration

	// EnableBatchedDatabaseWrites enables batched database operations for better performance
	EnableBatchedDatabaseWrites bool

	// RouteExpirationTimeout is how long a route can go without being refreshed before expiring
	// Default is 2 hours which is conservative for BGP (typical BGP hold time is 90-180 seconds)
	RouteExpirationTimeout time.Duration
}

// New creates a new Config with default paths based on the OS
func New() (*Config, error) {
	stateDir, err := getStateDirectory()
	if err != nil {
		return nil, fmt.Errorf("failed to determine state directory: %w", err)
	}

	return &Config{
		StateDir:                    stateDir,
		MaxRuntime:                  0,                                           // Run forever by default
		EnableBatchedDatabaseWrites: true,                                        // Enable batching by default
		RouteExpirationTimeout:      defaultRouteExpirationMinutes * time.Minute, // For active route monitoring
	}, nil
}

// GetStateDir returns the state directory path
func (c *Config) GetStateDir() string {
	return c.StateDir
}

// getStateDirectory returns the appropriate state directory based on the OS
func getStateDirectory() (string, error) {
	switch runtime.GOOS {
	case "darwin":
		// macOS: ~/Library/Application Support/berlin.sneak.app.routewatch
		home, err := os.UserHomeDir()
		if err != nil {
			return "", err
		}

		return filepath.Join(home, "Library", "Application Support", AppIdentifier), nil

	case "linux", "freebsd", "openbsd", "netbsd":
		// Unix-like: /var/lib/berlin.sneak.app.routewatch if root, else XDG_DATA_HOME
		if os.Geteuid() == 0 {
			return filepath.Join("/var/lib", AppIdentifier), nil
		}

		// Check XDG_DATA_HOME first
		if xdgData := os.Getenv("XDG_DATA_HOME"); xdgData != "" {
			return filepath.Join(xdgData, AppIdentifier), nil
		}

		// Fall back to ~/.local/share/berlin.sneak.app.routewatch
		home, err := os.UserHomeDir()
		if err != nil {
			return "", err
		}

		return filepath.Join(home, ".local", "share", AppIdentifier), nil

	default:
		return "", fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
	}
}

// EnsureDirectories creates all necessary directories if they don't exist
func (c *Config) EnsureDirectories() error {
	// Ensure state directory exists
	if err := os.MkdirAll(c.StateDir, dirPermissions); err != nil {
		return fmt.Errorf("failed to create state directory: %w", err)
	}

	return nil
}
