package cmd

import (
	"context"
	"encoding/json"

	"github.com/spf13/cobra"
	"github.com/tidbcloud/dataflow-service-ng/app/container"
	bootstarpSerer "github.com/tidbcloud/dataflow-service-ng/internal/cmd/bootstrap/server"
	service_config "github.com/tidbcloud/dataflow-service-ng/internal/config"
	"github.com/tidbcloud/dataflow-service-ng/pkg/agent"
	"github.com/tidbcloud/dataflow-service-ng/pkg/log"
	"go.uber.org/zap"
)

type premiumDMClusterRegionalClient interface {
	GetDMClusterByID(ctx context.Context, sharedPoolId uint64, dmClusterID string) (*agent.DMCluster, error)
	ListDMClusters(ctx context.Context, sharedPoolId uint64) (*agent.ListDMClustersResponse, error)
}

var (
	startPremiumDMClusterJobServer = func(cmd *cobra.Command) error {
		_, err := bootstarpSerer.NewServer(cmd.Context(), bootstarpSerer.ServerOption{
			EnableEventBusConsumer: false,
		})
		return err
	}
	newPremiumDMClusterRegionalClient = func(ctx context.Context, sharedPoolID uint64) (premiumDMClusterRegionalClient, error) {
		app := container.Global()
		cfg := service_config.Global()
		return agent.NewNGRegionalClientByResourcePoolID(ctx, sharedPoolID, app.MgmtSvcGrpcClient, &agent.ClientConfig{
			MgmtSvcProxyAddr:  cfg.GrpcConfig.MgmtSvcProxyAddr,
			MgmtSvcProxyToken: cfg.GrpcConfig.MgmtSvcProxyToken,
		})
	}
	writePremiumDMClusterJSON = func(cmd *cobra.Command, data any) error {
		encoder := json.NewEncoder(cmd.OutOrStdout())
		encoder.SetIndent("", "  ")
		return encoder.Encode(data)
	}
)

func registerPremiumDMClusterJobFunc(cmd *cobra.Command) {
	registerDeletePremiumDMClusterJobFunc(cmd)
	registerGetPremiumDMClusterJobFunc(cmd)
	registerListPremiumDMClusterJobFunc(cmd)
}

func registerDeletePremiumDMClusterJobFunc(cmd *cobra.Command) {
	var (
		sharedPoolID uint64
		dmClusterID  string
	)

	subCmd := &cobra.Command{
		Use:   "delete",
		Short: "delete a premium dm cluster",
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := startPremiumDMClusterJobServer(cmd); err != nil {
				return err
			}

			ctx := log.WithTraceID(cmd.Context())
			logger := log.GetLogger(ctx)

			if err := container.Global().PremiumDMWorker.DeleteDMClusterIfNoWorkers(ctx, sharedPoolID, dmClusterID); err != nil {
				logger.Error("delete premium dm cluster error",
					zap.Uint64("shared_pool_id", sharedPoolID),
					zap.String("dm_cluster_id", dmClusterID),
					zap.Error(err))
				return err
			}

			logger.Info("delete premium dm cluster successfully",
				zap.Uint64("shared_pool_id", sharedPoolID),
				zap.String("dm_cluster_id", dmClusterID))
			return nil
		},
	}

	subCmd.Flags().Uint64VarP(&sharedPoolID, "sharedPoolID", "", 0, "")
	subCmd.Flags().StringVarP(&dmClusterID, "dmClusterID", "", "", "")
	_ = subCmd.MarkFlagRequired("sharedPoolID")
	_ = subCmd.MarkFlagRequired("dmClusterID")
	cmd.AddCommand(subCmd)
}

func registerGetPremiumDMClusterJobFunc(cmd *cobra.Command) {
	var (
		sharedPoolID uint64
		dmClusterID  string
	)

	subCmd := &cobra.Command{
		Use:   "get",
		Short: "get a premium dm cluster",
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := startPremiumDMClusterJobServer(cmd); err != nil {
				return err
			}

			ctx := log.WithTraceID(cmd.Context())
			client, err := newPremiumDMClusterRegionalClient(ctx, sharedPoolID)
			if err != nil {
				return err
			}
			dmCluster, err := client.GetDMClusterByID(ctx, sharedPoolID, dmClusterID)
			if err != nil {
				return err
			}
			return writePremiumDMClusterJSON(cmd, dmCluster)
		},
	}

	subCmd.Flags().Uint64VarP(&sharedPoolID, "sharedPoolID", "", 0, "")
	subCmd.Flags().StringVarP(&dmClusterID, "dmClusterID", "", "", "")
	_ = subCmd.MarkFlagRequired("sharedPoolID")
	_ = subCmd.MarkFlagRequired("dmClusterID")
	cmd.AddCommand(subCmd)
}

func registerListPremiumDMClusterJobFunc(cmd *cobra.Command) {
	var sharedPoolID uint64

	subCmd := &cobra.Command{
		Use:   "list",
		Short: "list premium dm clusters in a shared pool",
		RunE: func(cmd *cobra.Command, args []string) error {
			if err := startPremiumDMClusterJobServer(cmd); err != nil {
				return err
			}

			ctx := log.WithTraceID(cmd.Context())
			client, err := newPremiumDMClusterRegionalClient(ctx, sharedPoolID)
			if err != nil {
				return err
			}
			resp, err := client.ListDMClusters(ctx, sharedPoolID)
			if err != nil {
				return err
			}
			return writePremiumDMClusterJSON(cmd, resp)
		},
	}

	subCmd.Flags().Uint64VarP(&sharedPoolID, "sharedPoolID", "", 0, "")
	_ = subCmd.MarkFlagRequired("sharedPoolID")
	cmd.AddCommand(subCmd)
}

func init() {
	cmd := &cobra.Command{
		Use:   "premium_dm_cluster",
		Short: "premium dm cluster cmd",
	}
	registerPremiumDMClusterJobFunc(cmd)
	jobCmd.AddCommand(cmd)
}
