package globalserverlesscli

import (
	"context"
	"errors"
	"fmt"
	"time"

	"braces.dev/errtrace"
	"github.com/samber/lo"
	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"google.golang.org/protobuf/types/known/emptypb"

	globalcommonv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/common/v1"
	globalserverlessv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/serverless/v1"
	regionalserverlessv1 "github.com/tidbcloud/tidb-management-service/api/spec/regional/serverless/v1"
)

// Deprecated: For newly-written tests, use mock in tests instead. Do not add mock data here.
type fakeImpl struct{}

var fakeRegion = &regionalserverlessv1.Region{
	Name:          "us-east-1",
	DisplayName:   "Fake Region Display Name us-east-1",
	CloudProvider: regionalserverlessv1.CloudProvider_CLOUD_PROVIDER_AWS,
}

func (c *fakeImpl) CreateCluster(
	ctx context.Context,
	in *globalserverlessv1.ServerlessServiceCreateRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.ServerlessServiceCreateResponse, error) {
	cluster := &globalserverlessv1.ServerlessServiceCluster{
		ClusterId: in.Id,
		Cluster: &regionalserverlessv1.ServerlessRegionalServiceClusterInfo{
			CreatedTs:                 time.Now().Unix(),
			UpdatedTs:                 time.Now().Unix(),
			DeleteTs:                  time.Now().Unix(),
			State:                     regionalserverlessv1.ClusterState_CLUSTER_STATE_READY,
			Version:                   "v1.0.0",
			UserPrefix:                "XXXYYYZZZ",
			EnhancedEncryptionEnabled: false, // default set false
			Region:                    fakeRegion,
		},
	}

	if in.Endpoints != nil && in.Endpoints.Public != nil {
		cluster.Cluster.Endpoints = &regionalserverlessv1.Endpoints{
			Public: &regionalserverlessv1.PublicEndpoint{
				Disabled: in.Endpoints.Public.Disabled,
			},
			Private: &regionalserverlessv1.PrivateEndpoint{},
		}
	}

	if in.EncryptionConfig != nil {
		cluster.Cluster.EnhancedEncryptionEnabled = in.EncryptionConfig.EnhancedEncryptionEnabled
	}

	return &globalserverlessv1.ServerlessServiceCreateResponse{
		Cluster: cluster,
	}, nil
}

func (c *fakeImpl) ListClusters(
	ctx context.Context,
	in *globalserverlessv1.ServerlessServiceListRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.ServerlessServiceListResponse, error) {
	// Only mock cluster id filter
	if in == nil || in.Filter == nil || len(in.Filter.ClusterIds) == 0 {
		return nil, errtrace.Wrap(errors.New("not supported"))
	}

	cs := lo.Map(in.Filter.ClusterIds, func(id string, _ int) *globalserverlessv1.ServerlessServiceCluster {
		return &globalserverlessv1.ServerlessServiceCluster{
			ClusterId: id,
			Cluster: &regionalserverlessv1.ServerlessRegionalServiceClusterInfo{
				CreatedTs:  time.Now().Unix(),
				UpdatedTs:  time.Now().Unix(),
				DeleteTs:   time.Now().Unix(),
				State:      regionalserverlessv1.ClusterState_CLUSTER_STATE_READY,
				Version:    "v1.0.0",
				UserPrefix: "XXXYYYZZZ",
				Endpoints: &regionalserverlessv1.Endpoints{
					Public:  &regionalserverlessv1.PublicEndpoint{},
					Private: &regionalserverlessv1.PrivateEndpoint{},
				},
				Region: fakeRegion,
			},
			BackupPolicy: &globalserverlessv1.AutomatedBackupPolicy{
				RetentionDays: 30,
				BackupTime:    "6:30",
			},
			SpendLimit: &globalserverlessv1.SpendLimit{
				Monthly: 0,
				Daily:   0,
			},
			UserStatus: globalserverlessv1.UserClusterStatus_USER_CLUSTER_STATUS_NORMAL,
		}
	})

	return &globalserverlessv1.ServerlessServiceListResponse{
		Items: cs,
		Total: uint32(len(cs)),
	}, nil
}

