package main

import (
	"errors"
	"os"
	"strings"

	"github.com/spf13/pflag"
)

const (
	CommandStart = "start"
	CommandStop  = "stop"
	CommandNew   = "new"
	CommandEdit  = "edit"
	CommandList  = "list"
	CommandPrint = "print"
)

type command struct {
	Name    string
	Aliases []string
}

type commands []command

var Commands = commands{
	{
		Name:    CommandStart,
		Aliases: []string{},
	},
	{
		Name:    CommandStop,
		Aliases: []string{"s", "st"},
	},
	{
		Name:    CommandNew,
		Aliases: []string{"n"},
	},
	{
		Name:    CommandEdit,
		Aliases: []string{"e"},
	},
	{
		Name:    CommandList,
		Aliases: []string{"l"},
	},
	{
		Name:    CommandPrint,
		Aliases: []string{"p"},
	},
}

func (c *commands) Resolve(v string) (*command, error) {
	for _, cmd := range *c {
		if cmd.Name == v || Contains(cmd.Aliases, v) {
			return &cmd, nil
		}
	}

	return nil, ErrCommandNotFound
}

func (c *commands) FindByName(n string) *command {
	for _, cmd := range *c {
		if cmd.Name == n {
			return &cmd
		}
	}

	return nil
}

type Options struct {
	Command              string
	Project              string
	Config               string
	Windows              []string
	Settings             map[string]string
	Attach               bool
	Detach               bool
	Debug                bool
	InsideCurrentSession bool
}

var (
	ErrHelp            = errors.New("help requested")
	ErrCommandNotFound = errors.New("command not found")
)

const (
	WindowsUsage              = "List of windows to start. If session exists, those windows will be attached to current session"
	AttachUsage               = "Force switch client for a session"
	DetachUsage               = "Detach tmux session. The same as -d flag in the tmux"
	DebugUsage                = "Print all commands to ~/.config/smug/smug.log"
	FileUsage                 = "A custom path to a config file"
	InsideCurrentSessionUsage = "Create all windows inside current session"
)

func parseUserSettings(args []string) map[string]string {
	settings := make(map[string]string)
	for _, kv := range args {
		s := strings.Split(kv, "=")
		if len(s) < 2 {
			continue
		}
		settings[s[0]] = s[1]
	}

	return settings
}

func ParseOptions(argv []string) (*Options, error) {
	if len(argv) == 0 || argv[0] == "--help" || argv[0] == "-h" {
		return nil, ErrHelp
	}

	cmd, cmdErr := Commands.Resolve(argv[0])
	if errors.Is(cmdErr, ErrCommandNotFound) {
		cmd = Commands.FindByName(CommandStart)
	}

	flags := pflag.NewFlagSet(cmd.Name, pflag.ContinueOnError)

	config := flags.StringP("file", "f", "", FileUsage)
	windows := flags.StringArrayP("windows", "w", []string{}, WindowsUsage)
	attach := flags.BoolP("attach", "a", false, AttachUsage)
	detach := flags.Bool("detach", false, DetachUsage)
	debug := flags.BoolP("debug", "d", false, DebugUsage)
	insideCurrentSession := flags.BoolP("inside-current-session", "i", false, InsideCurrentSessionUsage)

	err := flags.Parse(argv)
	if err == pflag.ErrHelp {
		return nil, ErrHelp
	}

	if err != nil {
		return nil, err
	}

	var project string
	if *config == "" {
		if errors.Is(cmdErr, ErrCommandNotFound) {
			project = argv[0]
		} else if len(argv) > 1 {
			project = argv[1]
		}
	}

	// If config file flag is not set, and env is, use the env
	val, ok := os.LookupEnv("SMUG_SESSION_CONFIG_PATH")
	if *config == "" && project == "" && ok {
		*config = val
	}

	if strings.Contains(project, ":") {
		parts := strings.Split(project, ":")
		project = parts[0]
		wl := strings.Split(parts[1], ",")
		windows = &wl
	}

	settings := parseUserSettings(flags.Args()[1:])

	return &Options{
		Project:              project,
		Config:               *config,
		Command:              cmd.Name,
		Settings:             settings,
		Windows:              *windows,
		Attach:               *attach,
		Detach:               *detach,
		Debug:                *debug,
		InsideCurrentSession: *insideCurrentSession,
	}, nil
}
