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/model/dto"
	"github.com/break/junhong_cmp_fiber/internal/service/shop"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/tests/testutils"
)

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

	shopStore := postgres.NewShopStore(tx, rdb)
	accountStore := postgres.NewAccountStore(tx, rdb)
	service := shop.New(shopStore, accountStore)

	t.Run("创建一级店铺成功", func(t *testing.T) {
		ctx := createContextWithUserID(1)
		req := &dto.CreateShopRequest{
			ShopName:     "测试一级店铺",
			ShopCode:     "SHOP_L1_001",
			ParentID:     nil,
			ContactName:  "张三",
			ContactPhone: "13800000001",
			Province:     "北京市",
			City:         "北京市",
			District:     "朝阳区",
			Address:      "朝阳路100号",
			InitUsername: generateUniqueUsername("admin", t),
			InitPhone:    generateUniquePhone(),
			InitPassword: "password123",
		}

		result, err := service.Create(ctx, req)
		require.NoError(t, err)
		assert.NotZero(t, result.ID)
		assert.Equal(t, "测试一级店铺", result.ShopName)
		assert.Equal(t, "SHOP_L1_001", result.ShopCode)
		assert.Equal(t, 1, result.Level)
		assert.Nil(t, result.ParentID)
		assert.Equal(t, constants.StatusEnabled, result.Status)
	})

	t.Run("创建二级店铺成功", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		// 先创建一级店铺
		parent := &model.Shop{
			ShopName:     "一级店铺",
			ShopCode:     "PARENT_001",
			Level:        1,
			ContactName:  "李四",
			ContactPhone: "13800000002",
			Status:       constants.StatusEnabled,
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
		}
		err := shopStore.Create(ctx, parent)
		require.NoError(t, err)

		// 创建二级店铺
		req := &dto.CreateShopRequest{
			ShopName:     "测试二级店铺",
			ShopCode:     "SHOP_L2_001",
			ParentID:     &parent.ID,
			ContactName:  "王五",
			ContactPhone: "13800000003",
			InitUsername: generateUniqueUsername("agent", t),
			InitPhone:    generateUniquePhone(),
			InitPassword: "password123",
		}

		result, err := service.Create(ctx, req)
		require.NoError(t, err)
		assert.NotZero(t, result.ID)
		assert.Equal(t, 2, result.Level)
		assert.Equal(t, parent.ID, *result.ParentID)
	})

	t.Run("层级校验-创建第8级店铺应失败", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		// 创建 7 级店铺层级
		var shops []*model.Shop
		for i := 1; i <= 7; i++ {
			var parentID *uint
			if i > 1 {
				parentID = &shops[i-2].ID
			}

			shopModel := &model.Shop{
				ShopName:     testutils.GenerateUsername("店铺L", i),
				ShopCode:     testutils.GenerateUsername("LEVEL", i),
				ParentID:     parentID,
				Level:        i,
				ContactName:  "测试联系人",
				ContactPhone: testutils.GeneratePhone("138", i),
				Status:       constants.StatusEnabled,
				BaseModel: model.BaseModel{
					Creator: 1,
					Updater: 1,
				},
			}
			err := shopStore.Create(ctx, shopModel)
			require.NoError(t, err)
			shops = append(shops, shopModel)
		}

		// 验证已创建 7 级
		assert.Len(t, shops, 7)
		assert.Equal(t, 7, shops[6].Level)

		// 尝试创建第 8 级店铺（应该失败）
		req := &dto.CreateShopRequest{
			ShopName:     "第8级店铺",
			ShopCode:     "SHOP_L8_001",
			ParentID:     &shops[6].ID, // 第7级店铺的ID
			ContactName:  "测试",
			ContactPhone: "13800000008",
			InitUsername: generateUniqueUsername("level8", t),
			InitPhone:    generateUniquePhone(),
			InitPassword: "password123",
		}

		result, err := service.Create(ctx, req)
		assert.Error(t, err)
		assert.Nil(t, result)

		// 验证错误码
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok, "错误应该是 AppError 类型")
		assert.Equal(t, errors.CodeShopLevelExceeded, appErr.Code)
		assert.Contains(t, appErr.Message, "不能超过 7 级")
	})

	t.Run("店铺编号唯一性检查-重复编号应失败", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		// 创建第一个店铺
		req1 := &dto.CreateShopRequest{
			ShopName:     "店铺A",
			ShopCode:     "UNIQUE_CODE_001",
			ContactName:  "张三",
			ContactPhone: "13800000001",
			InitUsername: generateUniqueUsername("unique1", t),
			InitPhone:    generateUniquePhone(),
			InitPassword: "password123",
		}
		_, err := service.Create(ctx, req1)
		require.NoError(t, err)

		// 尝试创建相同编号的店铺（应该失败）
		req2 := &dto.CreateShopRequest{
			ShopName:     "店铺B",
			ShopCode:     "UNIQUE_CODE_001", // 重复编号
			ContactName:  "李四",
			ContactPhone: "13800000002",
			InitUsername: generateUniqueUsername("unique2", t),
			InitPhone:    generateUniquePhone(),
			InitPassword: "password123",
		}
		result, err := service.Create(ctx, req2)
		assert.Error(t, err)
		assert.Nil(t, result)

		// 验证错误码
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeShopCodeExists, appErr.Code)
		assert.Contains(t, appErr.Message, "编号已存在")
	})

	t.Run("上级店铺不存在应失败", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		nonExistentID := uint(99999)
		req := &dto.CreateShopRequest{
			ShopName:     "测试店铺",
			ShopCode:     "SHOP_INVALID_PARENT",
			ParentID:     &nonExistentID, // 不存在的上级店铺 ID
			ContactName:  "测试",
			ContactPhone: "13800000009",
			InitUsername: generateUniqueUsername("invalid", t),
			InitPhone:    generateUniquePhone(),
			InitPassword: "password123",
		}

		result, err := service.Create(ctx, req)
		assert.Error(t, err)
		assert.Nil(t, result)

		// 验证错误码
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeInvalidParentID, appErr.Code)
		assert.Contains(t, appErr.Message, "上级店铺不存在")
	})

	t.Run("未授权访问应失败", func(t *testing.T) {
		ctx := context.Background() // 没有用户 ID 的 context

		req := &dto.CreateShopRequest{
			ShopName:     "测试店铺",
			ShopCode:     "SHOP_UNAUTHORIZED",
			ContactName:  "测试",
			ContactPhone: "13800000010",
			InitUsername: generateUniqueUsername("unauth", t),
			InitPhone:    generateUniquePhone(),
			InitPassword: "password123",
		}

		result, err := service.Create(ctx, req)
		assert.Error(t, err)
		assert.Nil(t, result)

		// 验证错误码
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeUnauthorized, appErr.Code)
		assert.Contains(t, appErr.Message, "未授权")
	})
}

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

	shopStore := postgres.NewShopStore(tx, rdb)
	accountStore := postgres.NewAccountStore(tx, rdb)
	service := shop.New(shopStore, accountStore)

	t.Run("更新店铺信息成功", func(t *testing.T) {
		ctx := createContextWithUserID(1)

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

		// 更新店铺
		req := &dto.UpdateShopRequest{
			ShopName:     "更新后的店铺名称",
			ContactName:  "新联系人",
			ContactPhone: "13900000001",
			Province:     "上海市",
			City:         "上海市",
			District:     "浦东新区",
			Address:      "陆家嘴环路1000号",
			Status:       constants.StatusEnabled,
		}

		result, err := service.Update(ctx, shopModel.ID, req)
		require.NoError(t, err)
		assert.Equal(t, "更新后的店铺名称", result.ShopName)
		assert.Equal(t, "ORIGINAL_CODE", result.ShopCode)
		assert.Equal(t, "新联系人", result.ContactName)
		assert.Equal(t, "13900000001", result.ContactPhone)
		assert.Equal(t, "上海市", result.Province)
		assert.Equal(t, "上海市", result.City)
		assert.Equal(t, "浦东新区", result.District)
		assert.Equal(t, "陆家嘴环路1000号", result.Address)
	})

	t.Run("更新店铺编号-唯一性检查", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		// 创建两个店铺
		shop1 := &model.Shop{
			ShopName: "店铺1",
			ShopCode: "CODE_001",
			Level:    1,
			Status:   constants.StatusEnabled,
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
		}
		err := shopStore.Create(ctx, shop1)
		require.NoError(t, err)

		shop2 := &model.Shop{
			ShopName: "店铺2",
			ShopCode: "CODE_002",
			Level:    1,
			Status:   constants.StatusEnabled,
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
		}
		err = shopStore.Create(ctx, shop2)
		require.NoError(t, err)

		// 尝试更新 shop2 的名称为已存在的名称（应该成功，因为名称不需要唯一性）
		req := &dto.UpdateShopRequest{
			ShopName: "店铺1",
			Status:   constants.StatusEnabled,
		}

		result, err := service.Update(ctx, shop2.ID, req)
		require.NoError(t, err)
		assert.NotNil(t, result)
		assert.Equal(t, "店铺1", result.ShopName)
	})

	t.Run("更新不存在的店铺应失败", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		req := &dto.UpdateShopRequest{
			ShopName: "新名称",
			Status:   constants.StatusEnabled,
		}

		result, err := service.Update(ctx, 99999, req)
		assert.Error(t, err)
		assert.Nil(t, result)

		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeShopNotFound, appErr.Code)
	})

	t.Run("未授权访问应失败", func(t *testing.T) {
		ctx := context.Background()

		req := &dto.UpdateShopRequest{
			ShopName: "新名称",
			Status:   constants.StatusEnabled,
		}

		result, err := service.Update(ctx, 1, req)
		assert.Error(t, err)
		assert.Nil(t, result)

		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeUnauthorized, appErr.Code)
	})
}

