package unit

import (
	"context"
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/tests/testutils"
)

// TestShopStore_Create 测试创建店铺
func TestShopStore_Create(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	store := postgres.NewShopStore(tx, rdb)
	ctx := context.Background()

	tests := []struct {
		name    string
		shop    *model.Shop
		wantErr bool
	}{
		{
			name: "创建一级店铺",
			shop: &model.Shop{
				ShopName:     "一级代理店铺",
				ShopCode:     "SHOP001",
				ParentID:     nil,
				Level:        1,
				ContactName:  "张三",
				ContactPhone: "13800000001",
				Province:     "北京市",
				City:         "北京市",
				District:     "朝阳区",
				Address:      "朝阳路100号",
				Status:       constants.StatusEnabled,
			},
			wantErr: false,
		},
		{
			name: "创建带父店铺的店铺",
			shop: &model.Shop{
				ShopName:     "二级代理店铺",
				ShopCode:     "SHOP002",
				Level:        2,
				ContactName:  "李四",
				ContactPhone: "13800000002",
				Status:       constants.StatusEnabled,
			},
			wantErr: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			tt.shop.BaseModel.Creator = 1
			tt.shop.BaseModel.Updater = 1

			err := store.Create(ctx, tt.shop)
			if tt.wantErr {
				assert.Error(t, err)
			} else {
				require.NoError(t, err)
				assert.NotZero(t, tt.shop.ID)
				assert.NotZero(t, tt.shop.CreatedAt)
				assert.NotZero(t, tt.shop.UpdatedAt)
			}
		})
	}
}

