package keybinds

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

type DiscoveryConfig struct {
	SearchPaths []string
}

func DefaultDiscoveryConfig() *DiscoveryConfig {
	var searchPaths []string

	configHome := os.Getenv("XDG_CONFIG_HOME")
	if configHome == "" {
		if homeDir, err := os.UserHomeDir(); err == nil {
			configHome = filepath.Join(homeDir, ".config")
		}
	}

	if configHome != "" {
		searchPaths = append(searchPaths, filepath.Join(configHome, "DankMaterialShell", "cheatsheets"))
	}

	configDirs := os.Getenv("XDG_CONFIG_DIRS")
	if configDirs != "" {
		for _, dir := range strings.Split(configDirs, ":") {
			if dir != "" {
				searchPaths = append(searchPaths, filepath.Join(dir, "DankMaterialShell", "cheatsheets"))
			}
		}
	}

	return &DiscoveryConfig{
		SearchPaths: searchPaths,
	}
}

func (d *DiscoveryConfig) FindJSONFiles() ([]string, error) {
	var files []string

	for _, searchPath := range d.SearchPaths {
		expandedPath, err := expandPath(searchPath)
		if err != nil {
			continue
		}

		if _, err := os.Stat(expandedPath); os.IsNotExist(err) {
			continue
		}

		entries, err := os.ReadDir(expandedPath)
		if err != nil {
			continue
		}

		for _, entry := range entries {
			if entry.IsDir() {
				continue
			}

			if !strings.HasSuffix(entry.Name(), ".json") {
				continue
			}

			fullPath := filepath.Join(expandedPath, entry.Name())
			files = append(files, fullPath)
		}
	}

	return files, nil
}

func expandPath(path string) (string, error) {
	expandedPath := os.ExpandEnv(path)

	if filepath.HasPrefix(expandedPath, "~") {
		home, err := os.UserHomeDir()
		if err != nil {
			return "", err
		}
		expandedPath = filepath.Join(home, expandedPath[1:])
	}

	return filepath.Clean(expandedPath), nil
}

type JSONProviderFactory func(filePath string) (Provider, error)

var jsonProviderFactory JSONProviderFactory

func SetJSONProviderFactory(factory JSONProviderFactory) {
	jsonProviderFactory = factory
}

func AutoDiscoverProviders(registry *Registry, config *DiscoveryConfig) error {
	if config == nil {
		config = DefaultDiscoveryConfig()
	}

	if jsonProviderFactory == nil {
		return nil
	}

	files, err := config.FindJSONFiles()
	if err != nil {
		return fmt.Errorf("failed to discover JSON files: %w", err)
	}

	for _, file := range files {
		provider, err := jsonProviderFactory(file)
		if err != nil {
			continue
		}

		if err := registry.Register(provider); err != nil {
			continue
		}
	}

	return nil
}
