package service

import (
	"os"
	"path/filepath"
	"strconv"
	"strings"
)

var hostNameLookup = os.Hostname

// Settings configures the Metis service runtime.
type Settings struct {
	BindAddr            string
	InventoryPath       string
	CacheDir            string
	ArtifactDir         string
	ArtifactStatePath   string
	HistoryPath         string
	SnapshotsPath       string
	TargetsPath         string
	DesiredMetadataPath string
	DefaultFlashHost    string
	FlashHosts          []string
	LocalHost           string
	AllowedGroups       []string
	MaxDeviceBytes      int64
	Namespace           string
	RunnerImageAMD64    string
	RunnerImageARM64    string
	HarborRegistry      string
	HarborProject       string
	HarborAPIBase       string
	HarborUsername      string
	HarborPassword      string
	HostTmpDir          string
	RemoteWorkspaceDir  string
	RemotePodTimeout    int64
}

// FromEnv builds service settings with sensible defaults for local dev and in-cluster use.
func FromEnv() Settings {
	dataDir := getenvDefault("METIS_DATA_DIR", "/var/lib/metis")
	localHost := getenvDefault("METIS_LOCAL_HOST", hostnameOr("unknown"))
	defaultFlashHost := getenvDefault("METIS_DEFAULT_FLASH_HOST", localHost)
	flashHosts := splitList(getenvDefault("METIS_FLASH_HOSTS", defaultFlashHost))
	return Settings{
		BindAddr:            getenvDefault("METIS_BIND_ADDR", ":8080"),
		InventoryPath:       getenvDefault("METIS_INVENTORY_PATH", "inventory.titan-rpi4.yaml"),
		CacheDir:            getenvDefault("METIS_CACHE_DIR", filepath.Join(dataDir, "cache")),
		ArtifactDir:         getenvDefault("METIS_ARTIFACT_DIR", filepath.Join(dataDir, "artifacts")),
		ArtifactStatePath:   getenvDefault("METIS_ARTIFACT_STATE_PATH", filepath.Join(dataDir, "artifacts.json")),
		HistoryPath:         getenvDefault("METIS_HISTORY_PATH", filepath.Join(dataDir, "history.jsonl")),
		SnapshotsPath:       getenvDefault("METIS_SNAPSHOTS_PATH", filepath.Join(dataDir, "snapshots.json")),
		TargetsPath:         getenvDefault("METIS_TARGETS_PATH", filepath.Join(dataDir, "targets.json")),
		DesiredMetadataPath: getenvDefault("METIS_DESIRED_METADATA_PATH", filepath.Join(dataDir, "desired-node-metadata.json")),
		DefaultFlashHost:    defaultFlashHost,
		FlashHosts:          flashHosts,
		LocalHost:           localHost,
		AllowedGroups:       splitList(getenvDefault("METIS_ALLOWED_GROUPS", "admin,maintenance")),
		MaxDeviceBytes:      getenvInt64("METIS_MAX_DEVICE_BYTES", 300000000000),
		Namespace:           getenvDefault("METIS_NAMESPACE", "maintenance"),
		RunnerImageAMD64:    getenvDefault("METIS_RUNNER_IMAGE_AMD64", ""),
		RunnerImageARM64:    getenvDefault("METIS_RUNNER_IMAGE_ARM64", ""),
		HarborRegistry:      getenvDefault("METIS_HARBOR_REGISTRY", "registry.bstein.dev"),
		HarborProject:       getenvDefault("METIS_HARBOR_PROJECT", "metis"),
		HarborAPIBase:       getenvDefault("METIS_HARBOR_API_BASE", "https://registry.bstein.dev/api/v2.0"),
		HarborUsername:      getenvDefault("METIS_HARBOR_USERNAME", ""),
		HarborPassword:      getenvDefault("METIS_HARBOR_PASSWORD", ""),
		HostTmpDir:          getenvDefault("METIS_HOST_TMP_DIR", "/var/tmp/metis-flash-test"),
		RemoteWorkspaceDir:  getenvDefault("METIS_REMOTE_WORKSPACE_DIR", "/var/tmp/metis-workspace"),
		RemotePodTimeout:    getenvInt64("METIS_REMOTE_POD_TIMEOUT_SEC", 1800),
	}
}

func getenvDefault(key, fallback string) string {
	if value := strings.TrimSpace(os.Getenv(key)); value != "" {
		return value
	}
	return fallback
}

func getenvInt64(key string, fallback int64) int64 {
	raw := strings.TrimSpace(os.Getenv(key))
	if raw == "" {
		return fallback
	}
	value, err := strconv.ParseInt(raw, 10, 64)
	if err != nil {
		return fallback
	}
	return value
}

func splitList(raw string) []string {
	if strings.TrimSpace(raw) == "" {
		return nil
	}
	parts := strings.Split(raw, ",")
	result := make([]string, 0, len(parts))
	for _, part := range parts {
		part = strings.TrimSpace(part)
		if part == "" {
			continue
		}
		result = append(result, part)
	}
	return result
}

func hostnameOr(fallback string) string {
	name, err := hostNameLookup()
	if err != nil || strings.TrimSpace(name) == "" {
		return fallback
	}
	return strings.TrimSpace(name)
}
