package commission_calculation

import (
	"context"
	"testing"
	"time"

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

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

	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)
	statsStore := postgres.NewShopSeriesCommissionStatsStore(tx)
	commissionStatsService := commission_stats.New(statsStore)

	service := New(
		tx,
		commissionRecordStore,
		shopStore,
		shopSeriesAllocationStore,
		shopSeriesOneTimeCommissionTierStore,
		iotCardStore,
		deviceStore,
		walletStore,
		walletTransactionStore,
		orderStore,
		orderItemStore,
		packageStore,
		commissionStatsService,
		zap.NewNop(),
	)

	ctx := context.Background()

	shop := &model.Shop{
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
		ShopName:     "测试店铺",
		ShopCode:     "TEST001",
		ContactName:  "测试联系人",
		ContactPhone: "13800000001",
	}
	require.NoError(t, tx.Create(shop).Error)

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

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

	card := &model.IotCard{
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
		ICCID:               "89860000000000000001",
		ShopID:              &shop.ID,
		SeriesID:            &allocation.SeriesID,
		AccumulatedRecharge: 0,
		FirstCommissionPaid: false,
	}
	require.NoError(t, tx.Create(card).Error)

	seriesID := allocation.SeriesID

	tests := []struct {
		name                        string
		isPurchaseOnBehalf          bool
		expectedAccumulatedRecharge int64
		expectedCommissionRecords   int
		expectedOneTimeCommission   bool
	}{
		{
			name:                        "普通订单_触发累计充值和一次性佣金",
			isPurchaseOnBehalf:          false,
			expectedAccumulatedRecharge: 15000,
			expectedCommissionRecords:   2,
			expectedOneTimeCommission:   true,
		},
		{
			name:                        "代购订单_不触发累计充值和一次性佣金",
			isPurchaseOnBehalf:          true,
			expectedAccumulatedRecharge: 0,
			expectedCommissionRecords:   1,
			expectedOneTimeCommission:   false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			require.NoError(t, tx.Model(&model.IotCard{}).Where("id = ?", card.ID).Updates(map[string]interface{}{
				"accumulated_recharge":  0,
				"first_commission_paid": false,
			}).Error)

			require.NoError(t, tx.Where("1=1").Delete(&model.CommissionRecord{}).Error)
			require.NoError(t, tx.Where("1=1").Delete(&model.Order{}).Error)

			order := &model.Order{
				BaseModel: model.BaseModel{
					Creator: 1,
					Updater: 1,
				},
				OrderNo:            "ORD" + time.Now().Format("20060102150405"),
				OrderType:          model.OrderTypeSingleCard,
				IotCardID:          &card.ID,
				BuyerType:          model.BuyerTypeAgent,
				BuyerID:            shop.ID,
				SellerShopID:       &shop.ID,
				SeriesID:           &seriesID,
				TotalAmount:        15000,
				SellerCostPrice:    5000,
				IsPurchaseOnBehalf: tt.isPurchaseOnBehalf,
				CommissionStatus:   model.CommissionStatusPending,
				PaymentStatus:      model.PaymentStatusPaid,
			}
			require.NoError(t, tx.Create(order).Error)

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

			var updatedCard model.IotCard
			require.NoError(t, tx.First(&updatedCard, card.ID).Error)
			assert.Equal(t, tt.expectedAccumulatedRecharge, updatedCard.AccumulatedRecharge, "累计充值金额不符合预期")

			var records []model.CommissionRecord
			require.NoError(t, tx.Where("order_id = ?", order.ID).Find(&records).Error)
			assert.Equal(t, tt.expectedCommissionRecords, len(records), "佣金记录数量不符合预期")

			hasOneTimeCommission := false
			for _, record := range records {
				if record.CommissionSource == model.CommissionSourceOneTime {
					hasOneTimeCommission = true
					break
				}
			}
			assert.Equal(t, tt.expectedOneTimeCommission, hasOneTimeCommission, "一次性佣金触发状态不符合预期")

			if tt.expectedOneTimeCommission {
				assert.True(t, updatedCard.FirstCommissionPaid, "首次佣金发放标记应为true")
			} else {
				assert.False(t, updatedCard.FirstCommissionPaid, "首次佣金发放标记应为false")
			}
		})
	}
}

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

	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)
	statsStore := postgres.NewShopSeriesCommissionStatsStore(tx)
	commissionStatsService := commission_stats.New(statsStore)

	service := New(
		tx,
		commissionRecordStore,
		shopStore,
		shopSeriesAllocationStore,
		shopSeriesOneTimeCommissionTierStore,
		iotCardStore,
		deviceStore,
		walletStore,
		walletTransactionStore,
		orderStore,
		orderItemStore,
		packageStore,
		commissionStatsService,
		zap.NewNop(),
	)

	ctx := context.Background()

	shop := &model.Shop{
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
		ShopName:     "测试店铺",
		ShopCode:     "TEST002",
		ContactName:  "测试联系人",
		ContactPhone: "13800000002",
	}
	require.NoError(t, tx.Create(shop).Error)

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

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

	device := &model.Device{
		BaseModel: model.BaseModel{
			Creator: 1,
			Updater: 1,
		},
		DeviceNo:            "DEV001",
		ShopID:              &shop.ID,
		SeriesID:            &allocation.SeriesID,
		AccumulatedRecharge: 0,
		FirstCommissionPaid: false,
	}
	require.NoError(t, tx.Create(device).Error)

	seriesID := allocation.SeriesID

	tests := []struct {
		name                        string
		isPurchaseOnBehalf          bool
		expectedAccumulatedRecharge int64
		expectedCommissionRecords   int
		expectedOneTimeCommission   bool
	}{
		{
			name:                        "普通订单_触发累计充值和一次性佣金",
			isPurchaseOnBehalf:          false,
			expectedAccumulatedRecharge: 15000,
			expectedCommissionRecords:   2,
			expectedOneTimeCommission:   true,
		},
		{
			name:                        "代购订单_不触发累计充值和一次性佣金",
			isPurchaseOnBehalf:          true,
			expectedAccumulatedRecharge: 0,
			expectedCommissionRecords:   1,
			expectedOneTimeCommission:   false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			require.NoError(t, tx.Model(&model.Device{}).Where("id = ?", device.ID).Updates(map[string]interface{}{
				"accumulated_recharge":  0,
				"first_commission_paid": false,
			}).Error)

			require.NoError(t, tx.Where("1=1").Delete(&model.CommissionRecord{}).Error)
			require.NoError(t, tx.Where("1=1").Delete(&model.Order{}).Error)

			order := &model.Order{
				BaseModel: model.BaseModel{
					Creator: 1,
					Updater: 1,
				},
				OrderNo:            "ORD" + time.Now().Format("20060102150405"),
				OrderType:          model.OrderTypeDevice,
				DeviceID:           &device.ID,
				BuyerType:          model.BuyerTypeAgent,
				BuyerID:            shop.ID,
				SellerShopID:       &shop.ID,
				SeriesID:           &seriesID,
				TotalAmount:        15000,
				SellerCostPrice:    5000,
				IsPurchaseOnBehalf: tt.isPurchaseOnBehalf,
				CommissionStatus:   model.CommissionStatusPending,
				PaymentStatus:      model.PaymentStatusPaid,
			}
			require.NoError(t, tx.Create(order).Error)

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

			var updatedDevice model.Device
			require.NoError(t, tx.First(&updatedDevice, device.ID).Error)
			assert.Equal(t, tt.expectedAccumulatedRecharge, updatedDevice.AccumulatedRecharge, "累计充值金额不符合预期")

			var records []model.CommissionRecord
			require.NoError(t, tx.Where("order_id = ?", order.ID).Find(&records).Error)
			assert.Equal(t, tt.expectedCommissionRecords, len(records), "佣金记录数量不符合预期")

			hasOneTimeCommission := false
			for _, record := range records {
				if record.CommissionSource == model.CommissionSourceOneTime {
					hasOneTimeCommission = true
					break
				}
			}
			assert.Equal(t, tt.expectedOneTimeCommission, hasOneTimeCommission, "一次性佣金触发状态不符合预期")

			if tt.expectedOneTimeCommission {
				assert.True(t, updatedDevice.FirstCommissionPaid, "首次佣金发放标记应为true")
			} else {
				assert.False(t, updatedDevice.FirstCommissionPaid, "首次佣金发放标记应为false")
			}
		})
	}
}
