package open_in_mpv

import (
	"log"
	"path/filepath"
	"strings"

	"github.com/shibukawa/configdir"
	"gopkg.in/yaml.v2"
)

// The Player struct contains useful informations for an mpv-based player,
// such as binary name and fullscreen/pip/enqueue/new_window flags overrides for
// use in GenerateIPC(). A way to override any generic flags is also
// provided through the map FlagOverrides.
type Player struct {
	// Full name of the player
	Name string
	// Executable path/name (if already in $PATH) for the player
	Executable string
	// Flag override for fullscreen
	Fullscreen string
	// Flag override for picture-in-picture mode
	Pip string
	// Flag override for enqueuing videos
	Enqueue string
	// Flag override for forcing new window
	NewWindow string `yaml:"new_window"`
	// Controls whether this player needs IPC command to enqueue videos
	NeedsIpc bool `yaml:"needs_ipc"`
	// Controls which (video URL) schemes are to be opened by the current
	// player. There is no match-all, each protocol has to be manuall specified
	SupportedSchemes []string `yaml:"supported_protocols"`
	// Overrides for any generic flag
	FlagOverrides map[string]string `yaml:"flag_overrides"`
}

// Top-level configuration object, maps a player by name to its Player object
type Config struct {
	Players map[string]Player
}

var defaultSupportedSchemas = []string{
	"http",
	"https",
}

var defaultConfig = Config{
	Players: map[string]Player{
		"mpv": {
			Name:             "mpv",
			Executable:       "mpv",
			Fullscreen:       "--fs",
			Pip:              `--ontop --no-border --autofit=384x216 --geometry=98%:98%`,
			Enqueue:          "",
			NewWindow:        "",
			NeedsIpc:         true,
			SupportedSchemes: defaultSupportedSchemas,
			FlagOverrides:    map[string]string{},
		},
	},
}

// Tries to load configuration file with fallback to a default configuration
// object
func LoadConfig() error {
	confDirs := configdir.New("", "open-in-mpv")
	confDirs.LocalPath, _ = filepath.Abs(".")
	confFolder := confDirs.QueryFolderContainsFile("config.yml")

	if confFolder == nil {
		log.Println("No config file found, using default")
		return nil
	}

	data, err := confFolder.ReadFile("config.yml")
	if err != nil {
		return err
	}

	err = yaml.Unmarshal(data, &defaultConfig)
	if err != nil {
		return err
	}

	// If the player has no external configuration, use strict defaults
	for name, player := range defaultConfig.Players {
		if len(player.SupportedSchemes) == 0 {
			log.Printf("Player '%s' has no schemas, setting to defaults", player.Name)
			player.SupportedSchemes = defaultSupportedSchemas
			defaultConfig.Players[name] = player
		}
		// TODO: restrict/escape custom flags
	}

	return nil
}

// Returns player information for the given name if present, otherwise nil
func GetPlayerConfig(name string) *Player {
	lowerName := strings.ToLower(name)
	if p, ok := defaultConfig.Players[lowerName]; ok {
		return &p
	}

	return nil
}