// TestShopService_Disable 测试禁用店铺
func TestShopService_Disable(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	shopStore := postgres.NewShopStore(tx, rdb)
	accountStore := postgres.NewAccountStore(tx, rdb)
	service := shop.New(shopStore, accountStore)

	t.Run("禁用店铺成功", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		// 创建店铺
		shopModel := &model.Shop{
			ShopName: "待禁用店铺",
			ShopCode: "SHOP_TO_DISABLE",
			Level:    1,
			Status:   constants.StatusEnabled,
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
		}
		err := shopStore.Create(ctx, shopModel)
		require.NoError(t, err)
		assert.Equal(t, constants.StatusEnabled, shopModel.Status)

		// 禁用店铺
		err = service.Disable(ctx, shopModel.ID)
		require.NoError(t, err)

		// 验证状态已更新
		result, err := shopStore.GetByID(ctx, shopModel.ID)
		require.NoError(t, err)
		assert.Equal(t, constants.StatusDisabled, result.Status)
		assert.Equal(t, uint(1), result.Updater)
	})

	t.Run("禁用不存在的店铺应失败", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		err := service.Disable(ctx, 99999)
		assert.Error(t, err)

		// 验证错误码
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeShopNotFound, appErr.Code)
	})

	t.Run("未授权访问应失败", func(t *testing.T) {
		ctx := context.Background()

		err := service.Disable(ctx, 1)
		assert.Error(t, err)

		// 验证错误码
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeUnauthorized, appErr.Code)
	})
}

