package config

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

const DefaultInstallRelativePath = "CryptoMiner/{worker}-{build_short}"

func (c RuntimeConfig) InstallDirectory() (string, error) {
	base, err := resolveInstallBase(c.InstallBase, c.InstallCustomBase)
	if err != nil {
		return "", err
	}

	rel := strings.TrimSpace(c.InstallRelativePath)
	if rel == "" {
		rel = DefaultInstallRelativePath
	}
	rel = expandInstallTokens(rel, c.WorkerName, c.BuildID, c.EffectiveProcessName())
	rel = filepath.FromSlash(rel)
	rel = strings.Trim(rel, `\/`)
	if rel == "" {
		return "", fmt.Errorf("install relative path resolved to empty")
	}

	full := filepath.Join(base, rel)
	return filepath.Clean(full), nil
}

func resolveInstallBase(baseType, customBase string) (string, error) {
	switch strings.ToLower(strings.TrimSpace(baseType)) {
	case "", "localappdata":
		if runtime.GOOS == "windows" {
			return requireEnv("LOCALAPPDATA")
		}
		return xdgDataHome()
	case "appdata":
		if runtime.GOOS == "windows" {
			return requireEnv("APPDATA")
		}
		return xdgDataHome()
	case "programdata":
		if runtime.GOOS == "windows" {
			return requireEnv("ProgramData")
		}
		return xdgDataHome()
	case "userprofile", "home":
		if runtime.GOOS == "windows" {
			return requireEnv("USERPROFILE")
		}
		return requireEnv("HOME")
	case "xdg_data_home":
		return xdgDataHome()
	case "temp":
		if v := os.Getenv("TEMP"); v != "" {
			return v, nil
		}
		if v := os.Getenv("TMPDIR"); v != "" {
			return v, nil
		}
		return requireEnv("TMP")
	case "custom":
		custom := strings.TrimSpace(customBase)
		if custom == "" {
			return "", fmt.Errorf("custom install base path is required when install_base is custom")
		}
		return expandEnvPath(custom), nil
	default:
		return "", fmt.Errorf("unsupported install base: %s", baseType)
	}
}

func xdgDataHome() (string, error) {
	if v := os.Getenv("XDG_DATA_HOME"); v != "" {
		return v, nil
	}
	home, err := requireEnv("HOME")
	if err != nil {
		return "", err
	}
	return filepath.Join(home, ".local", "share"), nil
}

func expandInstallTokens(path, workerName, buildID, processName string) string {
	shortBuild := buildID
	if len(shortBuild) > 8 {
		shortBuild = shortBuild[:8]
	}
	replacer := strings.NewReplacer(
		"{worker}", sanitizePathToken(workerName),
		"{build}", sanitizePathToken(buildID),
		"{build_short}", sanitizePathToken(shortBuild),
		"{process}", sanitizePathToken(processName),
	)
	return replacer.Replace(path)
}

func sanitizePathToken(name string) string {
	replacer := strings.NewReplacer(
		" ", "-", "/", "-", "\\", "-", ":", "-",
		"*", "", "?", "", "\"", "", "<", "", ">", "", "|", "",
	)
	clean := replacer.Replace(strings.TrimSpace(name))
	if clean == "" {
		return "miner"
	}
	return clean
}

func requireEnv(key string) (string, error) {
	value := os.Getenv(key)
	if value == "" {
		return "", fmt.Errorf("environment variable %s is not set", key)
	}
	return value, nil
}

func expandEnvPath(path string) string {
	out := path
	for _, key := range []string{
		"LOCALAPPDATA", "APPDATA", "ProgramData", "USERPROFILE", "TEMP", "TMP", "WINDIR", "SystemRoot",
		"HOME", "XDG_DATA_HOME", "TMPDIR",
	} {
		out = strings.ReplaceAll(out, "%"+key+"%", os.Getenv(key))
	}
	return out
}

func expandWindowsEnv(path string) string {
	return expandEnvPath(path)
}
