package nextgenmetering

import (
	"context"
	"testing"
	"time"

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

func TestMeteringLoader_MetaRead(t *testing.T) {
	// Create test logger
	logger, err := zap.NewDevelopment()
	require.NoError(t, err)

	// Create test config for local filesystem
	conf := &config.ServiceConfig{
		Vendor:   "local", // Use local filesystem for testing
		LogLevel: "debug",
	}

	// Create and initialize loader
	loader := NewMeteringLoader(conf, logger)
	err = loader.Init()
	require.NoError(t, err)
	defer loader.Close()

	ctx := context.Background()

	t.Run("CreateMetaData", func(t *testing.T) {
		clusterID := "test-cluster-123"
		modifyTS := time.Now().Unix()
		metadata := map[string]interface{}{
			"cluster_name": "test-cluster",
			"node_count":   3,
			"cpu_cores":    8,
		}

		metaData := loader.CreateMetaData(clusterID, modifyTS, metadata)

		assert.Equal(t, clusterID, metaData.ClusterID)
		assert.Equal(t, modifyTS, metaData.ModifyTS)
		assert.Equal(t, metadata, metaData.Metadata)
	})

	t.Run("ListMetaDataFiles", func(t *testing.T) {
		prefix := "test-prefix/"

		// This may return an empty list for local filesystem without data
		files, err := loader.ListMetaDataFiles(ctx, prefix)

		// We don't expect an error, but files may be empty
		assert.NoError(t, err)
		assert.IsType(t, []string{}, files) // Check type instead of nil
	})

	t.Run("LoadMetaDataFile_NotFound", func(t *testing.T) {
		path := "non-existent-path"

		// This should return an error for non-existent file
		_, err := loader.LoadMetaDataFile(ctx, path)

		// We expect an error since the file doesn't exist
		assert.Error(t, err)
	})

	t.Run("LoadMetaDataByTypeWithCategory_NotFound", func(t *testing.T) {
		clusterID := "non-existent-cluster"
		timestamp := time.Now().Unix()

		// This should return nil (no error) for non-existent cluster with logic meta type
		// as file not found should be treated as a normal case, not an error
		result, err := loader.LoadMetaDataByTypeWithCategory(ctx, clusterID, "logic", "", timestamp)

		// We expect no error since file not found should return nil, not error
		assert.NoError(t, err)
		assert.Nil(t, result)
	})
}

func TestMeteringLoader_MetaReadInitialization(t *testing.T) {
	logger, err := zap.NewDevelopment()
	require.NoError(t, err)

	conf := &config.ServiceConfig{
		Vendor:   "local",
		LogLevel: "debug",
	}

	loader := NewMeteringLoader(conf, logger)

	// Before initialization, metaReader should be nil
	assert.Nil(t, loader.metaReader)

	// After initialization, metaReader should be set
	err = loader.Init()
	require.NoError(t, err)
	assert.NotNil(t, loader.metaReader)

	// Test that methods fail when not initialized
	uninitializedLoader := NewMeteringLoader(conf, logger)
	ctx := context.Background()

	_, err = uninitializedLoader.LoadMetaDataByTypeWithCategory(ctx, "test", "logic", "", time.Now().Unix())
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "not initialized")

	_, err = uninitializedLoader.LoadMetaDataFile(ctx, "test-path")
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "not initialized")

	_, err = uninitializedLoader.ListMetaDataFiles(ctx, "test-prefix")
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "not initialized")

	// Test that LoadMetaDataByTypeWithCategory properly handles non-FileNotFound errors
	_, err = uninitializedLoader.LoadMetaDataByTypeWithCategory(ctx, "test", "logic", "", time.Now().Unix())
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "not initialized")

	// Cleanup
	loader.Close()
}
