package config

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

	"gopkg.in/yaml.v3"
)

// PollConfig defines how to poll for the current state of a toggle key.
type PollConfig struct {
	Command  string `yaml:"command"`  // shell command whose output is checked
	Interval string `yaml:"interval"` // how often to poll, e.g. "2s" (default: "2s")
	Match    string `yaml:"match"`    // substring to find in output → "on" state; omit to use exit code 0

	// Module-based alternative to Command: resolved to a shell string at startup.
	Module   string            `yaml:"module"`
	Function string            `yaml:"function"`
	Params   map[string]string `yaml:"params"`
}

// KeyConfig defines what a single Stream Deck key does.
type KeyConfig struct {
	Icon    string `yaml:"icon"`    // filename relative to icons_dir (regular keys)
	Command string `yaml:"command"` // shell command to run on press

	// Toggle/status keys: show different icons based on polled state.
	IconTrue  string      `yaml:"icon_true"`  // icon when poll match is true
	IconFalse string      `yaml:"icon_false"` // icon when poll match is false
	Poll      *PollConfig `yaml:"poll"`

	// Module-based alternative to Command: resolved to a shell string at startup.
	Module   string            `yaml:"module"`
	Function string            `yaml:"function"`
	Params   map[string]string `yaml:"params"`
}

// DefaultConfigPath returns the default config file path, respecting XDG_CONFIG_HOME.
func DefaultConfigPath() string {
	base := os.Getenv("XDG_CONFIG_HOME")
	if base == "" {
		home, _ := os.UserHomeDir()
		base = filepath.Join(home, ".config")
	}
	return filepath.Join(base, "streamdeck-go", "config.yaml")
}

// ModulesPath returns the path to the modules.yaml file next to the given config file.
func ModulesPath(cfgPath string) string {
	return filepath.Join(filepath.Dir(cfgPath), "modules.yaml")
}

// Config is the top-level structure of the YAML config file.
type Config struct {
	IconsDir   string            `yaml:"icons_dir"`
	Brightness int               `yaml:"brightness"`
	Device     DeviceConfig      `yaml:"device"`
	Keys       map[int]KeyConfig `yaml:"keys"`
}

// DeviceConfig allows overriding USB IDs (defaults work for Stream Deck XL v2).
type DeviceConfig struct {
	VendorID  uint16 `yaml:"vendor_id"`
	ProductID uint16 `yaml:"product_id"`
}

// Load reads and parses a YAML config file, applying sane defaults.
// icons_dir defaults to an "icons" folder next to the config file.
func Load(path string) (*Config, error) {
	data, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("read config %q: %w", path, err)
	}

	cfg := &Config{
		IconsDir:   filepath.Join(filepath.Dir(path), "icons"),
		Brightness: 70,
		Device: DeviceConfig{
			VendorID:  0x0fd9,
			ProductID: 0x00ba, // Stream Deck XL v2
		},
	}

	if err := yaml.Unmarshal(data, cfg); err != nil {
		return nil, fmt.Errorf("parse config: %w", err)
	}

	// Resolve relative icons_dir against the config file's directory so the
	// binary works regardless of the working directory (e.g. as a systemd service).
	if !filepath.IsAbs(cfg.IconsDir) {
		cfg.IconsDir = filepath.Join(filepath.Dir(path), cfg.IconsDir)
	}

	return cfg, nil
}
