package backend

import (
	"encoding/json"
	"errors"
	"os"
	"path/filepath"
	"strings"
)

const legacyTidalAPICacheFile = "tidal-api-urls.json"

func normalizeCustomTidalAPIValue(value interface{}) string {
	customAPI, _ := value.(string)
	customAPI = strings.TrimRight(strings.TrimSpace(customAPI), "/")
	if strings.HasPrefix(customAPI, "https://") {
		return customAPI
	}
	return ""
}

func sanitizeDownloaderValue(value interface{}, allowTidal bool) string {
	downloader, _ := value.(string)
	switch strings.TrimSpace(strings.ToLower(downloader)) {
	case "tidal":
		if allowTidal {
			return "tidal"
		}
		return "auto"
	case "qobuz":
		return "qobuz"
	case "amazon":
		return "amazon"
	default:
		return "auto"
	}
}

func sanitizeAutoOrderValue(value interface{}, allowTidal bool) string {
	autoOrder, _ := value.(string)
	allowed := map[string]struct{}{
		"qobuz":  {},
		"amazon": {},
	}
	fallback := "qobuz-amazon"
	if allowTidal {
		allowed["tidal"] = struct{}{}
		fallback = "tidal-qobuz-amazon"
	}

	seen := make(map[string]struct{})
	parts := make([]string, 0, 3)
	for _, rawPart := range strings.Split(strings.TrimSpace(strings.ToLower(autoOrder)), "-") {
		part := strings.TrimSpace(rawPart)
		if part == "" {
			continue
		}
		if _, ok := allowed[part]; !ok {
			continue
		}
		if _, ok := seen[part]; ok {
			continue
		}
		seen[part] = struct{}{}
		parts = append(parts, part)
	}

	if len(parts) < 2 {
		return fallback
	}

	return strings.Join(parts, "-")
}

func SanitizeSettingsMap(settings map[string]interface{}) map[string]interface{} {
	if settings == nil {
		return nil
	}

	sanitized := make(map[string]interface{}, len(settings))
	for key, value := range settings {
		sanitized[key] = value
	}

	customAPI := normalizeCustomTidalAPIValue(sanitized["customTidalApi"])
	sanitized["customTidalApi"] = customAPI
	allowTidal := customAPI != ""
	sanitized["downloader"] = sanitizeDownloaderValue(sanitized["downloader"], allowTidal)
	sanitized["autoOrder"] = sanitizeAutoOrderValue(sanitized["autoOrder"], allowTidal)

	return sanitized
}

func CleanupLegacyTidalPublicAPIState() error {
	appDir, err := EnsureAppDir()
	if err != nil {
		return err
	}

	cachePath := filepath.Join(appDir, legacyTidalAPICacheFile)
	if err := os.Remove(cachePath); err != nil && !errors.Is(err, os.ErrNotExist) {
		return err
	}

	return nil
}

func SanitizePersistedConfigSettings() error {
	configPath, err := GetConfigPath()
	if err != nil {
		return err
	}

	if _, err := os.Stat(configPath); os.IsNotExist(err) {
		return nil
	}

	data, err := os.ReadFile(configPath)
	if err != nil {
		return err
	}

	var settings map[string]interface{}
	if err := json.Unmarshal(data, &settings); err != nil {
		return err
	}

	sanitized := SanitizeSettingsMap(settings)
	payload, err := json.MarshalIndent(sanitized, "", "  ")
	if err != nil {
		return err
	}

	return os.WriteFile(configPath, payload, 0o644)
}

func GetDefaultMusicPath() string {

	homeDir, err := os.UserHomeDir()
	if err != nil {

		return "C:\\Users\\Public\\Music"
	}

	return filepath.Join(homeDir, "Music")
}

func GetConfigPath() (string, error) {
	dir, err := EnsureAppDir()
	if err != nil {
		return "", err
	}

	return filepath.Join(dir, "config.json"), nil
}

func LoadConfigSettings() (map[string]interface{}, error) {
	configPath, err := GetConfigPath()
	if err != nil {
		return nil, err
	}

	if _, err := os.Stat(configPath); os.IsNotExist(err) {
		return nil, nil
	}

	data, err := os.ReadFile(configPath)
	if err != nil {
		return nil, err
	}

	var settings map[string]interface{}
	if err := json.Unmarshal(data, &settings); err != nil {
		return nil, err
	}

	return SanitizeSettingsMap(settings), nil
}

func GetRedownloadWithSuffixSetting() bool {
	settings, err := LoadConfigSettings()
	if err != nil || settings == nil {
		return false
	}

	enabled, _ := settings["redownloadWithSuffix"].(bool)
	return enabled
}

func GetCustomTidalAPISetting() string {
	settings, err := LoadConfigSettings()
	if err != nil || settings == nil {
		return ""
	}

	return normalizeCustomTidalAPIValue(settings["customTidalApi"])
}

func normalizeExistingFileCheckMode(value string) string {
	switch strings.TrimSpace(strings.ToLower(value)) {
	case "isrc", "upc":
		return "isrc"
	default:
		return "filename"
	}
}

func GetExistingFileCheckModeSetting() string {
	settings, err := LoadConfigSettings()
	if err != nil || settings == nil {
		return "filename"
	}

	rawMode, _ := settings["existingFileCheckMode"].(string)
	return normalizeExistingFileCheckMode(rawMode)
}

func GetLinkResolverSetting() string {
	settings, err := LoadConfigSettings()
	if err != nil || settings == nil {
		return linkResolverProviderDeezerSongLink
	}

	resolver, _ := settings["linkResolver"].(string)
	switch strings.TrimSpace(strings.ToLower(resolver)) {
	case "songlink", linkResolverProviderDeezerSongLink:
		return linkResolverProviderDeezerSongLink
	case "songstats":
		return linkResolverProviderSongstats
	case "":
		return linkResolverProviderDeezerSongLink
	default:
		return linkResolverProviderDeezerSongLink
	}
}

func GetLinkResolverAllowFallback() bool {
	settings, err := LoadConfigSettings()
	if err != nil || settings == nil {
		return true
	}

	allowFallback, ok := settings["allowResolverFallback"].(bool)
	if !ok {
		return true
	}

	return allowFallback
}