func (c *fakeImpl) CountClusters(
	ctx context.Context,
	in *globalserverlessv1.ServerlessServiceCountClustersRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.ServerlessServiceCountClustersResponse, error) {
	// Only mock cluster id filter
	resp, err := c.ListClusters(ctx, &globalserverlessv1.ServerlessServiceListRequest{Filter: in.Filter})
	if err != nil {
		return nil, errtrace.Wrap(err)
	}

	return &globalserverlessv1.ServerlessServiceCountClustersResponse{
		Count: int64(resp.Total),
	}, nil
}

func (c *fakeImpl) DeleteCluster(
	ctx context.Context,
	in *globalserverlessv1.ServerlessServiceDeleteRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.ServerlessServiceDeleteResponse, error) {
	return &globalserverlessv1.ServerlessServiceDeleteResponse{
		Cluster: &globalserverlessv1.ServerlessServiceCluster{
			ClusterId:  in.ClusterId,
			UserStatus: globalserverlessv1.UserClusterStatus_USER_CLUSTER_STATUS_DELETED,
			Cluster: &regionalserverlessv1.ServerlessRegionalServiceClusterInfo{
				CreatedTs:  time.Now().Unix(),
				UpdatedTs:  time.Now().Unix(),
				DeleteTs:   time.Now().Unix(),
				State:      regionalserverlessv1.ClusterState_CLUSTER_STATE_DELETING,
				Version:    "v1.0.0",
				UserPrefix: "XXXYYYZZZ",
				Region:     fakeRegion,
			},
		},
	}, nil
}

func (c *fakeImpl) UpdateCluster(
	ctx context.Context,
	in *globalserverlessv1.ServerlessServiceUpdateRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.ServerlessServiceUpdateResponse, error) {
	if in.Cluster.Cluster != nil {
		in.Cluster.Cluster.UpdatedTs = time.Now().Unix()
		in.Cluster.Cluster.State = regionalserverlessv1.ClusterState_CLUSTER_STATE_READY
		in.Cluster.Cluster.Version = "v1.0.0"
		in.Cluster.Cluster.UserPrefix = "XXXYYYZZZ"
	} else {
		in.Cluster.Cluster = &regionalserverlessv1.ServerlessRegionalServiceClusterInfo{
			CreatedTs:  time.Now().Unix(),
			UpdatedTs:  time.Now().Unix(),
			State:      regionalserverlessv1.ClusterState_CLUSTER_STATE_READY,
			Version:    "v1.0.0",
			UserPrefix: "XXXYYYZZZ",
			Region:     fakeRegion,
		}
	}

	return &globalserverlessv1.ServerlessServiceUpdateResponse{
		Cluster: in.Cluster,
	}, nil
}

func (c *fakeImpl) ChangeSqlUserPasswd(
	ctx context.Context,
	in *globalserverlessv1.ChangeSqlUserPasswdRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.ChangeSqlUserPasswdResponse, error) {
	return nil, errtrace.Wrap(status.Error(codes.Unimplemented, "not supported"))
}

func (c *fakeImpl) RotateRootPassword(
	ctx context.Context,
	in *globalserverlessv1.RotateRootPasswordRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.RotateRootPasswordResponse, error) {
	return &globalserverlessv1.RotateRootPasswordResponse{Rotating: true}, nil
}

func (c *fakeImpl) RedeemRootPassword(
	ctx context.Context,
	in *globalserverlessv1.RedeemRootPasswordRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.RedeemRootPasswordResponse, error) {
	return &globalserverlessv1.RedeemRootPasswordResponse{Rotating: false, Password: "fake-password"}, nil
}

func (c *fakeImpl) CreatePGBackup(
	ctx context.Context,
	in *globalserverlessv1.CreatePGBackupRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.CreatePGBackupResponse, error) {
	return nil, errtrace.Wrap(status.Error(codes.Unimplemented, "not supported"))
}

