package main

import (
	"path/filepath"
	"strings"

	"github.com/pkg/errors"
	"github.com/spf13/cobra"
	"github.com/tidbcloud/config-service/pkg/clinic_event"
)

var (
	meta                 bool
	gitPRNum             string
	gitPRCreatedBy       string
	gitCommit            string
	gitCommitMsg         string
	gitCommitFiles       []string
	version              uint64
	output               string
	isOverlay            bool
	diff                 bool
	diffBase             string
	diffNew              string
	baseUrl              string
	activityHub          bool
	activityHubEndpoint  string
	activityHubSourceKey string

	filter *layerFilter
)

func main() {
	overlayCmd := &cobra.Command{
		Use:   "overlay",
		Short: "renders a layered structure of TiDB configurations to final configuration to use",
		Run: func(cmd *cobra.Command, args []string) {
			if activityHub {
				if err := clinic_event.InitEventClient(activityHubEndpoint, clinic_event.GitOpsEventSource, activityHubSourceKey, "", ""); err != nil {
					panic(err)
				}
			}

			// decode
			gitCommitMsg = strings.ReplaceAll(gitCommitMsg, "%20", " ")

			filter = newLayerFilter(gitCommitFiles)

			if isOverlay {
				// This is for config-service, and all CRs are created in base EKS.
				if err := runOverlay(cmd, args); err != nil {
					panic(err)
				}
			} else {
				// This is for config-manager, and all CRs are created in infra-api.
				if err := keepOrigin(cmd, args); err != nil {
					panic(err)
				}
			}
		},
	}
	overlayCmd.Flags().BoolVar(&meta, "meta", false, "whether add meta to output manifests")
	overlayCmd.Flags().StringVar(&gitPRNum, "git-pr-num", "", "git pr number of config")
	overlayCmd.Flags().StringVar(&gitPRCreatedBy, "git-pr-created-by", "", "git pr created by of config")
	overlayCmd.Flags().StringVar(&gitCommit, "git-commit", "", "git commit id of config")
	overlayCmd.Flags().StringVar(&gitCommitMsg, "git-commit-msg", "", "git commit message")
	overlayCmd.Flags().StringSliceVar(&gitCommitFiles, "git-commit-files", []string{}, "git commit files")
	overlayCmd.Flags().Uint64Var(&version, "version", 0, "version of config")
	overlayCmd.Flags().StringVar(&output, "output", "output", "path of output dir")
	overlayCmd.Flags().BoolVar(&isOverlay, "overlay", true, "if true, will overlay configuration")
	overlayCmd.Flags().BoolVar(&diff, "diff", false, "if true, will output diff of configuration")
	overlayCmd.Flags().StringVar(&diffBase, "diff-base", "", "base configuration to diff against")
	overlayCmd.Flags().StringVar(&diffNew, "diff-new", "", "new configuration to diff against")
	overlayCmd.Flags().StringVar(&baseUrl, "base-url", "https://clinic.pingcap.com/grafana/d/90I1Tiqnk/gitops-dryrun?orgId=1", "the external grafana dashboard base url")
	overlayCmd.Flags().BoolVar(&activityHub, "activity", false, "if true, will send the gitops event")
	overlayCmd.Flags().StringVar(&activityHubEndpoint, "activity-hub", "", "the activity hub endpoint")
	overlayCmd.Flags().StringVar(&activityHubSourceKey, "source-key", "", "the activity hub source key")
	if err := overlayCmd.Execute(); err != nil {
		panic(err)
	}
}

// overlay process the layered configuration file tree
// the file tree assumed to be the following format
//
//	.
//
// ├── tenants
// │   └── tenant-1270613000524402688
// │       ├── clusters
// │       │   └── cluster-1270613313241
// │       │       ├── tikv.toml      # cluster overlays, optional
// │       │       └── meta.yaml  # cluster’s version, optional
// │       ├── tikv.toml              # tenant overlays, optional
// │       └── meta.yaml          # tenant’s default version, optional
// ├── versions                       # must include all supported versions, required
// │   └── v4.0.9                     # base config of v4.0.9, required
// │       ├── base
// │       │   ├── backup.yaml
// │       │   ├── restore.yaml
// │       │   ├── pd.toml
// │       │   ├── tidb.toml
// │       │   ├── tiflash.toml
// │       │   ├── tikv.toml
// │       │   └── meta.yaml
// │       └── instances               # instance overlays, optional
// │           ├── aws.m5.2xlarge
// │           │   └── tikv.toml
// │           └── gcp.n2-standard-8
// │               └── tikv.toml
// └── meta.yaml                  # Global default version, required
func runOverlay(_ *cobra.Command, args []string) error {
	if diff {
		if err := runDiff(diffBase, diffNew); err != nil {
			return errors.Wrap(err, "overlay diff failed")
		}
		return nil
	}
	if len(args) < 1 {
		return errors.New("the base directory must be specified")
	}
	base := args[0]
	tree, err := visit(base)
	if err != nil {
		return err
	}
	return overlay(tree, filepath.Join(base, output))
}

func keepOrigin(_ *cobra.Command, args []string) error {
	if len(args) < 1 {
		return errors.New("the base directory must be specified")
	}
	base := args[0]
	tree, err := visit(base)
	if err != nil {
		return err
	}
	return origin(tree, filepath.Join(base, output))
}
