package unit

import (
	"context"
	"fmt"
	"testing"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/service/commission_calculation"
	"github.com/break/junhong_cmp_fiber/internal/service/commission_stats"
	"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"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/zap"
)

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

	ctx := context.Background()

	t.Run("累计充值触发-每次支付都写回累计金额", func(t *testing.T) {
		shop := &model.Shop{
			BaseModel: model.BaseModel{Creator: 1, Updater: 1},
			ShopName:  "测试店铺",
			ShopCode:  fmt.Sprintf("SHOP_%d", time.Now().UnixNano()),
			Level:     1,
			Status:    constants.StatusEnabled,
		}
		require.NoError(t, tx.Create(shop).Error)

		series := &model.PackageSeries{
			BaseModel:  model.BaseModel{Creator: 1, Updater: 1},
			SeriesCode: fmt.Sprintf("SERIES_%d", time.Now().UnixNano()),
			SeriesName: "测试系列",
			Status:     constants.StatusEnabled,
		}
		require.NoError(t, tx.Create(series).Error)

		allocation := &model.ShopSeriesAllocation{
			BaseModel:                  model.BaseModel{Creator: 1, Updater: 1},
			ShopID:                     shop.ID,
			SeriesID:                   series.ID,
			AllocatorShopID:            0,
			BaseCommissionMode:         model.CommissionModeFixed,
			BaseCommissionValue:        1000,
			EnableOneTimeCommission:    true,
			OneTimeCommissionType:      model.OneTimeCommissionTypeFixed,
			OneTimeCommissionTrigger:   model.OneTimeCommissionTriggerAccumulatedRecharge,
			OneTimeCommissionThreshold: 10000,
			OneTimeCommissionMode:      model.CommissionModeFixed,
			OneTimeCommissionValue:     500,
			Status:                     constants.StatusEnabled,
		}
		require.NoError(t, tx.Create(allocation).Error)

		card := &model.IotCard{
			BaseModel:           model.BaseModel{Creator: 1, Updater: 1},
			ICCID:               fmt.Sprintf("898600%013d", time.Now().Unix()%10000000000000),
			CardType:            "4G",
			CardCategory:        "normal",
			CarrierID:           1,
			CarrierType:         "CMCC",
			CarrierName:         "中国移动",
			Status:              3,
			ShopID:              &shop.ID,
			SeriesID:            &allocation.ID,
			FirstCommissionPaid: false,
			AccumulatedRecharge: 0,
		}
		require.NoError(t, tx.Create(card).Error)

		wallet := &model.Wallet{
			ResourceType: "shop",
			ResourceID:   shop.ID,
			WalletType:   "commission",
			Balance:      0,
			Version:      0,
			Status:       1,
		}
		require.NoError(t, tx.Create(wallet).Error)

		iotCardStore := postgres.NewIotCardStore(tx, rdb)
		shopSeriesAllocationStore := postgres.NewShopSeriesAllocationStore(tx)

		t.Run("第一次支付-累计金额更新为3000", func(t *testing.T) {
			order1 := &model.Order{
				BaseModel:        model.BaseModel{Creator: 1, Updater: 1},
				OrderNo:          fmt.Sprintf("ORDER_%d_1", time.Now().UnixNano()),
				OrderType:        model.OrderTypeSingleCard,
				BuyerType:        model.BuyerTypeAgent,
				BuyerID:          shop.ID,
				IotCardID:        &card.ID,
				SellerShopID:     &shop.ID,
				SeriesID:         &series.ID,
				TotalAmount:      3000,
				SellerCostPrice:  2000,
				PaymentStatus:    model.PaymentStatusPaid,
				CommissionStatus: model.CommissionStatusPending,
			}
			require.NoError(t, tx.Create(order1).Error)

			cardBefore, err := iotCardStore.GetByID(ctx, card.ID)
			require.NoError(t, err)
			assert.Equal(t, int64(0), cardBefore.AccumulatedRecharge)

			alloc, err := shopSeriesAllocationStore.GetByID(ctx, *card.SeriesID)
			require.NoError(t, err)

			if alloc.OneTimeCommissionTrigger == model.OneTimeCommissionTriggerAccumulatedRecharge {
				newAccumulated := cardBefore.AccumulatedRecharge + order1.TotalAmount
				err := tx.Model(&model.IotCard{}).Where("id = ?", card.ID).
					Update("accumulated_recharge", newAccumulated).Error
				require.NoError(t, err)
			}

			cardAfter, err := iotCardStore.GetByID(ctx, card.ID)
			require.NoError(t, err)
			assert.Equal(t, int64(3000), cardAfter.AccumulatedRecharge, "第一次支付后累计金额应为3000")
			assert.False(t, cardAfter.FirstCommissionPaid, "未达阈值不应标记为已发放")
		})

		t.Run("第二次支付-累计金额更新为7000", func(t *testing.T) {
			order2 := &model.Order{
				BaseModel:        model.BaseModel{Creator: 1, Updater: 1},
				OrderNo:          fmt.Sprintf("ORDER_%d_2", time.Now().UnixNano()),
				OrderType:        model.OrderTypeSingleCard,
				BuyerType:        model.BuyerTypeAgent,
				BuyerID:          shop.ID,
				IotCardID:        &card.ID,
				SellerShopID:     &shop.ID,
				SeriesID:         &series.ID,
				TotalAmount:      4000,
				SellerCostPrice:  3000,
				PaymentStatus:    model.PaymentStatusPaid,
				CommissionStatus: model.CommissionStatusPending,
			}
			require.NoError(t, tx.Create(order2).Error)

			cardBefore, err := iotCardStore.GetByID(ctx, card.ID)
			require.NoError(t, err)
			assert.Equal(t, int64(3000), cardBefore.AccumulatedRecharge)

			alloc, err := shopSeriesAllocationStore.GetByID(ctx, *card.SeriesID)
			require.NoError(t, err)

			if alloc.OneTimeCommissionTrigger == model.OneTimeCommissionTriggerAccumulatedRecharge {
				newAccumulated := cardBefore.AccumulatedRecharge + order2.TotalAmount
				err := tx.Model(&model.IotCard{}).Where("id = ?", card.ID).
					Update("accumulated_recharge", newAccumulated).Error
				require.NoError(t, err)
			}

			cardAfter, err := iotCardStore.GetByID(ctx, card.ID)
			require.NoError(t, err)
			assert.Equal(t, int64(7000), cardAfter.AccumulatedRecharge, "第二次支付后累计金额应为7000")
			assert.False(t, cardAfter.FirstCommissionPaid, "仍未达阈值不应标记为已发放")
		})

		t.Run("第三次支付-累计金额更新为11000且达到阈值", func(t *testing.T) {
			order3 := &model.Order{
				BaseModel:        model.BaseModel{Creator: 1, Updater: 1},
				OrderNo:          fmt.Sprintf("ORDER_%d_3", time.Now().UnixNano()),
				OrderType:        model.OrderTypeSingleCard,
				BuyerType:        model.BuyerTypeAgent,
				BuyerID:          shop.ID,
				IotCardID:        &card.ID,
				SellerShopID:     &shop.ID,
				SeriesID:         &series.ID,
				TotalAmount:      4000,
				SellerCostPrice:  3000,
				PaymentStatus:    model.PaymentStatusPaid,
				CommissionStatus: model.CommissionStatusPending,
			}
			require.NoError(t, tx.Create(order3).Error)

			cardBefore, err := iotCardStore.GetByID(ctx, card.ID)
			require.NoError(t, err)
			assert.Equal(t, int64(7000), cardBefore.AccumulatedRecharge)

			alloc, err := shopSeriesAllocationStore.GetByID(ctx, *card.SeriesID)
			require.NoError(t, err)

			if alloc.OneTimeCommissionTrigger == model.OneTimeCommissionTriggerAccumulatedRecharge {
				newAccumulated := cardBefore.AccumulatedRecharge + order3.TotalAmount
				err := tx.Model(&model.IotCard{}).Where("id = ?", card.ID).
					Update("accumulated_recharge", newAccumulated).Error
				require.NoError(t, err)
			}

			cardAfter, err := iotCardStore.GetByID(ctx, card.ID)
			require.NoError(t, err)
			assert.Equal(t, int64(11000), cardAfter.AccumulatedRecharge, "第三次支付后累计金额应为11000")

			if cardAfter.AccumulatedRecharge >= alloc.OneTimeCommissionThreshold && !cardAfter.FirstCommissionPaid {
				assert.GreaterOrEqual(t, cardAfter.AccumulatedRecharge, alloc.OneTimeCommissionThreshold, "累计金额已达阈值")

				err := tx.Model(&model.IotCard{}).Where("id = ?", card.ID).
					Update("first_commission_paid", true).Error
				require.NoError(t, err)

				cardFinal, err := iotCardStore.GetByID(ctx, card.ID)
				require.NoError(t, err)
				assert.True(t, cardFinal.FirstCommissionPaid, "达到阈值应标记为已发放")
			}
		})

		t.Run("第四次支付-累计金额继续更新但不重复发放", func(t *testing.T) {
			order4 := &model.Order{
				BaseModel:        model.BaseModel{Creator: 1, Updater: 1},
				OrderNo:          fmt.Sprintf("ORDER_%d_4", time.Now().UnixNano()),
				OrderType:        model.OrderTypeSingleCard,
				BuyerType:        model.BuyerTypeAgent,
				BuyerID:          shop.ID,
				IotCardID:        &card.ID,
				SellerShopID:     &shop.ID,
				SeriesID:         &series.ID,
				TotalAmount:      3000,
				SellerCostPrice:  2000,
				PaymentStatus:    model.PaymentStatusPaid,
				CommissionStatus: model.CommissionStatusPending,
			}
			require.NoError(t, tx.Create(order4).Error)

			cardBefore, err := iotCardStore.GetByID(ctx, card.ID)
			require.NoError(t, err)
			assert.Equal(t, int64(11000), cardBefore.AccumulatedRecharge)
			assert.True(t, cardBefore.FirstCommissionPaid, "标记应保持为true")

			alloc, err := shopSeriesAllocationStore.GetByID(ctx, *card.SeriesID)
			require.NoError(t, err)

			if alloc.OneTimeCommissionTrigger == model.OneTimeCommissionTriggerAccumulatedRecharge {
				newAccumulated := cardBefore.AccumulatedRecharge + order4.TotalAmount
				err := tx.Model(&model.IotCard{}).Where("id = ?", card.ID).
					Update("accumulated_recharge", newAccumulated).Error
				require.NoError(t, err)
			}

			cardAfter, err := iotCardStore.GetByID(ctx, card.ID)
			require.NoError(t, err)
			assert.Equal(t, int64(14000), cardAfter.AccumulatedRecharge, "第四次支付后累计金额应为14000")
			assert.True(t, cardAfter.FirstCommissionPaid, "已发放标记不应改变")
		})
	})
}

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

	ctx := context.Background()

	commissionRecordStore := postgres.NewCommissionRecordStore(tx, rdb)
	shopStore := postgres.NewShopStore(tx, rdb)
	shopSeriesAllocationStore := postgres.NewShopSeriesAllocationStore(tx)
	shopSeriesOneTimeCommissionTierStore := postgres.NewShopSeriesOneTimeCommissionTierStore(tx)
	iotCardStore := postgres.NewIotCardStore(tx, rdb)
	deviceStore := postgres.NewDeviceStore(tx, rdb)
	walletStore := postgres.NewWalletStore(tx, rdb)
	walletTransactionStore := postgres.NewWalletTransactionStore(tx, rdb)
	orderStore := postgres.NewOrderStore(tx, rdb)
	orderItemStore := postgres.NewOrderItemStore(tx, rdb)
	packageStore := postgres.NewPackageStore(tx)
	shopSeriesCommissionStatsStore := postgres.NewShopSeriesCommissionStatsStore(tx)
	commissionStatsService := commission_stats.New(shopSeriesCommissionStatsStore)
	logger, _ := zap.NewDevelopment()

	commCalcService := commission_calculation.New(
		tx,
		commissionRecordStore,
		shopStore,
		shopSeriesAllocationStore,
		shopSeriesOneTimeCommissionTierStore,
		iotCardStore,
		deviceStore,
		walletStore,
		walletTransactionStore,
		orderStore,
		orderItemStore,
		packageStore,
		commissionStatsService,
		logger,
	)

	t.Run("单次充值触发-达到阈值时发放佣金", func(t *testing.T) {
		shop := &model.Shop{
			BaseModel: model.BaseModel{Creator: 1, Updater: 1},
			ShopName:  "单次触发店铺",
			ShopCode:  fmt.Sprintf("SHOP_%d", time.Now().UnixNano()),
			Level:     1,
			Status:    constants.StatusEnabled,
		}
		require.NoError(t, tx.Create(shop).Error)

		series := &model.PackageSeries{
			BaseModel:  model.BaseModel{Creator: 1, Updater: 1},
			SeriesCode: fmt.Sprintf("SERIES_%d", time.Now().UnixNano()),
			SeriesName: "单次触发系列",
			Status:     constants.StatusEnabled,
		}
		require.NoError(t, tx.Create(series).Error)

		allocation := &model.ShopSeriesAllocation{
			BaseModel:                  model.BaseModel{Creator: 1, Updater: 1},
			ShopID:                     shop.ID,
			SeriesID:                   series.ID,
			AllocatorShopID:            0,
			BaseCommissionMode:         model.CommissionModeFixed,
			BaseCommissionValue:        500,
			EnableOneTimeCommission:    true,
			OneTimeCommissionType:      model.OneTimeCommissionTypeFixed,
			OneTimeCommissionTrigger:   model.OneTimeCommissionTriggerSingleRecharge,
			OneTimeCommissionThreshold: 5000,
			OneTimeCommissionMode:      model.CommissionModeFixed,
			OneTimeCommissionValue:     300,
			Status:                     constants.StatusEnabled,
		}
		require.NoError(t, tx.Create(allocation).Error)

		card := &model.IotCard{
			BaseModel:           model.BaseModel{Creator: 1, Updater: 1},
			ICCID:               fmt.Sprintf("898600%013d", time.Now().Unix()%10000000000000+1),
			CardType:            "4G",
			CardCategory:        "normal",
			CarrierID:           1,
			CarrierType:         "CMCC",
			CarrierName:         "中国移动",
			Status:              3,
			ShopID:              &shop.ID,
			SeriesID:            &allocation.ID,
			FirstCommissionPaid: false,
			AccumulatedRecharge: 0,
		}
		require.NoError(t, tx.Create(card).Error)

		wallet := &model.Wallet{
			ResourceType: "shop",
			ResourceID:   shop.ID,
			WalletType:   "commission",
			Balance:      0,
			Version:      0,
			Status:       1,
		}
		require.NoError(t, tx.Create(wallet).Error)

		t.Run("单次充值未达阈值-不触发", func(t *testing.T) {
			order := &model.Order{
				BaseModel:        model.BaseModel{Creator: 1, Updater: 1},
				OrderNo:          fmt.Sprintf("ORDER_%d", time.Now().UnixNano()),
				OrderType:        model.OrderTypeSingleCard,
				BuyerType:        model.BuyerTypeAgent,
				BuyerID:          shop.ID,
				IotCardID:        &card.ID,
				SellerShopID:     &shop.ID,
				SeriesID:         &series.ID,
				TotalAmount:      3000,
				SellerCostPrice:  2500,
				PaymentStatus:    model.PaymentStatusPaid,
				CommissionStatus: model.CommissionStatusPending,
			}
			require.NoError(t, tx.Create(order).Error)

			err := commCalcService.CalculateCommission(ctx, order.ID)
			require.NoError(t, err)

			cardAfter, err := iotCardStore.GetByID(ctx, card.ID)
			require.NoError(t, err)
			assert.False(t, cardAfter.FirstCommissionPaid, "单次充值未达阈值不应发放")
		})

		t.Run("单次充值达到阈值-触发", func(t *testing.T) {
			order := &model.Order{
				BaseModel:        model.BaseModel{Creator: 1, Updater: 1},
				OrderNo:          fmt.Sprintf("ORDER_%d", time.Now().UnixNano()+1),
				OrderType:        model.OrderTypeSingleCard,
				BuyerType:        model.BuyerTypeAgent,
				BuyerID:          shop.ID,
				IotCardID:        &card.ID,
				SellerShopID:     &shop.ID,
				SeriesID:         &series.ID,
				TotalAmount:      6000,
				SellerCostPrice:  5500,
				PaymentStatus:    model.PaymentStatusPaid,
				CommissionStatus: model.CommissionStatusPending,
			}
			require.NoError(t, tx.Create(order).Error)

			err := commCalcService.CalculateCommission(ctx, order.ID)
			require.NoError(t, err)

			cardAfter, err := iotCardStore.GetByID(ctx, card.ID)
			require.NoError(t, err)
			assert.True(t, cardAfter.FirstCommissionPaid, "单次充值达到阈值应发放")

			var commRecords []model.CommissionRecord
			err = tx.Where("order_id = ? AND commission_source = ?", order.ID, model.CommissionSourceOneTime).
				Find(&commRecords).Error
			require.NoError(t, err)
			assert.Len(t, commRecords, 1, "应有一条一次性佣金记录")
			assert.Equal(t, int64(300), commRecords[0].Amount, "佣金金额应为300")
		})
	})
}
