package deploy

import (
	"context"

	"github.com/go-gormigrate/gormigrate/v2"
	"gorm.io/gorm"
)

func init() {
	registerMigrateRecord((*migrator).migrateCleanupBuckets20251125)
}

// cleanup internal/data bucket for shared pools
// this ops only apply bucket lifecycle rules.
func (m *migrator) migrateCleanupBuckets20251125(ctx context.Context) gormigrate.MigrateFunc {
	return func(db *gorm.DB) error {

		return InvokeRunMigrateWithRetry(ctx, func() error {
			return db.Transaction(func(tx *gorm.DB) error {
				// sharedPools, err := m.sharedPoolRepo.List(ctx, nil, true)
				// if err != nil {
				// 	return fmt.Errorf("failed to list shared pools: %w", err)
				// }

				// if len(sharedPools) == 0 {
				// 	tilog.PlainInfo("no shared pools found, skip migration")
				// 	return nil
				// }

				// // Use concurrent execution with limited concurrency
				// const maxConcurrency = 10
				// semaphore := make(chan struct{}, maxConcurrency)
				// var wg sync.WaitGroup
				// var mu sync.Mutex
				// var errors []error

				// for _, sharedPool := range sharedPools {
				// 	// only clean up buckets for deleted shared pools
				// 	if sharedPool.DeletedAt == nil {
				// 		tilog.Info(ctx, "shared pool is not deleted, skip", zap.String("sharedPoolId", sharedPool.GetId()))
				// 		continue
				// 	}

				// 	wg.Add(1)
				// 	go func(sp *entity.SharedPool) {
				// 		defer wg.Done()

				// 		// Acquire semaphore
				// 		semaphore <- struct{}{}
				// 		defer func() { <-semaphore }()

				// 		// only 15 days after deletion
				// 		if time.Since(*sp.DeletedAt) < 15*24*time.Hour {
				// 			tilog.Info(ctx, "shared pool deleted less than 15 days ago, skip delete data bucket", zap.String("sharedPoolId", sp.GetId()))
				// 		} else {
				// 			// apply bucket lifecycle rules
				// 			tilog.Info(ctx, "applying lifecycle rules for data bucket", zap.String("sharedPoolId", sp.GetId()))
				// 			if err := m.applyBucketLifecycleRules(ctx, entity.GetDataBucketId(sp.GetId(), sp.GetObjectStorage().GetRegion()), sp.GetDataplaneName()); err != nil {
				// 				tilog.Error(ctx, "failed to apply lifecycle rules for data bucket", zap.String("sharedPoolId", sp.GetId()), zap.Error(err))
				// 				mu.Lock()
				// 				errors = append(errors, fmt.Errorf("failed to apply lifecycle rules for data bucket for %s: %w", sp.GetId(), err))
				// 				mu.Unlock()
				// 			}
				// 		}

				// 		// apply bucket lifecycle rules for internal bucket
				// 		tilog.Info(ctx, "applying lifecycle rules for internal bucket", zap.String("sharedPoolId", sp.GetId()))
				// 		if err := m.applyBucketLifecycleRules(ctx, entity.GetInternalBucketId(sp.GetId(), sp.GetInternalStorage().GetRegion()), sp.GetDataplaneName()); err != nil {
				// 			tilog.Error(ctx, "failed to apply lifecycle rules for internal bucket", zap.String("sharedPoolId", sp.GetId()), zap.Error(err))
				// 			mu.Lock()
				// 			errors = append(errors, fmt.Errorf("failed to apply lifecycle rules for internal bucket for %s: %w", sp.GetId(), err))
				// 			mu.Unlock()
				// 		}

				// 		tilog.Info(ctx, "finished applying lifecycle rules for buckets", zap.String("sharedPoolId", sp.GetId()))
				// 	}(sharedPool)
				// }

				// // Wait for all goroutines to complete
				// wg.Wait()

				// // Log summary of errors if any
				// if len(errors) > 0 {
				// 	tilog.Error(ctx, "some bucket lifecycle rule applications failed", zap.Int("errorCount", len(errors)))
				// 	for _, err := range errors {
				// 		tilog.Error(ctx, "bucket lifecycle rule application error", zap.Error(err))
				// 	}
				// 	// Don't return error to allow migration to succeed even if some buckets fail
				// }
				return nil
			})
		})
	}
}

// func (m *migrator) applyBucketLifecycleRules(ctx context.Context, bucketId, dataplaneId string) error {

// 	_, err := m.dataplaneClient.GetBucket(ctx, &dplanemgrv1.GetBucketRequest{
// 		DataplaneId: dataplaneId,
// 		BucketId:    bucketId,
// 	})

