package main

import (
	"context"
	"fmt"
	"os"

	"github.com/google/uuid"
	"github.com/spf13/cobra"

	configloader "github.com/tidbcloud/devops/pkg/infra/config/loader"
	"github.com/tidbcloud/devops/pkg/infra/deps"
	"github.com/tidbcloud/devops/pkg/infra/log"
	"github.com/tidbcloud/devops/pkg/infra/utils/signals"
	"github.com/tidbcloud/devops/pkg/service/cloudconfig/api"
	"github.com/tidbcloud/devops/pkg/service/systemmaintenance"
)

var (
	flagConfig string
	globalCtx  context.Context
	globalDeps *deps.Deps
)

func newRootCmd() *cobra.Command {
	cmd := &cobra.Command{
		Use:     "devops-server",
		Version: "v0.0.0",
		Run:     excute,
	}
	cmd.PersistentFlags().StringVar(&flagConfig, "config", "", "path to read root config")
	cmd.MarkFlagsRequiredTogether("config")

	cmd.AddCommand(
		newSendSystemMaintenanceEmailCmd(),
		newSyncVersionsFromGitopsCmd(),
	)
	return cmd
}

func newSendSystemMaintenanceEmailCmd() *cobra.Command {
	var targetRoles string // e.g. "MAIL_LABELS_ORG_OWNER,MAIL_LABELS_PROJ_OWNER", see https://github.com/tidbcloud/account/blob/main/idl/idl/account/account/account.proto#L12
	var batchId string
	cmd := &cobra.Command{
		Use:   "send-system-maintenance-email [tenantID1 tenantID2 ...]",
		Short: "send system maintenance notification email to specified tenants",
		Run: func(cmd *cobra.Command, args []string) {
			cobra.CheckErr(func() error {
				return globalDeps.Container.Invoke(func(svc *systemmaintenance.Service) error {
					if batchId == "" {
						batchId = uuid.New().String()
						log.Logger.Info("use new generated batchId", "batchId", batchId)
					}
					return svc.SendSystemMaintenanceEmail(globalCtx, batchId, args, targetRoles)
				})
			}())
		},
	}
	cmd.Flags().StringVar(&targetRoles, "targetRoles", "MAIL_LABELS_ORG_OWNER", "should send email to which roles, click https://github.com/tidbcloud/account/blob/main/idl/idl/account/account/account.proto#L12 to get all available values.")
	cmd.Flags().StringVar(&batchId, "batchId", "", "which batch of system maintenance, the same target roles in the same batch will receive email once.")

	return cmd
}

func newSyncVersionsFromGitopsCmd() *cobra.Command {
	var minVersion, maxVersion, gitopsBranch string
	cmd := &cobra.Command{
		Use:   "sync-versions-from-gitops",
		Short: "Sync versions from gitops repository",
		Long:  "Synchronize versions from the gitops repository to the configuration center",
		Run: func(cmd *cobra.Command, args []string) {
			cobra.CheckErr(func() error {
				return globalDeps.Container.Invoke(func(svc api.CloudConfigServiceAPI) error {
					ctx := context.Background()
					return svc.SyncVersionsFromGitops(ctx, minVersion, maxVersion, gitopsBranch)
				})
			}())
		},
	}

	cmd.Flags().StringVar(&minVersion, "min-version", "", "minimum version to sync")
	cmd.Flags().StringVar(&maxVersion, "max-version", "", "maximum version to sync")
	cmd.Flags().StringVar(&gitopsBranch, "gitops-branch", "3layer-prod", "branch of the tidb-configuration repository")

	cmd.MarkFlagRequired("min-version")
	cmd.MarkFlagRequired("max-version")

	return cmd
}

func excute(cmd *cobra.Command, args []string) {
	err := run(globalCtx, globalDeps)
	exitIfErr(err, "failed to run")
}

func main() {
	globalCtx = signals.SetupSignalHandler()

	cobra.OnInitialize(func() {
		conf, err := configloader.NewConfigurationLoader(flagConfig, false).Load(globalCtx)
		exitIfErr(err, "failed to init config")
		globalDeps, err = setup(globalCtx, conf)
		exitIfErr(err, "failed to setup")
	})

	cmd := newRootCmd()
	err := cmd.Execute()
	exitIfErr(err, "failed to execute cmd")
}

func exitIfErr(err error, msg string) {
	if err != nil {
		if log.Logger.IsZero() {
			fmt.Fprintln(os.Stderr, err.Error())
		} else {
			log.Logger.Error(err, msg)
		}
		os.Exit(1)
	}
}
