package order

import (
	"context"
	"testing"

	"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/purchase_validation"
	"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/pkg/middleware"
	"github.com/break/junhong_cmp_fiber/tests/testutils"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/zap"
)

type testEnv struct {
	ctx        context.Context
	svc        *Service
	card       *model.IotCard
	device     *model.Device
	pkg        *model.Package
	shop       *model.Shop
	wallet     *model.Wallet
	allocation *model.ShopSeriesAllocation
}

func setupOrderTestEnv(t *testing.T) *testEnv {
	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)
	orderStore := postgres.NewOrderStore(tx, rdb)
	orderItemStore := postgres.NewOrderItemStore(tx, rdb)
	walletStore := postgres.NewWalletStore(tx, rdb)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

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

	shop := &model.Shop{
		ShopName:  "测试店铺ORDER",
		ShopCode:  "TEST_SHOP_ORDER",
		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_ORDER",
		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_ORDER",
		PackageName:          "测试套餐",
		SeriesID:             series.ID,
		PackageType:          "formal",
		DurationMonths:       1,
		DataAmountMB:         1024,
		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:     "89860000000000000002",
		ShopID:    shopIDPtr,
		CarrierID: carrier.ID,
		SeriesID:  &allocation.SeriesID,
		Status:    constants.StatusEnabled,
		BaseModel: model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, iotCardStore.Create(ctx, card))

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

	wallet := &model.Wallet{
		ResourceType: "shop",
		ResourceID:   shop.ID,
		WalletType:   "main",
		Balance:      100000,
		Version:      1,
		BaseModel:    model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, tx.Create(wallet).Error)

	purchaseValidationSvc := purchase_validation.New(tx, iotCardStore, deviceStore, packageStore, seriesAllocationStore)
	logger := zap.NewNop()
	orderSvc := New(tx, orderStore, orderItemStore, walletStore, purchaseValidationSvc, nil, seriesAllocationStore, iotCardStore, deviceStore, nil, nil, logger)

	userCtx := middleware.SetUserContext(ctx, &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypeAgent,
		ShopID:   shop.ID,
	})

	return &testEnv{
		ctx:        userCtx,
		svc:        orderSvc,
		card:       card,
		device:     device,
		pkg:        pkg,
		shop:       shop,
		wallet:     wallet,
		allocation: allocation,
	}
}

func TestOrderService_Create(t *testing.T) {
	env := setupOrderTestEnv(t)

	t.Run("创建单卡订单成功", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &env.card.ID,
			PackageIDs:    []uint{env.pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}

		resp, err := env.svc.Create(env.ctx, req, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)
		assert.NotZero(t, resp.ID)
		assert.Contains(t, resp.OrderNo, "ORD")
		assert.Equal(t, model.OrderTypeSingleCard, resp.OrderType)
		assert.Equal(t, model.BuyerTypeAgent, resp.BuyerType)
		assert.Equal(t, env.shop.ID, resp.BuyerID)
		assert.Equal(t, env.pkg.SuggestedRetailPrice, resp.TotalAmount)
		assert.Equal(t, model.PaymentStatusPending, resp.PaymentStatus)
		assert.Len(t, resp.Items, 1)
	})

	t.Run("创建设备订单成功", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeDevice,
			DeviceID:      &env.device.ID,
			PackageIDs:    []uint{env.pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}

		resp, err := env.svc.Create(env.ctx, req, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)
		assert.NotZero(t, resp.ID)
		assert.Equal(t, model.OrderTypeDevice, resp.OrderType)
	})

	t.Run("单卡订单缺少卡ID", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			PackageIDs:    []uint{env.pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}

		_, err := env.svc.Create(env.ctx, req, model.BuyerTypeAgent, env.shop.ID)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeInvalidParam, appErr.Code)
	})

	t.Run("设备订单缺少设备ID", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeDevice,
			PackageIDs:    []uint{env.pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}

		_, err := env.svc.Create(env.ctx, req, model.BuyerTypeAgent, env.shop.ID)
		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) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &env.card.ID,
			PackageIDs:    []uint{env.pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}

		resp, err := env.svc.Create(env.ctx, req, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)
		assert.Equal(t, model.PaymentStatusPending, resp.PaymentStatus)
		assert.False(t, resp.IsPurchaseOnBehalf)
	})

	t.Run("线下支付创建订单", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &env.card.ID,
			PackageIDs:    []uint{env.pkg.ID},
			PaymentMethod: model.PaymentMethodOffline,
		}

		platformCtx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
			UserID:   1,
			UserType: constants.UserTypePlatform,
		})

		resp, err := env.svc.Create(platformCtx, req, "", 0)
		require.NoError(t, err)
		assert.Equal(t, model.PaymentStatusPaid, resp.PaymentStatus)
		assert.True(t, resp.IsPurchaseOnBehalf)
		assert.NotNil(t, resp.PaidAt)
	})
}

