package br

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/dataflow"
	"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/repository/br"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/cluster"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/encryptionkey"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/region"
	"github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/repository/resourcepool"
	resourcepoolservice "github.com/tidbcloud/tidb-management-service/nextgen-global-service/domain/service/resourcepool"
	"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"
	wf "github.com/tidbcloud/tidb-management-service/utilities/workflow"
)

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

type Service interface {
	ListBackups(
		ctx context.Context,
		req *globalngv1.ListBackupsRequest,
	) (*globalngv1.ListBackupsResponse, bizerr.BizError)
	DeleteBackup(ctx context.Context, backup *globalngv1.Backup) bizerr.BizError
	Restore(ctx context.Context, req *globalngv1.RestoreClusterRequest) bizerr.BizError
	TestClassicBackupAccess(
		ctx context.Context,
		req *globalngv1.TestClassicBackupAccessRequest,
	) (*globalngv1.TestClassicBackupAccessResponse, bizerr.BizError)
	RestoreStatus(
		ctx context.Context,
		req *globalngv1.RestoreStatusRequest,
	) (*globalngv1.RestoreStatusResponse, bizerr.BizError)
	StopRestore(ctx context.Context, req *globalngv1.StopRestoreClusterRequest) bizerr.BizError
	GetBackupSetting(
		ctx context.Context,
		req *globalngv1.GetBackupSettingRequest,
	) (*globalngv1.BackupSetting, bizerr.BizError)
	UpdateBackupSetting(
		ctx context.Context,
		req *globalngv1.UpdateBackupSettingRequest,
	) (*globalngv1.BackupSetting, bizerr.BizError)
	BackfillEssentialV2BackupSetting(ctx context.Context, clusterID uint64) (bool, bizerr.BizError)
	OverrideFlexibleBackupRetention(
		ctx context.Context,
		req *globalngv1.OverrideFlexibleBackupRetentionRequest,
	) (*globalngv1.BackupSetting, bizerr.BizError)
	ListNotCleanupBackupSettings(
		ctx context.Context,
		req *globalngv1.ListNotCleanupBackupSettingsRequest,
	) (*globalngv1.ListNotCleanupBackupSettingsResponse, bizerr.BizError)
	BatchUpdateBackupSettingNames(
		ctx context.Context,
		req *globalngv1.BatchUpdateBackupSettingNamesRequest,
	) bizerr.BizError
	ListBackupPolicies(
		ctx context.Context,
		req *globalngv1.ListBackupPoliciesRequest,
	) (*globalngv1.ListBackupPoliciesResponse, bizerr.BizError)
	CreateManualBackup(
		ctx context.Context,
		req *globalngv1.CreateManualBackupRequest,
	) (*globalngv1.CreateManualBackupResponse, bizerr.BizError)
	CreateFinalBackup(
		ctx context.Context,
		req *globalngv1.CreateFinalBackupRequest,
	) (*globalngv1.CreateFinalBackupResponse, bizerr.BizError)
	CreatePauseManualBackup(
		ctx context.Context,
		clusterID uint64,
		operationID string,
	) (*globalngv1.CreateManualBackupResponse, bizerr.BizError)
}

func NewService(
	cfg *config.Config,
	workflow wf.Workflow,
	transaction db.Transactioner,
	backupRepo br.BackupRepo,
	restoreRepo br.RestoreRepo,
	backupSettingRepo br.BackupSettingRepo,
	backupPolicyRepo br.BackupPolicyRepo,
	clusterRepo cluster.Repo,
	encryptionKeyRepo encryptionkey.Repo,
	regionRepo region.Repo,
	resourcePoolRepo resourcepool.Repo,
	resourcePoolService resourcepoolservice.Service,
	idGeneratorAdapter idgenerator.IDGenerator,
	regionalCli regionalserver.Client,
	dataflowCli dataflow.DataFlow,
	eventCommitter eventbus.WALCommitter,
) Service {
	return &serviceImpl{
		cfg:                      cfg,
		workflow:                 workflow,
		transaction:              transaction,
		backupRepo:               backupRepo,
		restoreRepo:              restoreRepo,
		backupSettingRepo:        backupSettingRepo,
		backupPolicyRepo:         backupPolicyRepo,
		clusterRepo:              clusterRepo,
		backupEncryptionResolver: NewResolver(encryptionKeyRepo),
		regionRepo:               regionRepo,
		resourcePoolRepo:         resourcePoolRepo,
		resourcePoolService:      resourcePoolService,
		idGeneratorAdapter:       idGeneratorAdapter,
		regionalCli:              regionalCli,
		eventCommitter:           eventCommitter,
		restoreAdapterPremium: &restoreFromPremiumAdapter{
			cfg:              cfg,
			workflow:         workflow,
			transaction:      transaction,
			backupRepo:       backupRepo,
			restoreRepo:      restoreRepo,
			clusterRepo:      clusterRepo,
			regionRepo:       regionRepo,
			regionalCli:      regionalCli,
			eventCommitter:   eventCommitter,
			resourcePoolRepo: resourcePoolRepo,
		},
		restoreAdapterDedicated: &restoreFromDedicatedAdapter{
			restoreAdapterClassicBase: restoreAdapterClassicBase{
				workflow:         workflow,
				clusterRepo:      clusterRepo,
				regionRepo:       regionRepo,
				regionalCli:      regionalCli,
				transaction:      transaction,
				restoreRepo:      restoreRepo,
				eventCommitter:   eventCommitter,
				resourcePoolRepo: resourcePoolRepo,
			},
			dataflowCli: dataflowCli,
		},
		restoreAdapterClassic: &restoreFromClassicAdapter{
			restoreAdapterClassicBase: restoreAdapterClassicBase{
				workflow:         workflow,
				clusterRepo:      clusterRepo,
				regionRepo:       regionRepo,
				regionalCli:      regionalCli,
				transaction:      transaction,
				restoreRepo:      restoreRepo,
				eventCommitter:   eventCommitter,
				resourcePoolRepo: resourcePoolRepo,
			},
		},
		restoreAdapterManual: &restoreFromManualAdapter{
			workflow:         workflow,
			transaction:      transaction,
			backupRepo:       backupRepo,
			restoreRepo:      restoreRepo,
			clusterRepo:      clusterRepo,
			regionRepo:       regionRepo,
			regionalCli:      regionalCli,
			eventCommitter:   eventCommitter,
			resourcePoolRepo: resourcePoolRepo,
		},
	}
}

type serviceImpl struct {
	cfg                      *config.Config
	workflow                 wf.Workflow
	transaction              db.Transactioner
	backupRepo               br.BackupRepo
	restoreRepo              br.RestoreRepo
	backupSettingRepo        br.BackupSettingRepo
	backupPolicyRepo         br.BackupPolicyRepo
	clusterRepo              cluster.Repo
	backupEncryptionResolver *Resolver
	regionRepo               region.Repo
	resourcePoolRepo         resourcepool.Repo
	resourcePoolService      resourcepoolservice.Service
	idGeneratorAdapter       idgenerator.IDGenerator
	regionalCli              regionalserver.Client
	eventCommitter           eventbus.WALCommitter
	restoreAdapterPremium    RestoreAdapter
	restoreAdapterDedicated  RestoreAdapter
	restoreAdapterClassic    RestoreAdapter
	restoreAdapterManual     RestoreAdapter
}