func (c *fakeImpl) ListPGBackups(
	ctx context.Context,
	in *globalserverlessv1.ListPGBackupsRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.ListPGBackupsResponse, error) {
	return nil, errtrace.Wrap(status.Error(codes.Unimplemented, "not supported"))
}

func (c *fakeImpl) GetPGBackup(
	ctx context.Context,
	in *globalserverlessv1.GetPGBackupRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.GetPGBackupResponse, error) {
	return nil, errtrace.Wrap(status.Error(codes.Unimplemented, "not supported"))
}

func (c *fakeImpl) GetPGBackupPolicy(
	ctx context.Context,
	in *globalserverlessv1.GetPGBackupPolicyRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.GetPGBackupPolicyResponse, error) {
	return nil, errtrace.Wrap(status.Error(codes.Unimplemented, "not supported"))
}

func (c *fakeImpl) UpdatePGBackupPolicy(
	ctx context.Context,
	in *globalserverlessv1.UpdatePGBackupPolicyRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.UpdatePGBackupPolicyResponse, error) {
	return nil, errtrace.Wrap(status.Error(codes.Unimplemented, "not supported"))
}

func (c *fakeImpl) RegisterCloudProvider(
	ctx context.Context,
	in *globalserverlessv1.CloudProviderServiceRegisterRequest,
	opts ...grpc.CallOption,
) (*globalcommonv1.CloudProvider, error) {
	return nil, errtrace.Wrap(status.Error(codes.Unimplemented, "not supported"))
}

func (c *fakeImpl) ListCloudProviders(
	ctx context.Context,
	in *globalserverlessv1.CloudProviderServiceListRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.CloudProviderServiceListResponse, error) {
	return nil, errtrace.Wrap(status.Error(codes.Unimplemented, "not supported"))
}

func (c *fakeImpl) ListRegions(
	ctx context.Context,
	in *globalserverlessv1.RegionServiceListRequest,
	opts ...grpc.CallOption,
) (*globalserverlessv1.RegionServiceListResponse, error) {
	return nil, errtrace.Wrap(status.Error(codes.Unimplemented, "not supported"))
}

func (c *fakeImpl) GetRegion(
	ctx context.Context,
	in *globalserverlessv1.RegionServiceGetRequest,
	opts ...grpc.CallOption,
) (*globalcommonv1.Region, error) {
	return &globalcommonv1.Region{
		Id:              in.RegionId,
		LogicalName:     in.RegionId.String(),
		CloudProviderId: in.CloudProviderId,
		DisplayName:     fmt.Sprintf("Fake Region Display Name %s", in.GetRegionId()),
	}, nil
}

func (c *fakeImpl) RegisterRegion(
	ctx context.Context,
	in *globalserverlessv1.RegionServiceRegisterRequest,
	opts ...grpc.CallOption,
) (*globalcommonv1.Region, error) {
	return nil, errtrace.Wrap(status.Error(codes.Unimplemented, "not supported"))
}

func (c *fakeImpl) UpdateRegion(
	ctx context.Context,
	in *globalserverlessv1.RegionServiceUpdateRequest,
	opts ...grpc.CallOption,
) (*globalcommonv1.Region, error) {
	return nil, errtrace.Wrap(status.Error(codes.Unimplemented, "not supported"))
}

func (c *fakeImpl) DeleteRegion(
	ctx context.Context,
	in *globalserverlessv1.RegionServiceDeleteRequest,
	opts ...grpc.CallOption,
) (*emptypb.Empty, error) {
	return nil, errtrace.Wrap(status.Error(codes.Unimplemented, "not supported"))
}

func (c *fakeImpl) CreateDataMigrationTask(ctx context.Context, taskId, sourceDsn, targetDsn string) error {
	return nil
}

func (c *fakeImpl) CheckDataMigrationTask(ctx context.Context, taskId string) (bool, error) {
	return true, nil
}