// 	if err != nil {
// 		if status.Code(err) == codes.NotFound {
// 			tilog.Info(ctx, "bucket not found, skip delete", zap.String("bucketId", bucketId))
// 			return nil
// 		}
// 		tilog.Error(ctx, "failed to get bucket", zap.String("bucketId", bucketId), zap.Error(err))
// 		return fmt.Errorf("failed to get bucket: %w", err)
// 	}

// 	// check if lifecycle rules exist
// 	rules, err := m.dataplaneClient.GetLifecycleRules(ctx, &dplanemgrv1.GetLifecycleRulesRequest{
// 		DataplaneId: dataplaneId,
// 		BucketId:    bucketId,
// 	})

// 	if err != nil {
// 		tilog.Error(ctx, "failed to get lifecycle rules", zap.String("bucketId", bucketId), zap.Error(err))
// 		return fmt.Errorf("failed to get lifecycle rules: %w", err)
// 	}

// 	if len(rules.GetRules()) != 0 && rules.GetRules()[0].GetId() != "cleanup-bucket-rule" {
// 		tilog.Info(ctx, "lifecycle rules already exist for bucket, skip delete", zap.String("bucketId", bucketId))
// 		return nil
// 	}

// 	// set lifecycle rule to delete objects immediately (0 days = delete as soon as possible)
// 	if _, err = m.dataplaneClient.ApplyLifecycleRules(ctx, &dplanemgrv1.ApplyLifecycleRulesRequest{
// 		DataplaneId: dataplaneId,
// 		BucketId:    bucketId,
// 		Rules: []*dplanemgrv1.LifecycleRule{
// 			{
// 				Id:             "cleanup-bucket-rule",
// 				Enabled:        true,
// 				PrefixFilter:   "/",
// 				ExpirationDays: 1,
// 			},
// 		},
// 	}); err != nil {
// 		tilog.Error(ctx, "failed to apply lifecycle rules to bucket", zap.String("bucketId", bucketId), zap.Error(err))
// 		return fmt.Errorf("failed to apply lifecycle rules to bucket: %w", err)
// 	}

// 	// wait lifecycle rules to be applied
// 	ruleApplied := false
// 	for i := 0; i < 12; i++ {
// 		time.Sleep(5 * time.Second)

// 		rules, err := m.dataplaneClient.GetLifecycleRules(ctx, &dplanemgrv1.GetLifecycleRulesRequest{
// 			DataplaneId: dataplaneId,
// 			BucketId:    bucketId,
// 		})

// 		if err != nil {
// 			tilog.Error(ctx, "failed to get lifecycle rules", zap.String("bucketId", bucketId), zap.Int("attempt", i+1), zap.Error(err))
// 			continue
// 		}

// 		if rules.GetStatus() != dplanemgrv1.GetLifecycleRulesResponse_Synced {
// 			tilog.Info(ctx, "lifecycle rules not synced yet, waiting", zap.String("bucketId", bucketId), zap.Int("attempt", i+1))
// 			continue
// 		}

// 		// Check if our cleanup rule is present and enabled
// 		for _, rule := range rules.GetRules() {
// 			if rule.GetId() == "cleanup-bucket-rule" && rule.GetEnabled() {
// 				tilog.Info(ctx, "lifecycle rule applied successfully", zap.String("bucketId", bucketId))
// 				ruleApplied = true
// 				break
// 			}
// 		}

// 		if ruleApplied {
// 			break
// 		}
// 	}

// 	if !ruleApplied {
// 		tilog.Error(ctx, "lifecycle rules not applied after retries, will force delete bucket", zap.String("bucketId", bucketId))
// 	} else {
// 		tilog.Info(ctx, "lifecycle rules applied successfully, bucket will be cleaned up by scheduled tasks", zap.String("bucketId", bucketId))
// 	}

// 	// // Delete the bucket immediately after lifecycle rules are applied
// 	// // The actual data cleanup will be handled by the lifecycle rules asynchronously
// 	// _, err = m.dataplaneClient.DeleteBucket(ctx, &dplanemgrv1.DeleteBucketRequest{
// 	// 	DataplaneId: dataplaneId,
// 	// 	BucketId:    bucketId,
// 	// })
// 	// if err != nil {
// 	// 	return fmt.Errorf("failed to delete bucket %s: %w", bucketId, err)
// 	// }
// 	// tilog.Info(ctx, "bucket deleted successfully", zap.String("bucketId", bucketId))

// 	return nil
// }
