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 TestAssetAllocationRecordStore_Create(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	s := NewAssetAllocationRecordStore(tx, rdb)
	ctx := context.Background()

	record := &model.AssetAllocationRecord{
		AllocationNo:    "AL20260124100001",
		AllocationType:  constants.AssetAllocationTypeAllocate,
		AssetType:       constants.AssetTypeIotCard,
		AssetID:         1,
		AssetIdentifier: "89860012345678901234",
		FromOwnerType:   constants.OwnerTypePlatform,
		ToOwnerType:     constants.OwnerTypeShop,
		ToOwnerID:       10,
		OperatorID:      1,
	}

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

func TestAssetAllocationRecordStore_BatchCreate(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	s := NewAssetAllocationRecordStore(tx, rdb)
	ctx := context.Background()

	records := []*model.AssetAllocationRecord{
		{
			AllocationNo:    "AL20260124100010",
			AllocationType:  constants.AssetAllocationTypeAllocate,
			AssetType:       constants.AssetTypeIotCard,
			AssetID:         1,
			AssetIdentifier: "89860012345678901001",
			FromOwnerType:   constants.OwnerTypePlatform,
			ToOwnerType:     constants.OwnerTypeShop,
			ToOwnerID:       10,
			OperatorID:      1,
		},
		{
			AllocationNo:    "AL20260124100011",
			AllocationType:  constants.AssetAllocationTypeAllocate,
			AssetType:       constants.AssetTypeIotCard,
			AssetID:         2,
			AssetIdentifier: "89860012345678901002",
			FromOwnerType:   constants.OwnerTypePlatform,
			ToOwnerType:     constants.OwnerTypeShop,
			ToOwnerID:       10,
			OperatorID:      1,
		},
	}

	err := s.BatchCreate(ctx, records)
	require.NoError(t, err)

	for _, record := range records {
		assert.NotZero(t, record.ID)
	}

	t.Run("空列表不报错", func(t *testing.T) {
		err := s.BatchCreate(ctx, []*model.AssetAllocationRecord{})
		require.NoError(t, err)
	})
}

func TestAssetAllocationRecordStore_GetByID(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	s := NewAssetAllocationRecordStore(tx, rdb)
	ctx := context.Background()

	record := &model.AssetAllocationRecord{
		AllocationNo:    "AL20260124100003",
		AllocationType:  constants.AssetAllocationTypeAllocate,
		AssetType:       constants.AssetTypeIotCard,
		AssetID:         1,
		AssetIdentifier: "89860012345678903001",
		FromOwnerType:   constants.OwnerTypePlatform,
		ToOwnerType:     constants.OwnerTypeShop,
		ToOwnerID:       10,
		OperatorID:      1,
		Remark:          "测试备注",
	}
	require.NoError(t, s.Create(ctx, record))

	result, err := s.GetByID(ctx, record.ID)
	require.NoError(t, err)
	assert.Equal(t, record.AllocationNo, result.AllocationNo)
	assert.Equal(t, record.AssetIdentifier, result.AssetIdentifier)
	assert.Equal(t, "测试备注", result.Remark)
}

func TestAssetAllocationRecordStore_List(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	s := NewAssetAllocationRecordStore(tx, rdb)
	ctx := context.Background()

	shopID := uint(100)
	records := []*model.AssetAllocationRecord{
		{
			AllocationNo:    "AL20260124100004",
			AllocationType:  constants.AssetAllocationTypeAllocate,
			AssetType:       constants.AssetTypeIotCard,
			AssetID:         1,
			AssetIdentifier: "89860012345678904001",
			FromOwnerType:   constants.OwnerTypePlatform,
			ToOwnerType:     constants.OwnerTypeShop,
			ToOwnerID:       shopID,
			OperatorID:      1,
		},
		{
			AllocationNo:    "AL20260124100005",
			AllocationType:  constants.AssetAllocationTypeAllocate,
			AssetType:       constants.AssetTypeIotCard,
			AssetID:         2,
			AssetIdentifier: "89860012345678904002",
			FromOwnerType:   constants.OwnerTypeShop,
			FromOwnerID:     &shopID,
			ToOwnerType:     constants.OwnerTypeShop,
			ToOwnerID:       200,
			OperatorID:      2,
		},
		{
			AllocationNo:    "RC20260124100001",
			AllocationType:  constants.AssetAllocationTypeRecall,
			AssetType:       constants.AssetTypeIotCard,
			AssetID:         3,
			AssetIdentifier: "89860012345678904003",
			FromOwnerType:   constants.OwnerTypeShop,
			FromOwnerID:     &shopID,
			ToOwnerType:     constants.OwnerTypePlatform,
			ToOwnerID:       0,
			OperatorID:      1,
		},
	}
	require.NoError(t, s.BatchCreate(ctx, records))

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

	t.Run("按分配类型过滤", func(t *testing.T) {
		filters := map[string]any{"allocation_type": constants.AssetAllocationTypeAllocate}
		result, total, err := s.List(ctx, nil, filters)
		require.NoError(t, err)
		assert.Equal(t, int64(2), total)
		for _, r := range result {
			assert.Equal(t, constants.AssetAllocationTypeAllocate, r.AllocationType)
		}
	})

	t.Run("按分配单号过滤", func(t *testing.T) {
		filters := map[string]any{"allocation_no": "AL20260124100004"}
		result, total, err := s.List(ctx, nil, filters)
		require.NoError(t, err)
		assert.Equal(t, int64(1), total)
		assert.Equal(t, "AL20260124100004", result[0].AllocationNo)
	})

	t.Run("按资产标识模糊查询", func(t *testing.T) {
		filters := map[string]any{"asset_identifier": "904002"}
		result, total, err := s.List(ctx, nil, filters)
		require.NoError(t, err)
		assert.Equal(t, int64(1), total)
		assert.Contains(t, result[0].AssetIdentifier, "904002")
	})

	t.Run("按目标店铺过滤", func(t *testing.T) {
		filters := map[string]any{"to_shop_id": shopID}
		result, total, err := s.List(ctx, nil, filters)
		require.NoError(t, err)
		assert.Equal(t, int64(1), total)
		assert.Equal(t, shopID, result[0].ToOwnerID)
	})

	t.Run("按操作人过滤", func(t *testing.T) {
		filters := map[string]any{"operator_id": uint(2)}
		result, total, err := s.List(ctx, nil, filters)
		require.NoError(t, err)
		assert.Equal(t, int64(1), total)
		assert.Equal(t, uint(2), result[0].OperatorID)
	})
}

func TestAssetAllocationRecordStore_GenerateAllocationNo(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	s := NewAssetAllocationRecordStore(tx, rdb)
	ctx := context.Background()

	t.Run("分配单号前缀为AL", func(t *testing.T) {
		no := s.GenerateAllocationNo(ctx, constants.AssetAllocationTypeAllocate)
		assert.True(t, len(no) > 0)
		assert.Equal(t, "AL", no[:2])
	})

	t.Run("回收单号前缀为RC", func(t *testing.T) {
		no := s.GenerateAllocationNo(ctx, constants.AssetAllocationTypeRecall)
		assert.True(t, len(no) > 0)
		assert.Equal(t, "RC", no[:2])
	})
}