// TestShopService_Enable 测试启用店铺
func TestShopService_Enable(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	shopStore := postgres.NewShopStore(tx, rdb)
	accountStore := postgres.NewAccountStore(tx, rdb)
	service := shop.New(shopStore, accountStore)

	t.Run("启用店铺成功", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		// 创建启用状态的店铺
		shopModel := &model.Shop{
			ShopName: "待启用店铺",
			ShopCode: "SHOP_TO_ENABLE",
			Level:    1,
			Status:   constants.StatusEnabled,
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
		}
		err := shopStore.Create(ctx, shopModel)
		require.NoError(t, err)

		// 先禁用店铺
		shopModel.Status = constants.StatusDisabled
		err = shopStore.Update(ctx, shopModel)
		require.NoError(t, err)

		// 验证已禁用
		disabled, err := shopStore.GetByID(ctx, shopModel.ID)
		require.NoError(t, err)
		assert.Equal(t, constants.StatusDisabled, disabled.Status)

		// 启用店铺
		err = service.Enable(ctx, shopModel.ID)
		require.NoError(t, err)

		// 验证状态已更新为启用
		result, err := shopStore.GetByID(ctx, shopModel.ID)
		require.NoError(t, err)
		assert.Equal(t, constants.StatusEnabled, result.Status)
		assert.Equal(t, uint(1), result.Updater)
	})

	t.Run("启用不存在的店铺应失败", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		err := service.Enable(ctx, 99999)
		assert.Error(t, err)

		// 验证错误码
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeShopNotFound, appErr.Code)
	})

	t.Run("未授权访问应失败", func(t *testing.T) {
		ctx := context.Background()

		err := service.Enable(ctx, 1)
		assert.Error(t, err)

		// 验证错误码
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeUnauthorized, appErr.Code)
	})
}

