package deploy

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

const desktopPathPrefix = "@desktop/"

// UserDesktopDir returns the interactive user's Desktop folder for the current OS.
func UserDesktopDir() (string, error) {
	switch runtime.GOOS {
	case "windows":
		return windowsDesktopDir()
	case "darwin":
		return unixDesktopFromHome("Desktop")
	default:
		return linuxDesktopDir()
	}
}

func windowsDesktopDir() (string, error) {
	profile := strings.TrimSpace(os.Getenv("USERPROFILE"))
	if profile == "" {
		return "", fmt.Errorf("USERPROFILE not set")
	}
	candidates := []string{
		filepath.Join(profile, "Desktop"),
		filepath.Join(profile, "OneDrive", "Desktop"),
		filepath.Join(profile, "OneDrive - Personal", "Desktop"),
	}
	for _, c := range candidates {
		if st, err := os.Stat(c); err == nil && st.IsDir() {
			return filepath.Clean(c), nil
		}
	}
	// Create default Desktop if missing (unusual profiles)
	fallback := candidates[0]
	if err := os.MkdirAll(fallback, 0o755); err != nil {
		return "", err
	}
	return fallback, nil
}

func unixDesktopFromHome(sub string) (string, error) {
	home, err := os.UserHomeDir()
	if err != nil || home == "" {
		return "", fmt.Errorf("home directory unavailable")
	}
	desktop := filepath.Join(home, sub)
	if st, err := os.Stat(desktop); err == nil && st.IsDir() {
		return filepath.Clean(desktop), nil
	}
	if err := os.MkdirAll(desktop, 0o755); err != nil {
		return "", fmt.Errorf("desktop: %w", err)
	}
	return desktop, nil
}

func linuxDesktopDir() (string, error) {
	if out, err := exec.Command("xdg-user-dir", "DESKTOP").Output(); err == nil {
		p := strings.TrimSpace(string(out))
		if p != "" {
			if st, err := os.Stat(p); err == nil && st.IsDir() {
				return filepath.Clean(p), nil
			}
		}
	}
	return unixDesktopFromHome("Desktop")
}

// ResolveDesktopFile joins a sanitized filename onto the user Desktop.
func ResolveDesktopFile(filename string) (string, error) {
	desktop, err := UserDesktopDir()
	if err != nil {
		return "", err
	}
	name := sanitizeDesktopFilename(filename)
	if name == "" {
		name = "upload.bin"
	}
	return filepath.Join(desktop, name), nil
}

func sanitizeDesktopFilename(name string) string {
	name = strings.TrimSpace(name)
	name = strings.ReplaceAll(name, "\\", "/")
	if name == "" {
		return ""
	}
	// Allow subfolders under Desktop but block traversal.
	parts := strings.Split(name, "/")
	var clean []string
	for _, p := range parts {
		p = strings.TrimSpace(p)
		if p == "" || p == "." || p == ".." {
			continue
		}
		clean = append(clean, p)
	}
	return filepath.Join(clean...)
}

// ResolveRemotePath expands @desktop/…, desktop:…, and ~/… for upload/download commands.
func ResolveRemotePath(remote string) (string, error) {
	remote = strings.TrimSpace(remote)
	if remote == "" {
		return "", fmt.Errorf("remote path is empty")
	}
	lower := strings.ToLower(remote)
	if strings.HasPrefix(lower, "desktop:") {
		return ResolveDesktopFile(remote[len("desktop:"):])
	}
	if strings.HasPrefix(remote, desktopPathPrefix) {
		return ResolveDesktopFile(remote[len(desktopPathPrefix):])
	}
	if strings.HasPrefix(remote, "~/") {
		home, err := os.UserHomeDir()
		if err != nil {
			return "", err
		}
		return filepath.Clean(filepath.Join(home, remote[2:])), nil
	}
	return filepath.Clean(remote), nil
}