func TestOrderService_Get(t *testing.T) {
	env := setupOrderTestEnv(t)

	req := &dto.CreateOrderRequest{
		OrderType:     model.OrderTypeSingleCard,
		IotCardID:     &env.card.ID,
		PackageIDs:    []uint{env.pkg.ID},
		PaymentMethod: model.PaymentMethodWallet,
	}
	created, err := env.svc.Create(env.ctx, req, model.BuyerTypeAgent, env.shop.ID)
	require.NoError(t, err)

	t.Run("获取订单成功", func(t *testing.T) {
		resp, err := env.svc.Get(env.ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, created.OrderNo, resp.OrderNo)
		assert.Len(t, resp.Items, 1)
	})

	t.Run("订单不存在", func(t *testing.T) {
		_, err := env.svc.Get(env.ctx, 99999)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeNotFound, appErr.Code)
	})
}

func TestOrderService_List(t *testing.T) {
	env := setupOrderTestEnv(t)

	for i := 0; i < 3; i++ {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &env.card.ID,
			PackageIDs:    []uint{env.pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}
		_, err := env.svc.Create(env.ctx, req, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)
	}

	t.Run("列表查询", func(t *testing.T) {
		listReq := &dto.OrderListRequest{
			Page:     1,
			PageSize: 10,
		}
		resp, err := env.svc.List(env.ctx, listReq, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)
		assert.GreaterOrEqual(t, resp.Total, int64(3))
		assert.GreaterOrEqual(t, len(resp.List), 3)
	})

	t.Run("按支付状态过滤", func(t *testing.T) {
		status := model.PaymentStatusPending
		listReq := &dto.OrderListRequest{
			Page:          1,
			PageSize:      10,
			PaymentStatus: &status,
		}
		resp, err := env.svc.List(env.ctx, listReq, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)
		for _, o := range resp.List {
			assert.Equal(t, model.PaymentStatusPending, o.PaymentStatus)
		}
	})
}

func TestOrderService_Cancel(t *testing.T) {
	env := setupOrderTestEnv(t)

	req := &dto.CreateOrderRequest{
		OrderType:     model.OrderTypeSingleCard,
		IotCardID:     &env.card.ID,
		PackageIDs:    []uint{env.pkg.ID},
		PaymentMethod: model.PaymentMethodWallet,
	}
	created, err := env.svc.Create(env.ctx, req, model.BuyerTypeAgent, env.shop.ID)
	require.NoError(t, err)

	t.Run("取消订单成功", func(t *testing.T) {
		err := env.svc.Cancel(env.ctx, created.ID, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)

		order, err := env.svc.Get(env.ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, model.PaymentStatusCancelled, order.PaymentStatus)
	})

	t.Run("订单不存在", func(t *testing.T) {
		err := env.svc.Cancel(env.ctx, 99999, model.BuyerTypeAgent, env.shop.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) {
		newReq := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &env.card.ID,
			PackageIDs:    []uint{env.pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}
		newOrder, err := env.svc.Create(env.ctx, newReq, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)

		err = env.svc.Cancel(env.ctx, newOrder.ID, model.BuyerTypeAgent, 99999)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeForbidden, appErr.Code)
	})
}