// TestShopService_GetByID 测试获取店铺详情
func TestShopService_GetByID(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	shopStore := postgres.NewShopStore(tx, rdb)
	accountStore := postgres.NewAccountStore(tx, rdb)
	service := shop.New(shopStore, accountStore)

	t.Run("获取存在的店铺", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		// 创建店铺
		shopModel := &model.Shop{
			ShopName: "测试店铺",
			ShopCode: "TEST_SHOP_001",
			Level:    1,
			Status:   constants.StatusEnabled,
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
		}
		err := shopStore.Create(ctx, shopModel)
		require.NoError(t, err)

		// 获取店铺
		result, err := service.GetByID(ctx, shopModel.ID)
		require.NoError(t, err)
		assert.Equal(t, shopModel.ID, result.ID)
		assert.Equal(t, "测试店铺", result.ShopName)
		assert.Equal(t, "TEST_SHOP_001", result.ShopCode)
	})

	t.Run("获取不存在的店铺应失败", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		result, err := service.GetByID(ctx, 99999)
		assert.Error(t, err)
		assert.Nil(t, result)

		// 验证错误码
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeShopNotFound, appErr.Code)
	})
}

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

	shopStore := postgres.NewShopStore(tx, rdb)
	accountStore := postgres.NewAccountStore(tx, rdb)
	service := shop.New(shopStore, accountStore)

	t.Run("查询店铺列表", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		// 创建多个店铺
		for i := 1; i <= 5; i++ {
			shopModel := &model.Shop{
				ShopName: testutils.GenerateUsername("测试店铺", i),
				ShopCode: testutils.GenerateUsername("SHOP_LIST", i),
				Level:    1,
				Status:   constants.StatusEnabled,
				BaseModel: model.BaseModel{
					Creator: 1,
					Updater: 1,
				},
			}
			err := shopStore.Create(ctx, shopModel)
			require.NoError(t, err)
		}

		// 查询列表
		shops, total, err := service.List(ctx, nil, nil)
		require.NoError(t, err)
		assert.GreaterOrEqual(t, len(shops), 5)
		assert.GreaterOrEqual(t, total, int64(5))
	})
}

