package cmd

import (
	"fmt"

	"github.com/spf13/cobra"
	"github.com/tidbcloud/dataflow-service/app/container"
	bootstarpSerer "github.com/tidbcloud/dataflow-service/internal/cmd/bootstrap/server"
	internalcontainer "github.com/tidbcloud/dataflow-service/internal/container"
	"github.com/tidbcloud/dataflow-service/internal/db"
	internalentity "github.com/tidbcloud/dataflow-service/internal/db/entity"
	"github.com/tidbcloud/dataflow-service/internal/model/connprofile"
	"github.com/tidbcloud/dataflow-service/pkg/account/accountdb"
	"github.com/tidbcloud/dataflow-service/pkg/account/accounttypes"
	"github.com/tidbcloud/dataflow-service/pkg/log"
	mgmt "github.com/tidbcloud/tidb-management-service/api/spec/tidb_mgmt_service/v1"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

func registerPrivateLinkJobFunc(cmd *cobra.Command) {

	{
		var upstreamClusterID, serverlessClusterID uint64
		subCmd := &cobra.Command{
			Use:   "create-df-private-link",
			Short: "create-df-private-link",
			RunE: func(cmd *cobra.Command, args []string) error {
				if _, err := bootstarpSerer.NewServer(cmd.Context(), bootstarpSerer.ServerOption{
					EnableEventBusConsumer: false,
				}); err != nil {
					return err
				}
				ctx := log.WithTraceID(cmd.Context())
				app := container.Global()
				internal := internalcontainer.Global()

				cluster, err := app.CoreGrpcClient.GetAvailableClusterByID(ctx, upstreamClusterID)
				if err != nil {
					return err.Chain("get upstream cluster failed")
				}

				user := &accountdb.User{
					User: accounttypes.User{},
				}
				user.ID = 123123
				userCtx := internal.ConnProfileModel.UserContext(ctx, user)

				resp, err := app.MgmtSvcGrpcClient.ListClusters(ctx, &mgmt.ListClustersRequest{Filter: &mgmt.ClusterFilter{ClusterIds: []uint64{serverlessClusterID}}})
				if err != nil {
					return err.Chain("list serverless cluster failed")
				}
				if len(resp.Clusters) == 0 {
					return fmt.Errorf("no serverless cluster found")
				}
				serverlessCluster := resp.Clusters[0]
				serverlessPrivateEndpoint := serverlessCluster.GetServerlessCluster().GetCluster().
					GetEndpoints().GetPrivate().GetAws()
				if serverlessPrivateEndpoint == nil {
					return fmt.Errorf("serverless aws private link endpoint is empty, serverless cluster: %+v",
						serverlessCluster)
				}

				endpointID, endpointErr := userCtx.CreatePLEndpoint(cluster, serverlessPrivateEndpoint.GetServiceName())
				if endpointErr != nil {
					return fmt.Errorf("create pl endpoint failed: %w", endpointErr)
				}
				log.GetLogger(ctx).Info("create pl endpoint successfully",
					zap.Uint64("endpointID", endpointID),
					zap.Uint64("upstreamClusterID", upstreamClusterID),
					zap.Uint64("serverlessClusterID", serverlessClusterID),
					zap.String("serviceName", serverlessPrivateEndpoint.GetServiceName()))
				return nil
			},
		}
		subCmd.Flags().Uint64VarP(&upstreamClusterID, "upstreamClusterID", "", 0, "")
		subCmd.Flags().Uint64VarP(&serverlessClusterID, "serverlessClusterID", "", 0, "")
		cmd.AddCommand(subCmd)
	}

	{
		var dfPrivateLinkID uint64
		subCmd := &cobra.Command{
			Use:   "mark-df-private-link-failed",
			Short: "mark-df-private-link-failed",
			RunE: func(cmd *cobra.Command, args []string) error {
				if _, err := bootstarpSerer.NewServer(cmd.Context(), bootstarpSerer.ServerOption{
					EnableEventBusConsumer: false,
				}); err != nil {
					return err
				}
				ctx := log.WithTraceID(cmd.Context())

				plEndpoint := new(internalentity.DFPrivateLinkEndpoint)
				dbErr := db.Transaction(func(tx *gorm.DB) error {
					return internalentity.NewDFPrivateLinkEndpointQuerySet(tx).
						PhaseEq(internalentity.PLEndpointPhaseAvailable).
						IDEq(internalentity.ID(dfPrivateLinkID)).
						One(plEndpoint)
				})
				if dbErr != nil {
					return fmt.Errorf("load available pl endpoint error: %w", dbErr)
				}

				logger := log.GetLogger(ctx).With(zap.Uint64("endpointID", dfPrivateLinkID))
				isUsing, err := connprofile.CheckIsPLEndpointBeingUsed(plEndpoint, logger)
				if err != nil {
					return fmt.Errorf("check pl endpoint is using error: %w", err)
				}
				if isUsing {
					return fmt.Errorf("pl endpoint is using, can not mark failed")
				}

				plEndpoint.Phase = internalentity.PLEndpointPhaseFailed
				plEndpoint.ErrMsg = "mark pl endpoint failed by cmd manually"
				dbErr = db.Transaction(func(tx *gorm.DB) error {
					return plEndpoint.Update(tx,
						internalentity.DFPrivateLinkEndpointDBSchema.Phase,
						internalentity.DFPrivateLinkEndpointDBSchema.ErrMsg)
				})
				if dbErr != nil {
					return fmt.Errorf("update pl endpoint error: %w", dbErr)
				}

				logger.Info("update pl endpoint successfully")
				return nil
			},
		}
		subCmd.Flags().Uint64VarP(&dfPrivateLinkID, "dfPrivateLinkID", "", 0, "")
		cmd.AddCommand(subCmd)
	}
}

func init() {
	cmd := &cobra.Command{
		Use:   "private_link",
		Short: "private link management",
		PreRunE: func(cmd *cobra.Command, args []string) error {
			return nil
		},
	}

	registerPrivateLinkJobFunc(cmd)
	jobCmd.AddCommand(cmd)
}