func TestOrderService_WalletPay(t *testing.T) {
	env := setupOrderTestEnv(t)

	t.Run("钱包支付成功", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &env.card.ID,
			PackageIDs:    []uint{env.pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}
		created, err := env.svc.Create(env.ctx, req, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)

		err = env.svc.WalletPay(env.ctx, created.ID, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)

		order, err := env.svc.Get(env.ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, model.PaymentStatusPaid, order.PaymentStatus)
		assert.Equal(t, model.PaymentMethodWallet, order.PaymentMethod)
		assert.NotNil(t, order.PaidAt)
	})

	t.Run("订单不存在", func(t *testing.T) {
		err := env.svc.WalletPay(env.ctx, 99999, model.BuyerTypeAgent, env.shop.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) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &env.card.ID,
			PackageIDs:    []uint{env.pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}
		created, err := env.svc.Create(env.ctx, req, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)

		err = env.svc.WalletPay(env.ctx, created.ID, model.BuyerTypeAgent, 99999)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeForbidden, appErr.Code)
	})

	t.Run("重复支付-幂等成功", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &env.card.ID,
			PackageIDs:    []uint{env.pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}
		created, err := env.svc.Create(env.ctx, req, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)

		err = env.svc.WalletPay(env.ctx, created.ID, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)

		err = env.svc.WalletPay(env.ctx, created.ID, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)
	})

	t.Run("已取消订单无法支付", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &env.card.ID,
			PackageIDs:    []uint{env.pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}
		created, err := env.svc.Create(env.ctx, req, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)

		err = env.svc.Cancel(env.ctx, created.ID, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)

		err = env.svc.WalletPay(env.ctx, created.ID, model.BuyerTypeAgent, env.shop.ID)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeInvalidStatus, appErr.Code)
	})
}

func TestOrderService_HandlePaymentCallback(t *testing.T) {
	env := setupOrderTestEnv(t)

	t.Run("支付回调成功", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &env.card.ID,
			PackageIDs:    []uint{env.pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}
		created, err := env.svc.Create(env.ctx, req, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)

		err = env.svc.HandlePaymentCallback(env.ctx, created.OrderNo, model.PaymentMethodWechat)
		require.NoError(t, err)

		order, err := env.svc.Get(env.ctx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, model.PaymentStatusPaid, order.PaymentStatus)
		assert.Equal(t, model.PaymentMethodWechat, order.PaymentMethod)
	})

	t.Run("幂等处理-已支付订单", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &env.card.ID,
			PackageIDs:    []uint{env.pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}
		created, err := env.svc.Create(env.ctx, req, model.BuyerTypeAgent, env.shop.ID)
		require.NoError(t, err)

		err = env.svc.HandlePaymentCallback(env.ctx, created.OrderNo, model.PaymentMethodAlipay)
		require.NoError(t, err)

		err = env.svc.HandlePaymentCallback(env.ctx, created.OrderNo, model.PaymentMethodAlipay)
		require.NoError(t, err)
	})

	t.Run("订单不存在", func(t *testing.T) {
		err := env.svc.HandlePaymentCallback(env.ctx, "NOT_EXISTS_ORDER_NO", model.PaymentMethodWechat)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeNotFound, appErr.Code)
	})
}

