package nextgenmetering

import (
	"testing"
	"time"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"github.com/tidbcloud/metering/pkg/common/models"
	"go.uber.org/zap"
)

func TestSKUHandlerRegistry_ManualBackup(t *testing.T) {
	registry := NewSKUHandlerRegistry(newTestSKUGenerator(t), zap.NewNop())

	t.Run("premium supports manual backup", func(t *testing.T) {
		handler, ok := registry.GetHandler(models.PlanPremium, models.NextGenCategoryManualBackup)
		require.True(t, ok)
		assert.IsType(t, &PremiumManualBackupHandler{}, handler)
	})

	t.Run("reserved supports manual backup", func(t *testing.T) {
		handler, ok := registry.GetHandler(models.PlanReserved, models.NextGenCategoryManualBackup)
		require.True(t, ok)
		assert.IsType(t, &PremiumManualBackupHandler{}, handler)
	})

	t.Run("essential supports manual backup", func(t *testing.T) {
		handler, ok := registry.GetHandler(models.PlanEssential, models.NextGenCategoryManualBackup)
		require.True(t, ok)
		assert.IsType(t, &EssentialManualBackupHandler{}, handler)
	})

	t.Run("byoc does not support manual backup", func(t *testing.T) {
		_, ok := registry.GetHandler(models.PlanBYOC, models.NextGenCategoryManualBackup)
		assert.False(t, ok)
	})
}

func TestSKUHandlerRegistry_ShouldProcessCategory(t *testing.T) {
	registry := NewSKUHandlerRegistry(newTestSKUGenerator(t), zap.NewNop())

	assert.True(t, registry.ShouldProcessCategory(models.PlanPremium, models.NextGenCategoryResourceManager))
	assert.True(t, registry.ShouldProcessCategory(models.PlanReserved, models.NextGenCategoryManualBackup))
	assert.False(t, registry.ShouldProcessCategory(models.PlanEssential, models.NextGenCategoryDXF))
	assert.False(t, registry.ShouldProcessCategory("unknown-plan", models.NextGenCategoryResourceManager))
}

func TestSKUHandlerRegistry_FlexBackup(t *testing.T) {
	registry := NewSKUHandlerRegistry(newTestSKUGenerator(t), zap.NewNop())

	t.Run("premium supports flex backup", func(t *testing.T) {
		handler, ok := registry.GetHandler(models.PlanPremium, models.NextGenCategoryFlexBackup)
		require.True(t, ok)
		assert.IsType(t, &PremiumFlexBackupHandler{}, handler)
	})

	t.Run("reserved supports flex backup", func(t *testing.T) {
		handler, ok := registry.GetHandler(models.PlanReserved, models.NextGenCategoryFlexBackup)
		require.True(t, ok)
		assert.IsType(t, &PremiumFlexBackupHandler{}, handler)
	})

	t.Run("essential supports flex backup", func(t *testing.T) {
		handler, ok := registry.GetHandler(models.PlanEssential, models.NextGenCategoryFlexBackup)
		require.True(t, ok)
		assert.IsType(t, &EssentialFlexBackupHandler{}, handler)
	})

	t.Run("byoc does not support flex backup", func(t *testing.T) {
		_, ok := registry.GetHandler(models.PlanBYOC, models.NextGenCategoryFlexBackup)
		assert.False(t, ok)
	})
}

func TestPremiumHandlers_DelegateToGenerator(t *testing.T) {
	gen := newTestSKUGenerator(t)
	params := &GenerateSKUParams{
		ClusterID:      "cluster-1",
		SharedPoolID:   "shared-1",
		TenantID:       6000,
		Timestamp:      1700000,
		CloudProvider:  "aws",
		Region:         "ap-south-1",
		Plan:           models.PlanPremium,
		EnrichmentData: map[string]interface{}{},
		Now:            time.Unix(1700000, 0),
	}

	t.Run("dfs stats handler delegates to generator", func(t *testing.T) {
		dataPoint := map[string]interface{}{
			models.NextGenMeteringWrittenBytes: map[string]interface{}{
				"value": uint64(2048),
				"unit":  "Bytes",
			},
		}
		records, err := NewPremiumDFSStatsHandler(gen).GenerateSKUs(dataPoint, params)
		require.NoError(t, err)
		require.Len(t, records, 1)
		assert.Equal(t, "backup-storage:aws:ap-south-1:premium:auto", records[0].Unit)
	})

	t.Run("manual backup handler delegates to generator", func(t *testing.T) {
		dataPoint := map[string]interface{}{
			models.NextGenMeteringBackupSizeGB: map[string]interface{}{
				"value": uint64(16),
				"unit":  "GB",
			},
		}
		records, err := NewPremiumManualBackupHandler(gen).GenerateSKUs(dataPoint, params)
		require.NoError(t, err)
		require.Len(t, records, 1)
		assert.Equal(t, "backup-storage:aws:ap-south-1:premium:manual", records[0].Unit)
	})

	t.Run("flex backup handler delegates to generator", func(t *testing.T) {
		dataPoint := map[string]interface{}{
			models.NextGenMeteringBackupSizeGB: map[string]interface{}{
				"value": uint64(16),
				"unit":  "GB",
			},
		}
		records, err := NewPremiumFlexBackupHandler(gen).GenerateSKUs(dataPoint, params)
		require.NoError(t, err)
		require.Len(t, records, 1)
		assert.Equal(t, "backup-storage:aws:ap-south-1:premium:daily", records[0].Unit)
	})
}
