package purchase_validation

import (
	"context"
	"testing"

	"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/pkg/errors"
	"github.com/break/junhong_cmp_fiber/tests/testutils"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func setupTestData(t *testing.T) (context.Context, *Service, *model.IotCard, *model.Device, *model.Package, *model.ShopSeriesAllocation) {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	iotCardStore := postgres.NewIotCardStore(tx, rdb)
	deviceStore := postgres.NewDeviceStore(tx, rdb)
	packageStore := postgres.NewPackageStore(tx)
	seriesAllocationStore := postgres.NewShopSeriesAllocationStore(tx)
	packageSeriesStore := postgres.NewPackageSeriesStore(tx)
	carrierStore := postgres.NewCarrierStore(tx)
	shopStore := postgres.NewShopStore(tx, rdb)

	ctx := context.Background()

	carrier := &model.Carrier{
		CarrierCode: "TEST_CARRIER_PV",
		CarrierName: "测试运营商",
		CarrierType: constants.CarrierTypeCMCC,
		Status:      constants.StatusEnabled,
	}
	require.NoError(t, carrierStore.Create(ctx, carrier))

	shop := &model.Shop{
		ShopName:  "测试店铺PV",
		ShopCode:  "TEST_SHOP_PV",
		Level:     1,
		Status:    constants.StatusEnabled,
		BaseModel: model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, shopStore.Create(ctx, shop))

	series := &model.PackageSeries{
		SeriesCode:  "TEST_SERIES_PV",
		SeriesName:  "测试套餐系列",
		Description: "测试用",
		Status:      constants.StatusEnabled,
		BaseModel:   model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, packageSeriesStore.Create(ctx, series))

	allocation := &model.ShopSeriesAllocation{
		ShopID:    shop.ID,
		SeriesID:  series.ID,
		Status:    constants.StatusEnabled,
		BaseModel: model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, seriesAllocationStore.Create(ctx, allocation))

	pkg := &model.Package{
		PackageCode:          "TEST_PKG_PV",
		PackageName:          "测试套餐",
		SeriesID:             series.ID,
		SuggestedRetailPrice: 9900,
		Status:               constants.StatusEnabled,
		ShelfStatus:          constants.ShelfStatusOn,
		BaseModel:            model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, packageStore.Create(ctx, pkg))

	shopIDPtr := &shop.ID
	card := &model.IotCard{
		ICCID:     "89860000000000000001",
		ShopID:    shopIDPtr,
		CarrierID: carrier.ID,
		SeriesID:  &series.ID,
		Status:    constants.StatusEnabled,
		BaseModel: model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, iotCardStore.Create(ctx, card))

	device := &model.Device{
		DeviceNo:  "DEV_TEST_PV_001",
		ShopID:    shopIDPtr,
		SeriesID:  &series.ID,
		Status:    constants.StatusEnabled,
		BaseModel: model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, deviceStore.Create(ctx, device))

	svc := New(tx, iotCardStore, deviceStore, packageStore, seriesAllocationStore)

	return ctx, svc, card, device, pkg, allocation
}

func TestPurchaseValidationService_ValidateCardPurchase(t *testing.T) {
	ctx, svc, card, _, pkg, _ := setupTestData(t)

	t.Run("验证成功", func(t *testing.T) {
		result, err := svc.ValidateCardPurchase(ctx, card.ID, []uint{pkg.ID})
		require.NoError(t, err)
		assert.NotNil(t, result.Card)
		assert.Equal(t, card.ID, result.Card.ID)
		assert.Len(t, result.Packages, 1)
		assert.Equal(t, pkg.SuggestedRetailPrice, result.TotalPrice)
	})

	t.Run("卡不存在", func(t *testing.T) {
		_, err := svc.ValidateCardPurchase(ctx, 99999, []uint{pkg.ID})
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeIotCardNotFound, appErr.Code)
	})

	t.Run("套餐列表为空", func(t *testing.T) {
		_, err := svc.ValidateCardPurchase(ctx, card.ID, []uint{})
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeInvalidParam, appErr.Code)
	})

	t.Run("套餐不存在", func(t *testing.T) {
		_, err := svc.ValidateCardPurchase(ctx, card.ID, []uint{99999})
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeInvalidParam, appErr.Code)
	})
}

func TestPurchaseValidationService_ValidateDevicePurchase(t *testing.T) {
	ctx, svc, _, device, pkg, _ := setupTestData(t)

	t.Run("验证成功", func(t *testing.T) {
		result, err := svc.ValidateDevicePurchase(ctx, device.ID, []uint{pkg.ID})
		require.NoError(t, err)
		assert.NotNil(t, result.Device)
		assert.Equal(t, device.ID, result.Device.ID)
		assert.Len(t, result.Packages, 1)
		assert.Equal(t, pkg.SuggestedRetailPrice, result.TotalPrice)
	})

	t.Run("设备不存在", func(t *testing.T) {
		_, err := svc.ValidateDevicePurchase(ctx, 99999, []uint{pkg.ID})
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeNotFound, appErr.Code)
	})

	t.Run("套餐列表为空", func(t *testing.T) {
		_, err := svc.ValidateDevicePurchase(ctx, device.ID, []uint{})
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeInvalidParam, appErr.Code)
	})
}

func TestPurchaseValidationService_GetPurchasePrice(t *testing.T) {
	ctx, svc, _, _, pkg, _ := setupTestData(t)

	t.Run("获取个人客户价格", func(t *testing.T) {
		price := svc.GetPurchasePrice(ctx, pkg, model.BuyerTypePersonal)
		assert.Equal(t, pkg.SuggestedRetailPrice, price)
	})

	t.Run("获取代理商价格", func(t *testing.T) {
		price := svc.GetPurchasePrice(ctx, pkg, model.BuyerTypeAgent)
		assert.Equal(t, pkg.SuggestedRetailPrice, price)
	})
}
