package backup

import (
	"context"
	"time"

	"github.com/tidbcloud/dataflow-service/app/container"
	"github.com/tidbcloud/dataflow-service/pkg/log"
	"go.uber.org/zap"
)

func DeleteExpiredAutoBackups(ctx context.Context) error {
	if err := container.Global().AutoBackupScheduler.DeleteExpiredAutoBackups(ctx); err != nil {
		log.GetLogger(ctx).Warn("dedicated delete expired auto backups error", zap.Error(err))
	}
	return nil
}

func ScheduleAutoBackup(ctx context.Context) error {
	if err := container.Global().AutoBackupScheduler.ScheduleAutoBackup(ctx); err != nil {
		log.GetLogger(ctx).Warn("dedicated schedule auto backup error", zap.Error(err))
	}
	return nil
}

func SyncLogBackupFromInfra(ctx context.Context) error {
	if err := container.Global().SyncLogBackupFromInfra.SyncAllLogBackup(ctx); err != nil {
		log.GetLogger(ctx).Warn("sync all log backup from infra error", zap.Error(err))
	}
	if err := container.Global().SyncLogBackupFromInfra.TruncateAllPendingLogBackups(ctx); err != nil {
		log.GetLogger(ctx).Warn("truncate all pending log backups from infra error", zap.Error(err))
	}
	return nil
}

func AutoBackupScheduleHealthCheck(ctx context.Context) error {
	if err := container.Global().BackupHealthChecker.CheckAutoBackupSchedule(ctx,
		autoBackupScheduleHealthCheckIntervalMinutes); err != nil {
		log.GetLogger(ctx).Error("check auto backup schedules execution error", zap.Error(err))
	}
	return nil
}

func SnapshotBackupCleanUpCheck(ctx context.Context) error {
	if err := container.Global().BackupHealthChecker.CheckSnapshotBackupCleanUp(ctx); err != nil {
		log.GetLogger(ctx).Error("check snapshot backup clean up execution error", zap.Error(err))
	}
	return nil
}

// ReconcileStuckRunningBackups verifies long-running `running`/`pending` backups
// against the dataplane Backup CR. If the CR has reached a final phase but mgmt
// missed it (e.g. because the create DAG already timed out), the mgmt row is
// updated so that the cleanup pipeline can proceed and orphan S3 data is removed.
func ReconcileStuckRunningBackups(ctx context.Context) error {
	if err := container.Global().BackupHealthChecker.ReconcileStuckRunningBackups(ctx); err != nil {
		log.GetLogger(ctx).Error("reconcile stuck running backups execution error", zap.Error(err))
	}
	return nil
}

// MarkBackupsFailedFromFailedDag scans stuck `running`/`pending` backups and
// looks up their snapshot create DAG instance in fastflow. If the DAG is in
// Failed/Canceled state, the mgmt row is marked Failed. Catches legacy backups
// whose DAG failed before the BeforeFail hook was deployed.
func MarkBackupsFailedFromFailedDag(ctx context.Context) error {
	if err := container.Global().BackupHealthChecker.MarkBackupsFailedFromFailedDag(ctx); err != nil {
		log.GetLogger(ctx).Error("mark backups failed from failed dag execution error", zap.Error(err))
	}
	return nil
}

// MarkBackupExportsFailedFromFailedDag scans stuck `running`/`pending` backup
// exports and looks up their create DAG instance in fastflow. If the DAG is in
// Failed/Canceled state, the export row is marked Failed. Catches exports
// orphaned when the create DAG was watchdog-killed before its own error handler
// ran, which otherwise keeps the BackupExportDurationTooLong alert firing.
func MarkBackupExportsFailedFromFailedDag(ctx context.Context) error {
	if err := container.Global().BackupHealthChecker.MarkBackupExportsFailedFromFailedDag(ctx); err != nil {
		log.GetLogger(ctx).Error("mark backup exports failed from failed dag execution error", zap.Error(err))
	}
	return nil
}

func CleanupExpiredClassicRestoreAccess(ctx context.Context) error {
	logger := log.GetLogger(ctx)
	logger.Info("cleanup expired classic restore access started")
	if err := container.Global().ClassicRestoreAccessModel.ReconcileExpired(ctx); err != nil {
		logger.Warn("cleanup expired classic restore access error", zap.Error(err))
	}
	logger.Info("cleanup expired classic restore access completed")
	return nil
}

func BackupNodeGroupAndNodePoolExpiredCheck(ctx context.Context) error {
	if err := container.Global().BackupHealthChecker.CheckBackupNodeGroupAndNodePoolCleanUp(ctx); err != nil {
		log.GetLogger(ctx).Error("fail to check snapshot backup node clean up", zap.Error(err))
	}
	return nil
}

func CalculateLogBackupSize(ctx context.Context) error {
	if err := container.Global().LogBackupSizeCalculator.CalculateAll(ctx); err != nil {
		log.GetLogger(ctx).Warn("calculate log backup size error", zap.Error(err))
	}
	return nil
}

func GenerateBackupBillingRecord(ctx context.Context) error {
	if err := container.Global().BackupBillingRecordGenerator.AggregateAllByCluster(ctx); err != nil {
		log.GetLogger(ctx).Warn("generate backup billing record error", zap.Error(err))
	}
	return nil
}

func GenerateLogBackupBillingRecord(ctx context.Context) error {
	if err := container.Global().LogBackupBillingRecordGenerator.AggregateAllByCluster(ctx); err != nil {
		log.GetLogger(ctx).Warn("generate log backup billing record error", zap.Error(err))
	}
	return nil
}

func CompactLogBackup(ctx context.Context) error {
	log.GetLogger(ctx).Info("=== CompactLogBackup worker started ===",
		zap.Time("timestamp", time.Now()),
		zap.String("worker", "compact-log-backup"))

	if err := container.Global().CompactBackupScheduler.CompactLogBackup(ctx); err != nil {
		log.GetLogger(ctx).Warn("compact log backup error", zap.Error(err))
	}

	log.GetLogger(ctx).Info("=== CompactLogBackup worker completed ===",
		zap.Time("timestamp", time.Now()),
		zap.String("worker", "compact-log-backup"))

	return nil
}