// TestShopStore_GetByID 测试根据 ID 查询店铺
func TestShopStore_GetByID(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	store := postgres.NewShopStore(tx, rdb)
	ctx := context.Background()

	// 创建测试店铺
	shop := &model.Shop{
		ShopName:     "测试店铺",
		ShopCode:     "TEST001",
		Level:        1,
		ContactName:  "测试联系人",
		ContactPhone: "13800000001",
		Status:       constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err := store.Create(ctx, shop)
	require.NoError(t, err)

	t.Run("查询存在的店铺", func(t *testing.T) {
		found, err := store.GetByID(ctx, shop.ID)
		require.NoError(t, err)
		assert.Equal(t, shop.ShopName, found.ShopName)
		assert.Equal(t, shop.ShopCode, found.ShopCode)
		assert.Equal(t, shop.Level, found.Level)
	})

	t.Run("查询不存在的店铺", func(t *testing.T) {
		_, err := store.GetByID(ctx, 99999)
		assert.Error(t, err)
	})
}

// TestShopStore_GetByCode 测试根据店铺编号查询
func TestShopStore_GetByCode(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	store := postgres.NewShopStore(tx, rdb)
	ctx := context.Background()

	// 创建测试店铺
	shop := &model.Shop{
		ShopName:     "测试店铺",
		ShopCode:     "UNIQUE001",
		Level:        1,
		ContactName:  "测试联系人",
		ContactPhone: "13800000001",
		Status:       constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err := store.Create(ctx, shop)
	require.NoError(t, err)

	t.Run("根据店铺编号查询", func(t *testing.T) {
		found, err := store.GetByCode(ctx, "UNIQUE001")
		require.NoError(t, err)
		assert.Equal(t, shop.ID, found.ID)
		assert.Equal(t, shop.ShopName, found.ShopName)
	})

	t.Run("查询不存在的店铺编号", func(t *testing.T) {
		_, err := store.GetByCode(ctx, "NONEXISTENT")
		assert.Error(t, err)
	})
}

// TestShopStore_Update 测试更新店铺
func TestShopStore_Update(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	store := postgres.NewShopStore(tx, rdb)
	ctx := context.Background()

	// 创建测试店铺
	shop := &model.Shop{
		ShopName:     "原始店铺名称",
		ShopCode:     "UPDATE001",
		Level:        1,
		ContactName:  "原联系人",
		ContactPhone: "13800000001",
		Status:       constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err := store.Create(ctx, shop)
	require.NoError(t, err)

	t.Run("更新店铺信息", func(t *testing.T) {
		shop.ShopName = "更新后的店铺名称"
		shop.ContactName = "新联系人"
		shop.ContactPhone = "13900000001"
		shop.Updater = 2

		err := store.Update(ctx, shop)
		require.NoError(t, err)

		// 验证更新
		found, err := store.GetByID(ctx, shop.ID)
		require.NoError(t, err)
		assert.Equal(t, "更新后的店铺名称", found.ShopName)
		assert.Equal(t, "新联系人", found.ContactName)
		assert.Equal(t, "13900000001", found.ContactPhone)
		assert.Equal(t, uint(2), found.Updater)
	})

	t.Run("更新店铺状态", func(t *testing.T) {
		shop.Status = constants.StatusDisabled
		err := store.Update(ctx, shop)
		require.NoError(t, err)

		found, err := store.GetByID(ctx, shop.ID)
		require.NoError(t, err)
		assert.Equal(t, constants.StatusDisabled, found.Status)
	})
}

// TestShopStore_Delete 测试软删除店铺
func TestShopStore_Delete(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	store := postgres.NewShopStore(tx, rdb)
	ctx := context.Background()

	// 创建测试店铺
	shop := &model.Shop{
		ShopName:     "待删除店铺",
		ShopCode:     "DELETE001",
		Level:        1,
		ContactName:  "测试",
		ContactPhone: "13800000001",
		Status:       constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err := store.Create(ctx, shop)
	require.NoError(t, err)

	t.Run("软删除店铺", func(t *testing.T) {
		err := store.Delete(ctx, shop.ID)
		require.NoError(t, err)

		// 验证已被软删除（GetByID 应该找不到）
		_, err = store.GetByID(ctx, shop.ID)
		assert.Error(t, err)
	})
}

// TestShopStore_List 测试查询店铺列表
func TestShopStore_List(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	store := postgres.NewShopStore(tx, rdb)
	ctx := context.Background()

	// 创建多个测试店铺
	for i := 1; i <= 5; i++ {
		shop := &model.Shop{
			ShopName:     testutils.GenerateUsername("测试店铺", i),
			ShopCode:     testutils.GenerateUsername("SHOP", i),
			Level:        1,
			ContactName:  "测试联系人",
			ContactPhone: testutils.GeneratePhone("138", i),
			Status:       constants.StatusEnabled,
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
		}
		err := store.Create(ctx, shop)
		require.NoError(t, err)
	}

	t.Run("分页查询", func(t *testing.T) {
		shops, total, err := store.List(ctx, nil, nil)
		require.NoError(t, err)
		assert.GreaterOrEqual(t, len(shops), 5)
		assert.GreaterOrEqual(t, total, int64(5))
	})

	t.Run("带过滤条件查询", func(t *testing.T) {
		filters := map[string]interface{}{
			"level": 1,
		}
		shops, _, err := store.List(ctx, nil, filters)
		require.NoError(t, err)
		for _, shop := range shops {
			assert.Equal(t, 1, shop.Level)
		}
	})
}

// TestShopStore_GetSubordinateShopIDs 测试递归查询下级店铺 ID
func TestShopStore_GetSubordinateShopIDs(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	store := postgres.NewShopStore(tx, rdb)
	ctx := context.Background()

	// 创建店铺层级结构
	// Level 1
	shop1 := &model.Shop{
		ShopName:     "一级店铺",
		ShopCode:     "L1_001",
		ParentID:     nil,
		Level:        1,
		ContactName:  "一级联系人",
		ContactPhone: "13800000001",
		Status:       constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err := store.Create(ctx, shop1)
	require.NoError(t, err)

	// Level 2 - 子店铺 1
	shop2_1 := &model.Shop{
		ShopName:     "二级店铺1",
		ShopCode:     "L2_001",
		ParentID:     &shop1.ID,
		Level:        2,
		ContactName:  "二级联系人1",
		ContactPhone: "13800000002",
		Status:       constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err = store.Create(ctx, shop2_1)
	require.NoError(t, err)

	// Level 2 - 子店铺 2
	shop2_2 := &model.Shop{
		ShopName:     "二级店铺2",
		ShopCode:     "L2_002",
		ParentID:     &shop1.ID,
		Level:        2,
		ContactName:  "二级联系人2",
		ContactPhone: "13800000003",
		Status:       constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err = store.Create(ctx, shop2_2)
	require.NoError(t, err)

	// Level 3 - 孙店铺
	shop3 := &model.Shop{
		ShopName:     "三级店铺",
		ShopCode:     "L3_001",
		ParentID:     &shop2_1.ID,
		Level:        3,
		ContactName:  "三级联系人",
		ContactPhone: "13800000004",
		Status:       constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err = store.Create(ctx, shop3)
	require.NoError(t, err)

	t.Run("查询一级店铺的所有下级（包含自己）", func(t *testing.T) {
		ids, err := store.GetSubordinateShopIDs(ctx, shop1.ID)
		require.NoError(t, err)
		// 应该包含自己(shop1)和所有下级(shop2_1, shop2_2, shop3)
		assert.Contains(t, ids, shop1.ID)
		assert.Contains(t, ids, shop2_1.ID)
		assert.Contains(t, ids, shop2_2.ID)
		assert.Contains(t, ids, shop3.ID)
		assert.Len(t, ids, 4)
	})

	t.Run("查询二级店铺的下级（包含自己）", func(t *testing.T) {
		ids, err := store.GetSubordinateShopIDs(ctx, shop2_1.ID)
		require.NoError(t, err)
		// 应该包含自己(shop2_1)和下级(shop3)
		assert.Contains(t, ids, shop2_1.ID)
		assert.Contains(t, ids, shop3.ID)
		assert.Len(t, ids, 2)
	})

	t.Run("查询没有下级的店铺（只返回自己）", func(t *testing.T) {
		ids, err := store.GetSubordinateShopIDs(ctx, shop3.ID)
		require.NoError(t, err)
		// 应该只包含自己
		assert.Contains(t, ids, shop3.ID)
		assert.Len(t, ids, 1)
	})

	t.Run("验证 Redis 缓存", func(t *testing.T) {
		// 第一次查询会写入缓存
		ids1, err := store.GetSubordinateShopIDs(ctx, shop1.ID)
		require.NoError(t, err)

		// 第二次查询应该从缓存读取（结果相同）
		ids2, err := store.GetSubordinateShopIDs(ctx, shop1.ID)
		require.NoError(t, err)

		assert.Equal(t, ids1, ids2)
		assert.Len(t, ids2, 4) // 包含自己+3个下级
	})
}

// TestShopStore_UniqueConstraints 测试唯一约束
func TestShopStore_UniqueConstraints(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	store := postgres.NewShopStore(tx, rdb)
	ctx := context.Background()

	// 创建测试店铺
	shop := &model.Shop{
		ShopName:     "唯一测试店铺",
		ShopCode:     "UNIQUE_CODE",
		Level:        1,
		ContactName:  "测试",
		ContactPhone: "13800000001",
		Status:       constants.StatusEnabled,
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
	}
	err := store.Create(ctx, shop)
	require.NoError(t, err)

	t.Run("重复店铺编号应失败", func(t *testing.T) {
		duplicate := &model.Shop{
			ShopName:     "另一个店铺",
			ShopCode:     "UNIQUE_CODE", // 重复
			Level:        1,
			ContactName:  "测试",
			ContactPhone: "13800000002",
			Status:       constants.StatusEnabled,
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
		}
		err := store.Create(ctx, duplicate)
		assert.Error(t, err)
	})
}
