package postgres

import (
	"context"
	"testing"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/store"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/tests/testutils"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func TestShopPackageAllocationStore_Create(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	s := NewShopPackageAllocationStore(tx)
	ctx := context.Background()

	allocation := &model.ShopPackageAllocation{
		ShopID:       1,
		PackageID:    1,
		AllocationID: 1,
		CostPrice:    5000,
		Status:       constants.StatusEnabled,
	}

	err := s.Create(ctx, allocation)
	require.NoError(t, err)
	assert.NotZero(t, allocation.ID)
}

func TestShopPackageAllocationStore_GetByID(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	s := NewShopPackageAllocationStore(tx)
	ctx := context.Background()

	allocation := &model.ShopPackageAllocation{
		ShopID:       2,
		PackageID:    2,
		AllocationID: 1,
		CostPrice:    6000,
		Status:       constants.StatusEnabled,
	}
	require.NoError(t, s.Create(ctx, allocation))

	t.Run("查询存在的分配", func(t *testing.T) {
		result, err := s.GetByID(ctx, allocation.ID)
		require.NoError(t, err)
		assert.Equal(t, allocation.ShopID, result.ShopID)
		assert.Equal(t, allocation.PackageID, result.PackageID)
		assert.Equal(t, allocation.CostPrice, result.CostPrice)
	})

	t.Run("查询不存在的分配", func(t *testing.T) {
		_, err := s.GetByID(ctx, 99999)
		require.Error(t, err)
	})
}

func TestShopPackageAllocationStore_GetByShopAndPackage(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	s := NewShopPackageAllocationStore(tx)
	ctx := context.Background()

	allocation := &model.ShopPackageAllocation{
		ShopID:       3,
		PackageID:    3,
		AllocationID: 1,
		CostPrice:    7000,
		Status:       constants.StatusEnabled,
	}
	require.NoError(t, s.Create(ctx, allocation))

	t.Run("查询存在的店铺和套餐组合", func(t *testing.T) {
		result, err := s.GetByShopAndPackage(ctx, 3, 3)
		require.NoError(t, err)
		assert.Equal(t, allocation.ID, result.ID)
		assert.Equal(t, uint(3), result.ShopID)
		assert.Equal(t, uint(3), result.PackageID)
	})

	t.Run("查询不存在的组合", func(t *testing.T) {
		_, err := s.GetByShopAndPackage(ctx, 99, 99)
		require.Error(t, err)
	})
}

func TestShopPackageAllocationStore_Update(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	s := NewShopPackageAllocationStore(tx)
	ctx := context.Background()

	allocation := &model.ShopPackageAllocation{
		ShopID:       4,
		PackageID:    4,
		AllocationID: 1,
		CostPrice:    5000,
		Status:       constants.StatusEnabled,
	}
	require.NoError(t, s.Create(ctx, allocation))

	allocation.CostPrice = 8000
	err := s.Update(ctx, allocation)
	require.NoError(t, err)

	updated, err := s.GetByID(ctx, allocation.ID)
	require.NoError(t, err)
	assert.Equal(t, int64(8000), updated.CostPrice)
}

func TestShopPackageAllocationStore_Delete(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	s := NewShopPackageAllocationStore(tx)
	ctx := context.Background()

	allocation := &model.ShopPackageAllocation{
		ShopID:       5,
		PackageID:    5,
		AllocationID: 1,
		CostPrice:    5000,
		Status:       constants.StatusEnabled,
	}
	require.NoError(t, s.Create(ctx, allocation))

	err := s.Delete(ctx, allocation.ID)
	require.NoError(t, err)

	_, err = s.GetByID(ctx, allocation.ID)
	require.Error(t, err)
}

func TestShopPackageAllocationStore_List(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	s := NewShopPackageAllocationStore(tx)
	ctx := context.Background()

	allocations := []*model.ShopPackageAllocation{
		{ShopID: 10, PackageID: 10, AllocationID: 1, CostPrice: 5000, Status: constants.StatusEnabled},
		{ShopID: 11, PackageID: 11, AllocationID: 1, CostPrice: 6000, Status: constants.StatusEnabled},
		{ShopID: 12, PackageID: 12, AllocationID: 2, CostPrice: 7000, Status: constants.StatusEnabled},
	}
	for _, a := range allocations {
		require.NoError(t, s.Create(ctx, a))
	}
	allocations[2].Status = constants.StatusDisabled
	require.NoError(t, s.Update(ctx, allocations[2]))

	t.Run("查询所有分配", func(t *testing.T) {
		result, total, err := s.List(ctx, &store.QueryOptions{Page: 1, PageSize: 20}, nil)
		require.NoError(t, err)
		assert.GreaterOrEqual(t, total, int64(3))
		assert.GreaterOrEqual(t, len(result), 3)
	})

	t.Run("按店铺ID过滤", func(t *testing.T) {
		filters := map[string]interface{}{"shop_id": uint(10)}
		result, total, err := s.List(ctx, &store.QueryOptions{Page: 1, PageSize: 20}, filters)
		require.NoError(t, err)
		assert.GreaterOrEqual(t, total, int64(1))
		for _, a := range result {
			assert.Equal(t, uint(10), a.ShopID)
		}
	})

	t.Run("按套餐ID过滤", func(t *testing.T) {
		filters := map[string]interface{}{"package_id": uint(11)}
		result, total, err := s.List(ctx, &store.QueryOptions{Page: 1, PageSize: 20}, filters)
		require.NoError(t, err)
		assert.GreaterOrEqual(t, total, int64(1))
		for _, a := range result {
			assert.Equal(t, uint(11), a.PackageID)
		}
	})

	t.Run("按分配ID过滤", func(t *testing.T) {
		filters := map[string]interface{}{"allocation_id": uint(1)}
		result, total, err := s.List(ctx, &store.QueryOptions{Page: 1, PageSize: 20}, filters)
		require.NoError(t, err)
		assert.GreaterOrEqual(t, total, int64(2))
		for _, a := range result {
			assert.Equal(t, uint(1), a.AllocationID)
		}
	})

	t.Run("按状态过滤-启用状态值为1", func(t *testing.T) {
		filters := map[string]interface{}{"status": 1}
		result, total, err := s.List(ctx, &store.QueryOptions{Page: 1, PageSize: 20}, filters)
		require.NoError(t, err)
		assert.GreaterOrEqual(t, total, int64(2))
		for _, a := range result {
			assert.Equal(t, 1, a.Status)
		}
	})

	t.Run("按状态过滤-启用", func(t *testing.T) {
		filters := map[string]interface{}{"status": constants.StatusEnabled}
		result, total, err := s.List(ctx, &store.QueryOptions{Page: 1, PageSize: 20}, filters)
		require.NoError(t, err)
		assert.GreaterOrEqual(t, total, int64(2))
		for _, a := range result {
			assert.Equal(t, constants.StatusEnabled, a.Status)
		}
	})

	t.Run("分页查询", func(t *testing.T) {
		result, total, err := s.List(ctx, &store.QueryOptions{Page: 1, PageSize: 2}, nil)
		require.NoError(t, err)
		assert.GreaterOrEqual(t, total, int64(3))
		assert.LessOrEqual(t, len(result), 2)
	})

	t.Run("默认分页选项", func(t *testing.T) {
		result, _, err := s.List(ctx, nil, nil)
		require.NoError(t, err)
		assert.NotNil(t, result)
	})
}

func TestShopPackageAllocationStore_UpdateStatus(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	s := NewShopPackageAllocationStore(tx)
	ctx := context.Background()

	allocation := &model.ShopPackageAllocation{
		ShopID:       20,
		PackageID:    20,
		AllocationID: 1,
		CostPrice:    5000,
		Status:       constants.StatusEnabled,
	}
	require.NoError(t, s.Create(ctx, allocation))

	err := s.UpdateStatus(ctx, allocation.ID, constants.StatusDisabled, 1)
	require.NoError(t, err)

	updated, err := s.GetByID(ctx, allocation.ID)
	require.NoError(t, err)
	assert.Equal(t, constants.StatusDisabled, updated.Status)
	assert.Equal(t, uint(1), updated.Updater)
}
