package main

import (
	"github.com/abiosoft/ishell/v2"
	"github.com/adrg/xdg"
	jira "github.com/andygrunwald/go-jira/v2/cloud"
	prompt "github.com/elk-language/go-prompt"
	pstrings "github.com/elk-language/go-prompt/strings"
	"github.com/pkg/errors"
	"github.com/spf13/viper"
	"log"
	"os"
	"strings"
)

var configPath string
var shell *ishell.Shell
var jiraClient *jira.Client
var jiraUser *jira.User
var promptRunner *prompt.Prompt
var prefix = "> "

func loadConfig() {
	err := viper.ReadInConfig()
	if err != nil {
		log.Fatal(err)
	}
}

func SaveConfig() {
	err := viper.WriteConfig()
	if err != nil {
		log.Fatal(err)
	}
}

func UpdatePrompt() {
	if HasIssue() {
		prefix = "issue " + GetIssueKey()
	} else if HasSprint() {
		prefix = "sprint " + viper.GetString("sprint.name")
	} else if HasBoard() {
		prefix = "board " + viper.GetString("board.name")
	} else if HasProject() {
		prefix = "project " + viper.GetString("project.key")
	} else {
		prefix = "(no project)"
	}
	prefix += "> "
}

func executor(in string) {
	command, args := GetCommand(in)
	if command == nil {
		println("Invalid command", in)
		return
	}
	command.Action(args)
}

func completer(d prompt.Document) ([]prompt.Suggest, pstrings.RuneNumber, pstrings.RuneNumber) {
	endIndex := d.CurrentRuneIndex()
	w := d.GetWordBeforeCursor()
	startIndex := endIndex - pstrings.RuneCount([]byte(w))
	s := GetSuggestionsFor(d.TextBeforeCursor())
	return prompt.FilterHasPrefix(s, w, true), startIndex, endIndex
}

func main() {
	// Open config file
	configPath, err := xdg.ConfigFile("jirashell/config.toml")
	if err != nil {
		log.Fatal(err)
	}
	viper.SetConfigFile(configPath)

	_, err = os.Stat(configPath)
	if err != nil && !errors.Is(err, os.ErrNotExist) {
		log.Fatal(err)
	} else if err == nil {
		loadConfig()
	}

	if !ensureLoggedIn() {
		os.Exit(0)
	}
	if len(os.Args) > 1 {
		executor(strings.Join(os.Args[1:], " "))
	} else {
		UpdatePrompt()

		promptRunner = prompt.New(
			executor,
			prompt.WithCompleter(completer),
			prompt.WithTitle("jirashell"),
			prompt.WithPrefixCallback(func() string { return prefix }),
		)
		promptRunner.Run()
	}
}

func ensureLoggedIn() bool {
	for {
		username := viper.GetString("username")
		host := viper.GetString("host")
		token := viper.GetString("token")

		if host != "" && token != "" && username != "" {
			err := login(host, username, token)
			if err != nil {
				println("Could not log in:", err)
			} else {
				SaveConfig()
				return true
			}
		}

		println()
		println("A host name is required.")
		host = prompt.Input(prompt.WithPrefix("Host: "), prompt.WithInitialText(host))
		if host == "" {
			return false
		}
		viper.Set("host", host)

		println()
		println("A username is required.")
		username = prompt.Input(prompt.WithPrefix("Username: "), prompt.WithInitialText(username))
		if username == "" {
			return false
		}
		viper.Set("username", username)

		println()
		println("A token is required.")
		token = prompt.Input(prompt.WithPrefix("Token: "), prompt.WithInitialText(token))
		if token == "" {
			return false
		}
		viper.Set("token", token)
	}
}

func login(host, username, token string) error {
	var err error
	tp := jira.BasicAuthTransport{
		Username: username,
		APIToken: token,
	}
	jiraClient, err = jira.NewClient(host, tp.Client())
	if err != nil {
		return err
	}

	jiraUser, err = GetUserData()
	return err
}