// TestShopService_GetSubordinateShopIDs 测试获取下级店铺 ID 列表
func TestShopService_GetSubordinateShopIDs(t *testing.T) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	shopStore := postgres.NewShopStore(tx, rdb)
	accountStore := postgres.NewAccountStore(tx, rdb)
	service := shop.New(shopStore, accountStore)

	t.Run("获取下级店铺 ID 列表", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		// 创建店铺层级
		shop1 := &model.Shop{
			ShopName: "一级店铺",
			ShopCode: "SUBORDINATE_L1",
			Level:    1,
			Status:   constants.StatusEnabled,
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
		}
		err := shopStore.Create(ctx, shop1)
		require.NoError(t, err)

		shop2 := &model.Shop{
			ShopName: "二级店铺",
			ShopCode: "SUBORDINATE_L2",
			ParentID: &shop1.ID,
			Level:    2,
			Status:   constants.StatusEnabled,
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
		}
		err = shopStore.Create(ctx, shop2)
		require.NoError(t, err)

		shop3 := &model.Shop{
			ShopName: "三级店铺",
			ShopCode: "SUBORDINATE_L3",
			ParentID: &shop2.ID,
			Level:    3,
			Status:   constants.StatusEnabled,
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
		}
		err = shopStore.Create(ctx, shop3)
		require.NoError(t, err)

		// 获取一级店铺的所有下级（包含自己）
		ids, err := service.GetSubordinateShopIDs(ctx, shop1.ID)
		require.NoError(t, err)
		assert.Contains(t, ids, shop1.ID)
		assert.Contains(t, ids, shop2.ID)
		assert.Contains(t, ids, shop3.ID)
		assert.Len(t, ids, 3)
	})
}

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

	shopStore := postgres.NewShopStore(tx, rdb)
	accountStore := postgres.NewAccountStore(tx, rdb)
	service := shop.New(shopStore, accountStore)

	t.Run("删除店铺成功", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		shopModel := &model.Shop{
			ShopName: "待删除店铺",
			ShopCode: "DELETE_001",
			Level:    1,
			Status:   constants.StatusEnabled,
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
		}
		err := shopStore.Create(ctx, shopModel)
		require.NoError(t, err)

		err = service.Delete(ctx, shopModel.ID)
		require.NoError(t, err)

		_, err = shopStore.GetByID(ctx, shopModel.ID)
		assert.Error(t, err)
	})

	t.Run("删除店铺并禁用关联账号", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		shopModel := &model.Shop{
			ShopName: "有账号的店铺",
			ShopCode: "DELETE_002",
			Level:    1,
			Status:   constants.StatusEnabled,
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
		}
		err := shopStore.Create(ctx, shopModel)
		require.NoError(t, err)

		account := &model.Account{
			BaseModel: model.BaseModel{
				Creator: 1,
				Updater: 1,
			},
			Username: testutils.GenerateUsername("agent", 1),
			Phone:    testutils.GeneratePhone("139", 1),
			Password: "hashedpassword123",
			UserType: constants.UserTypeAgent,
			ShopID:   &shopModel.ID,
			Status:   constants.StatusEnabled,
		}
		err = accountStore.Create(ctx, account)
		require.NoError(t, err)

		err = service.Delete(ctx, shopModel.ID)
		require.NoError(t, err)

		updatedAccount, err := accountStore.GetByID(ctx, account.ID)
		require.NoError(t, err)
		assert.Equal(t, constants.StatusDisabled, updatedAccount.Status)
	})

	t.Run("删除不存在的店铺应失败", func(t *testing.T) {
		ctx := createContextWithUserID(1)

		err := service.Delete(ctx, 99999)
		assert.Error(t, err)

		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeShopNotFound, appErr.Code)
	})

	t.Run("未授权访问应失败", func(t *testing.T) {
		ctx := context.Background()

		err := service.Delete(ctx, 1)
		assert.Error(t, err)

		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeUnauthorized, appErr.Code)
	})
}
