package cluster

import (
	"context"

	"github.com/tidbcloud/pkgv2/db"
	"go.opentelemetry.io/otel"

	globalngv1 "github.com/tidbcloud/tidb-management-service/api/spec/global/nextgen/v1"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/awss3"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/billing"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/clusterproxy"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/dataflow"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/encryptionchange"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/eventbus"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/regionalserver"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/adapter/remoteencryptor"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/entity"
	auditlogrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/auditlog"
	brrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/br"
	repobyocvpcpeering "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/byocvpcpeering"
	clusterrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/cluster"
	bindingrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/clusterencryptionbinding"
	encryptionkeyrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/encryptionkey"
	exportrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/export"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/logredactionpolicy"
	passwordrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/password"
	privatelinkrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/privatelink"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/publicconnectionsetting"
	rcuquotarepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/rcuquota"
	regionrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/region"
	reservedcapacitytemplaterepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/reservedcapacitytemplate"
	resourcepoolrepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/resourcepool"
	tidbgrouprepo "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/tidbgroup"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/auditlog"
	brservice "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/br"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/encryptionkey"
	logredactionpolicysvc "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/logredactionpolicy"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/resourcepool"
	clusterworkflow "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/workflow"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/pkg/config"
	"github.com/tidbcloud/tidb-management-service/utilities/bizerr"
	"github.com/tidbcloud/tidb-management-service/utilities/idgenerator"
	"github.com/tidbcloud/tidb-management-service/utilities/workflow"
)

var tracer = otel.Tracer("domain.cluster")

type Service interface {
	Create(ctx context.Context, req *globalngv1.CreateClusterRequest) (*entity.Cluster, bizerr.BizError)
	List(ctx context.Context, req *globalngv1.ListClustersRequest) ([]*entity.Cluster, bizerr.BizError)
	Get(ctx context.Context, req *globalngv1.GetClusterRequest) (*entity.Cluster, bizerr.BizError)
	Delete(ctx context.Context, req *globalngv1.DeleteClusterRequest) (*entity.Cluster, bizerr.BizError)
	Update(ctx context.Context, req *globalngv1.UpdateClusterRequest) (*entity.Cluster, bizerr.BizError)
	EstimatePrice(ctx context.Context, req *globalngv1.EstimatePriceRequest) (*globalngv1.EstimatePriceResponse, bizerr.BizError)
	UpdateProjectId(ctx context.Context, clusterId, projectId uint64) bizerr.BizError
	ChangeRootPasswd(ctx context.Context, req *globalngv1.ChangeClusterPasswdRequest) bizerr.BizError
	GetProviderRole(
		ctx context.Context,
		req *globalngv1.GetProviderRoleRequest,
	) (*entity.ProviderRole, bizerr.BizError)
	GetCaCertificateDownloadUrl(ctx context.Context,
		request *globalngv1.GetCaCertificateDownloadUrlRequest,
	) (*entity.CaCertificateDownloadUrl, bizerr.BizError)
	ForceUpdateGatewayIdentity(ctx context.Context,
		req *globalngv1.ForceUpdateGatewayIdentityRequest,
	) bizerr.BizError
}

// Define methods for the cluster service here

