package cmd

import (
	"os"
	"path/filepath"
	"regexp"

	multierror "github.com/hashicorp/go-multierror"
	"github.com/spf13/cobra"

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

var (
	repoURL       string
	repoPath      string
	plansRootPath string
	armIndexOnly  bool
)

// ghpCmd represents the github pipeline command
var ghpCmd = &cobra.Command{
	Use:   "ghp",
	Short: "Github pipeline subcommand",
}

var metafileRegex = regexp.MustCompile(`^meta(-\w+)*\.ya*ml$`)

var ghpSubmitCmd = &cobra.Command{
	Use:          "submit",
	Short:        "Submit all the github plans from the `repo-dir` directory",
	Long:         "Submit is a subcommand used to submit all the github plans, it should be called on the root directory of a github plan repo",
	SilenceUsage: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		git, err := ghpkg.NewGitTool(repoURL, repoPath)
		if err != nil {
			return err
		}
		metafiles, err := scanMetafiles()
		if err != nil {
			return err
		}
		var anyErrors error
		for i, metafile := range metafiles {
			removeOldPlans := i == (len(metafiles) - 1)
			armMode := false
			if metafile == "meta-arm64.yaml" {
				armMode = true
			}
			syncer := ghpkg.Syncer{
				MetafilePath:     metafile,
				PlansDir:         plansRootPath,
				Git:              git,
				ServerConfig:     serverConfig,
				ECRServer:        ecrServer,
				OnlySyncEcrImage: onlySyncECRImage,
				ARMMode:          armMode,
			}
			if err := syncer.Init().Sync(dryrun, removeOldPlans); err != nil {
				anyErrors = multierror.Append(anyErrors, err)
			}
		}
		return anyErrors
	},
}

func scanMetafiles() (metafiles []string, err error) {
	if err = filepath.Walk(plansRootPath, func(path string, f os.FileInfo, err error) error {
		if f.IsDir() && path != "." {
			return filepath.SkipDir
		}
		if metafileRegex.MatchString(path) {
			metafiles = append(metafiles, path)
		}
		return nil
	}); err != nil {
		return
	}
	return
}

var ghpCheckCmd = &cobra.Command{
	Use:          "check",
	Short:        "Check all the github plans from the `repo-dir` directory",
	Long:         "Check is a subcommand used to check all the github plans, it should be called on the root directory of a github plan repo",
	SilenceUsage: true,
	RunE: func(cmd *cobra.Command, args []string) error {
		git, err := ghpkg.NewGitTool(repoURL, repoPath)
		if err != nil {
			return err
		}
		metafiles, err := scanMetafiles()
		if err != nil {
			return err
		}
		var anyErrors error
		for _, metafile := range metafiles {
			armMode := false
			if metafile == "meta-arm64.yaml" {
				armMode = true
			}
			if armIndexOnly && !armMode {
				continue
			}
			syncer := ghpkg.Syncer{
				MetafilePath:     metafile,
				PlansDir:         plansRootPath,
				Git:              git,
				ServerConfig:     serverConfig,
				ECRServer:        ecrServer,
				OnlySyncEcrImage: onlySyncECRImage,
				ARMMode:          armMode,
			}
			if err := syncer.Init().Check(); err != nil {
				anyErrors = multierror.Append(anyErrors, err)
			}
		}
		return anyErrors
	},
}

func init() {
	ghpCmd.PersistentFlags().StringVar(&repoURL, "repo", "github.com/pingcap/test-plan", "specify the repo url")
	ghpCmd.PersistentFlags().StringVar(&repoPath, "repo-dir", ".", "specify the repo path")
	ghpCmd.PersistentFlags().StringVar(&plansRootPath, "plan-root", ".", "specify the plans root dir")

	ghpSubmitCmd.PersistentFlags().BoolVar(&dryrun, dryRunFlag, false, "dry run")
	ghpSubmitCmd.PersistentFlags().StringVar(&ecrServer, "ecr-server", ecrServerDefault, "the ecr server")
	ghpSubmitCmd.PersistentFlags().BoolVar(&onlySyncECRImage, "only-ecr-image", false, "only sync ecr images")

	ghpCheckCmd.PersistentFlags().BoolVar(&armIndexOnly, "arm-only", false, "index the arm test-plan only")

	ghpCmd.AddCommand(ghpSubmitCmd)
	ghpCmd.AddCommand(ghpCheckCmd)
	rootCmd.AddCommand(ghpCmd)
}
