package cmd

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

	"github.com/spf13/cobra"

	ghpkg "github.com/pingcap/test-infra/tools/tcctl/pkg/github_plan"
	oneshotpkg "github.com/pingcap/test-infra/tools/tcctl/pkg/one_shot"
)

var metaFile string

// runCmd represents the run command
var runCmd = &cobra.Command{
	Use:          "run",
	Short:        "Run an one_shot plan",
	Long:         `Run an one_shot plan'`,
	SilenceUsage: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		var configs map[string]*ghpkg.Config
		var err error

		if inputFile == "" {
			return fmt.Errorf("no input file")
		}
		configs, err = loadMetas(metaFile)
		if err != nil {
			return fmt.Errorf("load metas error: %w", err)
		}
		return runFile(inputFile, configs)
	},
}

func runFile(fileName string, metas map[string]*ghpkg.Config) error {
	var input io.Reader
	if fileName == "-" {
		input = os.Stdin
	} else {
		_f, err := os.Open(fileName)
		if err != nil {
			panic(err)
		}
		input = _f
	}
	oneshot := oneshotpkg.OneShot{ServerConfig: serverConfig, ECRServer: ecrServer}
	switch len(metas) {
	case 0:
		return oneshot.Init().Run(input, nil, dryrun)
	case 1:
		for _, meta := range metas {
			return oneshot.Init().Run(input, meta, dryrun)
		}
	default:
		return oneshot.Init().RunOnMetafiles(input, metas, dryrun)
	}
	return nil
}

func loadMetas(metaFile string) (metas map[string]*ghpkg.Config, err error) {
	if metaFile == "" {
		return nil, nil
	}
	metas = make(map[string]*ghpkg.Config)
	err = filepath.Walk(metaFile, func(path string, info fs.FileInfo, err error) error {
		switch filepath.Ext(path) {
		case ".yaml", ".yml":
			config, err := ghpkg.ReadConfigFile(path)
			if err != nil {
				return err
			}
			metas[path] = config
		}
		return nil
	})
	return metas, err
}

func init() {
	runCmd.PersistentFlags().StringVarP(&metaFile, "meta-file", "m", "", "the meta.yaml path")
	runCmd.PersistentFlags().StringVar(&ecrServer, "ecr-server", ecrServerDefault, "the ecr server")
	runCmd.PersistentFlags().BoolVar(&dryrun, dryRunFlag, false, "dry run")
	rootCmd.AddCommand(runCmd)
}