func TestOrderService_IdempotencyAndConcurrency(t *testing.T) {
	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)
	orderStore := postgres.NewOrderStore(tx, rdb)
	orderItemStore := postgres.NewOrderItemStore(tx, rdb)
	walletStore := postgres.NewWalletStore(tx, rdb)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

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

	shop := &model.Shop{
		ShopName:  "测试店铺IDEM",
		ShopCode:  "TEST_SHOP_IDEM",
		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_IDEM",
		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_IDEM",
		PackageName:          "测试套餐幂等",
		SeriesID:             series.ID,
		PackageType:          "formal",
		DurationMonths:       1,
		DataAmountMB:         1024,
		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:     "89860000000000000099",
		ShopID:    shopIDPtr,
		CarrierID: carrier.ID,
		SeriesID:  &allocation.SeriesID,
		Status:    constants.StatusEnabled,
		BaseModel: model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, iotCardStore.Create(ctx, card))

	wallet := &model.Wallet{
		ResourceType: "shop",
		ResourceID:   shop.ID,
		WalletType:   "main",
		Balance:      1000000,
		Version:      1,
		BaseModel:    model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, tx.Create(wallet).Error)

	purchaseValidationSvc := purchase_validation.New(tx, iotCardStore, deviceStore, packageStore, seriesAllocationStore)
	logger := zap.NewNop()
	orderSvc := New(tx, orderStore, orderItemStore, walletStore, purchaseValidationSvc, nil, seriesAllocationStore, iotCardStore, deviceStore, nil, nil, logger)

	userCtx := middleware.SetUserContext(ctx, &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypeAgent,
		ShopID:   shop.ID,
	})

	t.Run("串行幂等支付测试", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &card.ID,
			PackageIDs:    []uint{pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}
		created, err := orderSvc.Create(userCtx, req, model.BuyerTypeAgent, shop.ID)
		require.NoError(t, err)

		err = orderSvc.WalletPay(userCtx, created.ID, model.BuyerTypeAgent, shop.ID)
		require.NoError(t, err)

		err = orderSvc.WalletPay(userCtx, created.ID, model.BuyerTypeAgent, shop.ID)
		require.NoError(t, err)

		err = orderSvc.WalletPay(userCtx, created.ID, model.BuyerTypeAgent, shop.ID)
		require.NoError(t, err)

		var usageCount int64
		err = tx.Model(&model.PackageUsage{}).Where("order_id = ?", created.ID).Count(&usageCount).Error
		require.NoError(t, err)
		assert.Equal(t, int64(1), usageCount)

		order, err := orderSvc.Get(userCtx, created.ID)
		require.NoError(t, err)
		assert.Equal(t, model.PaymentStatusPaid, order.PaymentStatus)
	})

	t.Run("串行回调幂等测试", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &card.ID,
			PackageIDs:    []uint{pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}
		created, err := orderSvc.Create(userCtx, req, model.BuyerTypeAgent, shop.ID)
		require.NoError(t, err)

		err = orderSvc.HandlePaymentCallback(userCtx, created.OrderNo, model.PaymentMethodWechat)
		require.NoError(t, err)

		err = orderSvc.HandlePaymentCallback(userCtx, created.OrderNo, model.PaymentMethodWechat)
		require.NoError(t, err)

		err = orderSvc.HandlePaymentCallback(userCtx, created.OrderNo, model.PaymentMethodWechat)
		require.NoError(t, err)

		var usageCount int64
		err = tx.Model(&model.PackageUsage{}).Where("order_id = ?", created.ID).Count(&usageCount).Error
		require.NoError(t, err)
		assert.Equal(t, int64(1), usageCount)
	})

	t.Run("已取消订单回调测试", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &card.ID,
			PackageIDs:    []uint{pkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}
		created, err := orderSvc.Create(userCtx, req, model.BuyerTypeAgent, shop.ID)
		require.NoError(t, err)

		err = orderSvc.Cancel(userCtx, created.ID, model.BuyerTypeAgent, shop.ID)
		require.NoError(t, err)

		err = orderSvc.HandlePaymentCallback(userCtx, created.OrderNo, model.PaymentMethodWechat)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeInvalidStatus, appErr.Code)

		var usageCount int64
		err = tx.Model(&model.PackageUsage{}).Where("order_id = ?", created.ID).Count(&usageCount).Error
		require.NoError(t, err)
		assert.Equal(t, int64(0), usageCount)
	})
}

