package backup

import (
	"context"

	"github.com/tidbcloud/dataflow-service/app/models/domain"
	"github.com/tidbcloud/dataflow-service/idl/pbgen/proto/dataflow"
	"github.com/tidbcloud/dataflow-service/pkg/account/accountdb"
	"github.com/tidbcloud/pkgv2/bizerr"
)

//nolint:interfacebloat
type BackupSettingModel interface {
	CreateBackupSetting(
		ctx context.Context, req *domain.CreateBackupSettingReqV2) bizerr.BizError

	DeleteBackupSetting(
		ctx context.Context, req *domain.DeleteBackupSettingReqV2) bizerr.BizError

	QueryBackupSetting(ctx context.Context, clusterId *uint64) (*domain.QueryBackupSettingRespV2, bizerr.BizError)
	ListBackupSetting(
		ctx context.Context, req *domain.ListBackupSettingReq,
	) (*domain.ListBackupSettingResp, bizerr.BizError)

	ModifyRegionSetting(
		ctx context.Context, req *domain.RegionSettingModificationReqV2,
	) (*domain.RegionSettingModificationRespV2, bizerr.BizError)

	ModifyReplicationRTC(ctx context.Context, req *domain.ReplicationRTCModificationReq) bizerr.BizError

	QueryMasterBucket(
		ctx context.Context, req *domain.QueryMasterBucketReqV2,
	) (*domain.QueryMasterBucketRespV2, bizerr.BizError)

	ModifyAutoBackupSetting(
		ctx context.Context, req *domain.ModifyAutoBackupSettingReq,
	) (*domain.ModifyAutoBackupSettingResp, bizerr.BizError)

	// modify pit backup setting spec for user
	// note the real log backup status is in table: PiTLogBackupSwitch , so we called  PitBackupSwitcher to modify it
	ModifyPitBackupSetting(ctx context.Context, req *domain.PitSettingModificationReq) bizerr.BizError

	QueryBackupRegionOptions(
		ctx context.Context, req *domain.QueryBackupRegionOptionsReq,
	) (*domain.QueryBackupRegionOptionsResp, bizerr.BizError)
	QueryBackupSettingForAPI(
		ctx context.Context, clusterId *uint64,
	) (*domain.QueryBackupSettingForAPIResp, bizerr.BizError)

	MarkBackupScheduleAsDeleted(
		ctx context.Context, req *domain.MarkBackupScheduleAsDeletedReq,
	) bizerr.BizError
}

// see more in https://pingcap.feishu.cn/wiki/QO70wnpnyikLDqknIcocgqqKnXd
type BackupCreateRouter interface {
	AsyncCreate(ctx context.Context, req *domain.AsyncCreateBackupReq) (*domain.AsyncCreateBackupResp, bizerr.BizError)
}

type SnapshotBackupModel interface {
	BackupCreateRouter
	AsyncDelete(ctx context.Context, req *domain.AsyncDeleteBackupReq) (*domain.AsyncDeleteBackupResp, bizerr.BizError)
	Query(ctx context.Context, req *domain.QueryBackupReq) (*domain.QueryBackupResp, bizerr.BizError)
	List(ctx context.Context, req *domain.ListBackupReq) (*domain.ListBackupResp, bizerr.BizError)
	CreateFinalBackup(ctx context.Context, req *domain.CreateFinalBackupReq) (backupId uint64, err error)
	ListRecycleBinClusters(
		ctx context.Context, req *domain.ListRecycleBinClustersReq,
	) (*domain.ListRecycleBinClustersResp, bizerr.BizError)
	ListRecycleBinClustersV2(
		ctx context.Context, req *domain.ListRecycleBinClustersV2Req,
	) (*domain.ListRecycleBinClustersResp, bizerr.BizError)
}

// Pit means only backup no restore
type PitBackupModel interface {
	BackupCreateRouter
	AsyncDeleteLogBackup(
		ctx context.Context, req *domain.DeleteLogBackupReq) (*domain.DeleteLogBackupResp, bizerr.BizError)
	ListPiTRTimeRanges(
		ctx context.Context, req *domain.PiTRTimeRangeListReq) (*domain.PiTRTimeRangeListResp, bizerr.BizError)
}

type PitBackupSwitcher interface {
	Enable(ctx context.Context, req *domain.EnablePitBackupReq) (*domain.EnablePitBackupResp, bizerr.BizError)
	Disable(
		ctx context.Context, req *domain.DisablePitBackupReq) (*domain.DisablePitBackupResp, bizerr.BizError)
	Restart(
		ctx context.Context, req *domain.RestartPitBackupReq) (*domain.RestartPitBackupResp, bizerr.BizError)
	CancelRestart(
		ctx context.Context, req *domain.CancelRestartPitBackupReq) bizerr.BizError
	GetOrCreatePitBackupSwitch(ctx context.Context, req *domain.SwitchPitBackupReq) (
		*domain.GetOrCreatePitBackupSwitchResp, bizerr.BizError)
}