func NewService(
	cfg *config.Config,
	flow workflow.Workflow,
	idGeneratorAdapter idgenerator.IDGenerator,
	transaction db.Transactioner,
	clusterRepo clusterrepo.Repo,
	tidbgroupRepo tidbgrouprepo.Repo,
	publicConnectionSettingRepo publicconnectionsetting.Repo,
	reservedCapacityTemplateRepo reservedcapacitytemplaterepo.Repo,
	byocVpcPeeringRepo repobyocvpcpeering.Repo,
	privatelinkRepo privatelinkrepo.Repo,
	regionRepo regionrepo.Repo,
	rcuQuotaRepo rcuquotarepo.Repo,
	resourcePoolRepo resourcepoolrepo.Repo,
	pauseOperationRepo resourcepoolrepo.PauseOperationRepo,
	passwordRepo passwordrepo.Repo,
	restoreRepo brrepo.RestoreRepo,
	backupRepo brrepo.BackupRepo,
	auditLogSettingRepo auditlogrepo.SettingRepo,
	auditLogFilterRuleRepo auditlogrepo.FilterRuleRepo,
	logRedactionPolicyRepo logredactionpolicy.Repo,
	backupSettingRepo brrepo.BackupSettingRepo,
	backupPolicyRepo brrepo.BackupPolicyRepo,
	backupService brservice.Service,
	exportRepo exportrepo.ExportRepo,
	committer eventbus.WALCommitter,
	regionalCli regionalserver.Client,
	dataflowCli dataflow.DataFlow,
	clusterProxyProvider clusterproxy.Provider,
	encryptor remoteencryptor.Client,
	auditLogSvc auditlog.Service,
	logRedactionPolicySvc logredactionpolicysvc.Service,
	resourcePoolSvc resourcepool.Service,
	s3PresignClient awss3.PresignClient,
	s3Client awss3.GetClient,
	billingCli billing.Client,
	encryptionKeySvc encryptionkey.Service,
	regionProviderIdentityRepo regionrepo.ProviderIdentityRepo,
	encryptionKeyRepo encryptionkeyrepo.Repo,
	bindingRepo bindingrepo.Repo,
	encryptionChangeExecutor encryptionchange.Executor,
) (Service, error) {
	if err := clusterworkflow.RegisterDags(
		flow,
		cfg,
		clusterRepo,
		tidbgroupRepo,
		publicConnectionSettingRepo,
		reservedCapacityTemplateRepo,
		byocVpcPeeringRepo,
		privatelinkRepo,
		regionRepo,
		resourcePoolRepo,
		pauseOperationRepo,
		passwordRepo,
		auditLogSettingRepo,
		auditLogFilterRuleRepo,
		logRedactionPolicyRepo,
		restoreRepo,
		backupRepo,
		backupSettingRepo,
		backupPolicyRepo,
		backupService,
		exportRepo,
		committer,
		regionalCli,
		dataflowCli,
		clusterProxyProvider,
		transaction,
		encryptor,
		auditLogSvc,
		logRedactionPolicySvc,
		resourcePoolSvc,
		encryptionKeyRepo,
		rcuQuotaRepo,
		bindingRepo,
		encryptionChangeExecutor,
		s3Client,
	); err != nil {
		return nil, err
	}
	return &serviceImpl{
		workflow:                     flow,
		transaction:                  transaction,
		clusterRepo:                  clusterRepo,
		tidbgroupRepo:                tidbgroupRepo,
		reservedCapacityTemplateRepo: reservedCapacityTemplateRepo,
		publicConnectionSettingRepo:  publicConnectionSettingRepo,
		byocVpcPeeringRepo:           byocVpcPeeringRepo,
		privatelinkRepo:              privatelinkRepo,
		regionRepo:                   regionRepo,
		rcuQuotaRepo:                 rcuQuotaRepo,
		resourcePoolRepo:             resourcePoolRepo,
		backupRepo:                   backupRepo,
		backupSettingRepo:            backupSettingRepo,
		auditLogSettingRepo:          auditLogSettingRepo,
		auditLogFilterRuleRepo:       auditLogFilterRuleRepo,
		logRedactionPolicyRepo:       logRedactionPolicyRepo,
		regionalCli:                  regionalCli,
		clusterProxyProvider:         clusterProxyProvider,
		idGeneratorAdapter:           idGeneratorAdapter,
		eventCommitter:               committer,
		encryptor:                    encryptor,
		cfg:                          cfg,
		resourcePoolSvc:              resourcePoolSvc,
		s3PresignClient:              s3PresignClient,
		billingCli:                   billingCli,
		encryptionKeySvc:             encryptionKeySvc,
		regionProviderIdentityRepo:   regionProviderIdentityRepo,
		encryptionKeyRepo:            encryptionKeyRepo,
		exportRepo:                   exportRepo,
		bindingRepo:                  bindingRepo,
	}, nil
}

type serviceImpl struct {
	// Add fields for the service implementation here
	workflow workflow.Workflow

	transaction                  db.Transactioner
	clusterRepo                  clusterrepo.Repo
	tidbgroupRepo                tidbgrouprepo.Repo
	reservedCapacityTemplateRepo reservedcapacitytemplaterepo.Repo
	publicConnectionSettingRepo  publicconnectionsetting.Repo
	byocVpcPeeringRepo           repobyocvpcpeering.Repo
	regionRepo                   regionrepo.Repo
	regionProviderIdentityRepo   regionrepo.ProviderIdentityRepo
	privatelinkRepo              privatelinkrepo.Repo
	rcuQuotaRepo                 rcuquotarepo.Repo
	resourcePoolRepo             resourcepoolrepo.Repo
	backupRepo                   brrepo.BackupRepo
	backupSettingRepo            brrepo.BackupSettingRepo
	auditLogSettingRepo          auditlogrepo.SettingRepo
	auditLogFilterRuleRepo       auditlogrepo.FilterRuleRepo
	logRedactionPolicyRepo       logredactionpolicy.Repo
	encryptionKeyRepo            encryptionkeyrepo.Repo
	bindingRepo                  bindingrepo.Repo

	clusterProxyProvider clusterproxy.Provider
	regionalCli          regionalserver.Client
	eventCommitter       eventbus.WALCommitter
	idGeneratorAdapter   idgenerator.IDGenerator
	encryptor            remoteencryptor.Client

	resourcePoolSvc  resourcepool.Service
	encryptionKeySvc encryptionkey.Service
	billingCli       billing.Client

	cfg             *config.Config
	s3PresignClient awss3.PresignClient
	exportRepo      exportrepo.ExportRepo
}