func TestOrderService_ForceRechargeValidation(t *testing.T) {
	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)
	orderStore := postgres.NewOrderStore(tx, rdb)
	orderItemStore := postgres.NewOrderItemStore(tx, rdb)
	walletStore := postgres.NewWalletStore(tx, rdb)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

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

	shop := &model.Shop{
		ShopName:  "测试店铺FR",
		ShopCode:  "TEST_SHOP_FR",
		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_FR",
		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,
		EnableOneTimeCommission:    true,
		OneTimeCommissionTrigger:   model.OneTimeCommissionTriggerSingleRecharge,
		OneTimeCommissionThreshold: 20000,
		BaseModel:                  model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, seriesAllocationStore.Create(ctx, allocation))

	cheapPkg := &model.Package{
		PackageCode:          "TEST_PKG_CHEAP",
		PackageName:          "便宜套餐",
		SeriesID:             series.ID,
		PackageType:          "formal",
		DurationMonths:       1,
		DataAmountMB:         512,
		SuggestedRetailPrice: 5000,
		Status:               constants.StatusEnabled,
		ShelfStatus:          constants.ShelfStatusOn,
		BaseModel:            model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, packageStore.Create(ctx, cheapPkg))

	expensivePkg := &model.Package{
		PackageCode:          "TEST_PKG_EXP",
		PackageName:          "高价套餐",
		SeriesID:             series.ID,
		PackageType:          "formal",
		DurationMonths:       12,
		DataAmountMB:         10240,
		SuggestedRetailPrice: 25000,
		Status:               constants.StatusEnabled,
		ShelfStatus:          constants.ShelfStatusOn,
		BaseModel:            model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, packageStore.Create(ctx, expensivePkg))

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

	purchaseValidationSvc := purchase_validation.New(tx, iotCardStore, deviceStore, packageStore, seriesAllocationStore)
	logger := zap.NewNop()
	orderSvc := New(tx, orderStore, orderItemStore, walletStore, purchaseValidationSvc, nil, seriesAllocationStore, iotCardStore, deviceStore, nil, nil, logger)

	userCtx := middleware.SetUserContext(ctx, &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypeAgent,
		ShopID:   shop.ID,
	})

	t.Run("强充验证-金额不足拒绝", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &card.ID,
			PackageIDs:    []uint{cheapPkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}

		_, err := orderSvc.Create(userCtx, req, model.BuyerTypeAgent, shop.ID)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeForceRechargeRequired, appErr.Code)
	})

	t.Run("强充验证-金额足够通过", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &card.ID,
			PackageIDs:    []uint{expensivePkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}

		resp, err := orderSvc.Create(userCtx, req, model.BuyerTypeAgent, shop.ID)
		require.NoError(t, err)
		assert.NotZero(t, resp.ID)
		assert.Equal(t, expensivePkg.SuggestedRetailPrice, resp.TotalAmount)
	})

	t.Run("已付佣金-跳过强充验证", func(t *testing.T) {
		card2 := &model.IotCard{
			ICCID:               "89860000000000000FR2",
			ShopID:              shopIDPtr,
			CarrierID:           carrier.ID,
			SeriesID:            &allocation.SeriesID,
			Status:              constants.StatusEnabled,
			FirstCommissionPaid: true,
			BaseModel:           model.BaseModel{Creator: 1, Updater: 1},
		}
		require.NoError(t, iotCardStore.Create(ctx, card2))

		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &card2.ID,
			PackageIDs:    []uint{cheapPkg.ID},
			PaymentMethod: model.PaymentMethodWallet,
		}

		resp, err := orderSvc.Create(userCtx, req, model.BuyerTypeAgent, shop.ID)
		require.NoError(t, err)
		assert.NotZero(t, resp.ID)
	})
}

func TestOrderService_GetPurchaseCheck(t *testing.T) {
	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)
	orderStore := postgres.NewOrderStore(tx, rdb)
	orderItemStore := postgres.NewOrderItemStore(tx, rdb)
	walletStore := postgres.NewWalletStore(tx, rdb)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

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

	shop := &model.Shop{
		ShopName:  "测试店铺PC",
		ShopCode:  "TEST_SHOP_PC",
		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_PC",
		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,
		EnableOneTimeCommission:    true,
		OneTimeCommissionTrigger:   model.OneTimeCommissionTriggerSingleRecharge,
		OneTimeCommissionThreshold: 10000,
		BaseModel:                  model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, seriesAllocationStore.Create(ctx, allocation))

	pkg := &model.Package{
		PackageCode:          "TEST_PKG_PC",
		PackageName:          "测试套餐预检",
		SeriesID:             series.ID,
		PackageType:          "formal",
		DurationMonths:       1,
		DataAmountMB:         1024,
		SuggestedRetailPrice: 5000,
		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:               "89860000000000000PC1",
		ShopID:              shopIDPtr,
		CarrierID:           carrier.ID,
		SeriesID:            &allocation.SeriesID,
		Status:              constants.StatusEnabled,
		FirstCommissionPaid: false,
		BaseModel:           model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, iotCardStore.Create(ctx, card))

	purchaseValidationSvc := purchase_validation.New(tx, iotCardStore, deviceStore, packageStore, seriesAllocationStore)
	logger := zap.NewNop()
	orderSvc := New(tx, orderStore, orderItemStore, walletStore, purchaseValidationSvc, nil, seriesAllocationStore, iotCardStore, deviceStore, nil, nil, logger)

	t.Run("预检-需要强充", func(t *testing.T) {
		req := &dto.PurchaseCheckRequest{
			OrderType:  model.OrderTypeSingleCard,
			ResourceID: card.ID,
			PackageIDs: []uint{pkg.ID},
		}

		resp, err := orderSvc.GetPurchaseCheck(ctx, req)
		require.NoError(t, err)
		assert.Equal(t, pkg.SuggestedRetailPrice, resp.TotalPackageAmount)
		assert.True(t, resp.NeedForceRecharge)
		assert.Equal(t, allocation.OneTimeCommissionThreshold, resp.ForceRechargeAmount)
		assert.Equal(t, allocation.OneTimeCommissionThreshold, resp.ActualPayment)
		assert.NotEmpty(t, resp.Message)
	})

	t.Run("预检-无需强充", func(t *testing.T) {
		card2 := &model.IotCard{
			ICCID:               "89860000000000000PC2",
			ShopID:              shopIDPtr,
			CarrierID:           carrier.ID,
			SeriesID:            &allocation.SeriesID,
			Status:              constants.StatusEnabled,
			FirstCommissionPaid: true,
			BaseModel:           model.BaseModel{Creator: 1, Updater: 1},
		}
		require.NoError(t, iotCardStore.Create(ctx, card2))

		req := &dto.PurchaseCheckRequest{
			OrderType:  model.OrderTypeSingleCard,
			ResourceID: card2.ID,
			PackageIDs: []uint{pkg.ID},
		}

		resp, err := orderSvc.GetPurchaseCheck(ctx, req)
		require.NoError(t, err)
		assert.Equal(t, pkg.SuggestedRetailPrice, resp.TotalPackageAmount)
		assert.False(t, resp.NeedForceRecharge)
		assert.Equal(t, pkg.SuggestedRetailPrice, resp.ActualPayment)
		assert.Empty(t, resp.Message)
	})
}

