package internal

import (
	"fmt"
	"os"
	"strings"

	appPkg "coopcloud.tech/abra/pkg/app"
	"coopcloud.tech/abra/pkg/formatter"
	"coopcloud.tech/abra/pkg/log"
	"github.com/AlecAivazis/survey/v2"
	dockerClient "github.com/docker/docker/client"
)

// NewVersionOverview shows an upgrade or downgrade overview
func NewVersionOverview(app appPkg.App, currentVersion, chaosVersion, newVersion, releaseNotes string) error {
	tableCol := []string{"server", "recipe", "config", "domain", "version", "chaos", "to deploy"}
	table := formatter.CreateTable(tableCol)

	deployConfig := "compose.yml"
	if composeFiles, ok := app.Env["COMPOSE_FILE"]; ok {
		deployConfig = strings.Join(strings.Split(composeFiles, ":"), "\n")
	}

	server := app.Server
	if app.Server == "default" {
		server = "local"
	}

	table.Append([]string{
		server,
		app.Recipe.Name,
		deployConfig,
		app.Domain,
		currentVersion,
		chaosVersion,
		newVersion,
	})
	table.Render()

	if releaseNotes != "" && newVersion != "" {
		fmt.Println()
		fmt.Print(releaseNotes)
	} else {
		log.Warnf("no release notes available for %s", newVersion)
	}

	if NoInput {
		return nil
	}

	response := false
	prompt := &survey.Confirm{
		Message: "continue with deployment?",
	}

	if err := survey.AskOne(prompt, &response); err != nil {
		return err
	}

	if !response {
		log.Fatal("exiting as requested")
	}

	return nil
}

// PostCmds parses a string of commands and executes them inside of the respective services
// the commands string must have the following format:
// "<service> <command> <arguments>|<service> <command> <arguments>|... "
func PostCmds(cl *dockerClient.Client, app appPkg.App, commands string) error {
	if _, err := os.Stat(app.Recipe.AbraShPath); err != nil {
		if os.IsNotExist(err) {
			return fmt.Errorf(fmt.Sprintf("%s does not exist for %s?", app.Recipe.AbraShPath, app.Name))
		}
		return err
	}

	for _, command := range strings.Split(commands, "|") {
		commandParts := strings.Split(command, " ")
		if len(commandParts) < 2 {
			return fmt.Errorf(fmt.Sprintf("not enough arguments: %s", command))
		}
		targetServiceName := commandParts[0]
		cmdName := commandParts[1]
		parsedCmdArgs := ""
		if len(commandParts) > 2 {
			parsedCmdArgs = fmt.Sprintf("%s ", strings.Join(commandParts[2:], " "))
		}
		log.Infof("running post-command '%s %s' in container %s", cmdName, parsedCmdArgs, targetServiceName)

		if err := EnsureCommand(app.Recipe.AbraShPath, app.Recipe.Name, cmdName); err != nil {
			return err
		}

		serviceNames, err := appPkg.GetAppServiceNames(app.Name)
		if err != nil {
			return err
		}

		matchingServiceName := false
		for _, serviceName := range serviceNames {
			if serviceName == targetServiceName {
				matchingServiceName = true
			}
		}

		if !matchingServiceName {
			return fmt.Errorf(fmt.Sprintf("no service %s for %s?", targetServiceName, app.Name))
		}

		log.Debugf("running command %s %s within the context of %s_%s", cmdName, parsedCmdArgs, app.StackName(), targetServiceName)

		Tty = true
		if err := RunCmdRemote(cl, app, app.Recipe.AbraShPath, targetServiceName, cmdName, parsedCmdArgs); err != nil {
			return err
		}
	}
	return nil
}

// DeployOverview shows a deployment overview
func DeployOverview(app appPkg.App, version, chaosVersion, message string) error {
	tableCol := []string{"server", "recipe", "config", "domain", "version", "chaos"}
	table := formatter.CreateTable(tableCol)

	deployConfig := "compose.yml"
	if composeFiles, ok := app.Env["COMPOSE_FILE"]; ok {
		deployConfig = strings.Join(strings.Split(composeFiles, ":"), "\n")
	}

	server := app.Server
	if app.Server == "default" {
		server = "local"
	}

	table.Append([]string{
		server,
		app.Recipe.Name,
		deployConfig,
		app.Domain,
		version,
		chaosVersion,
	})
	table.Render()

	if NoInput {
		return nil
	}

	response := false
	prompt := &survey.Confirm{
		Message: message,
	}

	if err := survey.AskOne(prompt, &response); err != nil {
		return err
	}

	if !response {
		log.Fatal("exiting as requested")
	}

	return nil
}