type LogBackupLongTermSynchronizationFromInfra interface {
	SyncAllLogBackup(ctx context.Context) bizerr.BizError
	TruncateAllPendingLogBackups(ctx context.Context) bizerr.BizError
}

type LogBackupSizeCalculator interface {
	CalculateAll(ctx context.Context) bizerr.BizError
}

type BackupBillingRecordGenerator interface {
	AggregateAllByCluster(ctx context.Context) bizerr.BizError
}

type AutoBackupScheduler interface {
	ScheduleAutoBackup(ctx context.Context) bizerr.BizError
	DeleteExpiredAutoBackups(ctx context.Context) bizerr.BizError
}

type BackupHealthChecker interface {
	CheckAutoBackupSchedule(ctx context.Context, timeRangeInMinute int64) bizerr.BizError
	CheckSnapshotBackupCleanUp(ctx context.Context) bizerr.BizError
	CheckBackupNodeGroupAndNodePoolCleanUp(ctx context.Context) bizerr.BizError
	// ReconcileStuckRunningBackups scans backups whose mgmt status is still `running`
	// long after creation and reconciles them against the dataplane Backup CR.
	// If the CR has reached a final phase (Failed/Complete) but mgmt missed the update
	// (e.g. because the create DAG `sync_snapshot_backup_cr_status` action timed out),
	// the mgmt row is updated to the matching final status. Without this reconciler,
	// stuck `running` rows never trigger `clean_failed_snapshot_backup_storage` and
	// the S3 data leaks.
	ReconcileStuckRunningBackups(ctx context.Context) bizerr.BizError
	// MarkBackupsFailedFromFailedDag scans stuck `running`/`pending` backups and
	// looks up their associated snapshot create DAG instance in fastflow. If the
	// DAG is in Failed/Canceled state, the mgmt row is marked Failed with the DAG
	// reason recorded. This is the legacy/fallback path: it catches backups whose
	// DAG failed BEFORE the BeforeFail hook was deployed, and any case the hook
	// missed (e.g. process restarted between Status=Failed write and hook fire).
	MarkBackupsFailedFromFailedDag(ctx context.Context) bizerr.BizError
	// MarkBackupExportsFailedFromFailedDag is the backup_export analog of
	// MarkBackupsFailedFromFailedDag: it scans stuck `running`/`pending` backup
	// exports and, if their create DAG instance is in Failed/Canceled state,
	// marks the export row Failed. Without it an export orphaned by a
	// watchdog-killed create DAG (empty job_id, stuck running) keeps the
	// BackupExportDurationTooLong alert firing forever.
	MarkBackupExportsFailedFromFailedDag(ctx context.Context) bizerr.BizError
}

type CompactBackupModel interface {
	AsyncCreate(
		ctx context.Context, req *domain.AsyncCreateCompactBackupReq,
	) (*domain.AsyncCreateCompactBackupResp, bizerr.BizError)
	AsyncDelete(
		ctx context.Context, req *domain.AsyncDeleteCompactBackupReq,
	) (*domain.AsyncDeleteCompactBackupResp, bizerr.BizError)
	// SyncDeleteMigrations synchronously deletes the v1/migrations/ directory for the
	// given compact backup from object storage. Returns an error on failure so the
	// caller can propagate it for retry.
	SyncDeleteMigrations(ctx context.Context, compactBackupID uint64) bizerr.BizError
	// DeleteCompactionsSubDir synchronously deletes the compaction-specific subdirectory
	// v1/compactions/compact-{ID}/ from object storage.
	DeleteCompactionsSubDir(ctx context.Context, compactBackupID uint64) bizerr.BizError
}

type CompactBackupScheduler interface {
	CompactLogBackup(ctx context.Context) bizerr.BizError
}

type BackupExportModel interface {
	GetBackupExportProfile(
		ctx context.Context, req *domain.GetBackupExportProfileReq,
	) (*domain.GetBackupExportProfileResp, bizerr.BizError)
	CreateBackupExport(
		ctx context.Context, req *dataflow.CreateBackupExportReq, user *accountdb.User,
	) (uint64, bizerr.BizError)
	CancelBackupExport(ctx context.Context, req *dataflow.CancelBackupExportReq) bizerr.BizError
}