func TestOrderService_WalletPay_PurchaseOnBehalf(t *testing.T) {
	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)
	orderStore := postgres.NewOrderStore(tx, rdb)
	orderItemStore := postgres.NewOrderItemStore(tx, rdb)
	walletStore := postgres.NewWalletStore(tx, rdb)

	ctx := middleware.SetUserContext(context.Background(), &middleware.UserContextInfo{
		UserID:   1,
		UserType: constants.UserTypePlatform,
	})

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

	shop := &model.Shop{
		ShopName:  "测试店铺WP",
		ShopCode:  "TEST_SHOP_WP",
		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_WP",
		SeriesName:  "测试套餐系列WP",
		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,
		AllocatorShopID:     0,
		BaseCommissionMode:  model.CommissionModePercent,
		BaseCommissionValue: 100,
		Status:              constants.StatusEnabled,
		BaseModel:           model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, seriesAllocationStore.Create(ctx, allocation))

	pkg := &model.Package{
		PackageCode:          "TEST_PKG_WP",
		PackageName:          "测试套餐WP",
		SeriesID:             series.ID,
		PackageType:          "formal",
		DurationMonths:       1,
		DataAmountMB:         1024,
		SuggestedRetailPrice: 10000,
		Status:               constants.StatusEnabled,
		ShelfStatus:          constants.ShelfStatusOn,
		BaseModel:            model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, packageStore.Create(ctx, pkg))

	wallet := &model.Wallet{
		ResourceType: "shop",
		ResourceID:   shop.ID,
		WalletType:   "main",
		Balance:      100000,
		Version:      1,
		BaseModel:    model.BaseModel{Creator: 1, Updater: 1},
	}
	require.NoError(t, tx.Create(wallet).Error)

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

	purchaseValidationSvc := purchase_validation.New(tx, iotCardStore, deviceStore, packageStore, seriesAllocationStore)
	logger := zap.NewNop()
	orderSvc := New(tx, orderStore, orderItemStore, walletStore, purchaseValidationSvc, nil, seriesAllocationStore, iotCardStore, deviceStore, nil, nil, logger)

	t.Run("代购订单无法进行钱包支付", func(t *testing.T) {
		req := &dto.CreateOrderRequest{
			OrderType:     model.OrderTypeSingleCard,
			IotCardID:     &card.ID,
			PackageIDs:    []uint{pkg.ID},
			PaymentMethod: model.PaymentMethodOffline,
		}

		created, err := orderSvc.Create(ctx, req, model.BuyerTypeAgent, shop.ID)
		require.NoError(t, err)

		err = orderSvc.WalletPay(ctx, created.ID, model.BuyerTypeAgent, shop.ID)
		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok)
		assert.Equal(t, errors.CodeInvalidStatus, appErr.Code)
	})
}
