package cmd

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

	"git.cryptic.systems/volker.raschek/dcmerge/pkg/domain/dockerCompose"
	"git.cryptic.systems/volker.raschek/dcmerge/pkg/fetcher"
	"github.com/spf13/cobra"
	"gopkg.in/yaml.v2"
)

func Execute(version string) error {
	completionCmd := &cobra.Command{
		Use:                   "completion [bash|zsh|fish|powershell]",
		Short:                 "Generate completion script",
		Long:                  "To load completions",
		DisableFlagsInUseLine: true,
		ValidArgs:             []string{"bash", "zsh", "fish", "powershell"},
		Args:                  cobra.ExactValidArgs(1),
		Run: func(cmd *cobra.Command, args []string) {
			switch args[0] {
			case "bash":
				cmd.Root().GenBashCompletion(os.Stdout)
			case "zsh":
				cmd.Root().GenZshCompletion(os.Stdout)
			case "fish":
				cmd.Root().GenFishCompletion(os.Stdout, true)
			case "powershell":
				cmd.Root().GenPowerShellCompletionWithDesc(os.Stdout)
			}
		},
	}

	rootCmd := &cobra.Command{
		Use:   "dcmerge",
		Args:  cobra.MinimumNArgs(1),
		Short: "Merge docker-compose files from multiple resources",
		Example: `dcmerge docker-compose.yml ./integration-test/docker-compose.yml
dcmerge docker-compose.yml https://git.example.local/user/repo/docker-compose.yml`,
		RunE:    run,
		Version: version,
	}
	rootCmd.Flags().BoolP("existing-win", "f", false, "Protect existing attributes")
	rootCmd.Flags().BoolP("last-win", "l", false, "Overwrite existing attributes")
	rootCmd.Flags().StringP("output-file", "o", "", "Write instead on stdout into a file")
	rootCmd.AddCommand(completionCmd)

	return rootCmd.Execute()
}

func run(cmd *cobra.Command, args []string) error {
	mergeExisting, err := cmd.Flags().GetBool("existing-win")
	if err != nil {
		return fmt.Errorf("Failed to parse flag last-win: %s", err)
	}

	mergeLastWin, err := cmd.Flags().GetBool("last-win")
	if err != nil {
		return fmt.Errorf("Failed to parse flag last-win: %s", err)
	}

	outputFile, err := cmd.Flags().GetString("output-file")
	if err != nil {
		return fmt.Errorf("Failed to parse flag output-file: %s", err)
	}

	dockerComposeConfig := dockerCompose.NewConfig()

	dockerComposeConfigs, err := fetcher.Fetch(args...)
	if err != nil {
		return err
	}

	for _, config := range dockerComposeConfigs {
		switch {
		case mergeExisting && mergeLastWin:
			return fmt.Errorf("Neither --first-win or --last-win can be specified - not booth.")
		case mergeExisting && !mergeLastWin:
			dockerComposeConfig.MergeExistingWin(config)
		case !mergeExisting && mergeLastWin:
			dockerComposeConfig.MergeLastWin(config)
		default:
			dockerComposeConfig.Merge(config)
		}
	}

	switch {
	case len(outputFile) > 0:
		err = os.MkdirAll(filepath.Dir(outputFile), 0755)
		if err != nil {
			return err
		}

		f, err := os.Create(outputFile)
		if err != nil {
			return err
		}
		defer f.Close()

		yamlEncoder := yaml.NewEncoder(f)
		return yamlEncoder.Encode(dockerComposeConfig)

	default:
		yamlEncoder := yaml.NewEncoder(os.Stdout)
		return yamlEncoder.Encode(dockerComposeConfig)
	}

}