package task

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/utils"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
	"go.uber.org/zap"
)

func TestDeviceImportHandler_ProcessBatch_AllOrNothingValidation(t *testing.T) {
	tx := newTaskTestTransaction(t)
	rdb := getTaskTestRedis(t)
	cleanTaskTestRedisKeys(t, rdb)

	logger := zap.NewNop()
	importTaskStore := postgres.NewDeviceImportTaskStore(tx, rdb)
	deviceStore := postgres.NewDeviceStore(tx, rdb)
	bindingStore := postgres.NewDeviceSimBindingStore(tx, rdb)
	cardStore := postgres.NewIotCardStore(tx, rdb)

	handler := NewDeviceImportHandler(tx, rdb, importTaskStore, deviceStore, bindingStore, cardStore, nil, logger)
	ctx := context.Background()

	shopID := uint(100)
	platformCard := &model.IotCard{ICCID: "89860012345670001001", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: nil}
	platformCard2 := &model.IotCard{ICCID: "89860012345670001003", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: nil}
	shopCard := &model.IotCard{ICCID: "89860012345670001002", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: &shopID}
	require.NoError(t, cardStore.Create(ctx, platformCard))
	require.NoError(t, cardStore.Create(ctx, platformCard2))
	require.NoError(t, cardStore.Create(ctx, shopCard))

	t.Run("所有卡可用-成功", func(t *testing.T) {
		task := &model.DeviceImportTask{
			BatchNo: "TEST_BATCH_001",
		}
		task.Creator = 1

		batch := []utils.DeviceRow{
			{Line: 2, DeviceNo: "DEV-OWNER-001", MaxSimSlots: 4, ICCIDs: []string{"89860012345670001001"}},
		}
		result := &deviceImportResult{
			skippedItems: make(model.ImportResultItems, 0),
			failedItems:  make(model.ImportResultItems, 0),
		}

		handler.processBatch(ctx, task, batch, result)

		assert.Equal(t, 1, result.successCount)
		assert.Equal(t, 0, result.failCount)
	})

	t.Run("任一卡分配给店铺-整体失败", func(t *testing.T) {
		task := &model.DeviceImportTask{
			BatchNo: "TEST_BATCH_002",
		}
		task.Creator = 1

		batch := []utils.DeviceRow{
			{Line: 3, DeviceNo: "DEV-OWNER-002", MaxSimSlots: 4, ICCIDs: []string{"89860012345670001003", "89860012345670001002"}},
		}
		result := &deviceImportResult{
			skippedItems: make(model.ImportResultItems, 0),
			failedItems:  make(model.ImportResultItems, 0),
		}

		handler.processBatch(ctx, task, batch, result)

		assert.Equal(t, 0, result.successCount)
		assert.Equal(t, 1, result.failCount)
		require.Len(t, result.failedItems, 1)
		assert.Contains(t, result.failedItems[0].Reason, "已分配给店铺")
	})

	t.Run("任一卡不存在-整体失败", func(t *testing.T) {
		task := &model.DeviceImportTask{
			BatchNo: "TEST_BATCH_003",
		}
		task.Creator = 1

		batch := []utils.DeviceRow{
			{Line: 4, DeviceNo: "DEV-OWNER-003", MaxSimSlots: 4, ICCIDs: []string{"89860012345670001002", "89860012345670009999"}},
		}
		result := &deviceImportResult{
			skippedItems: make(model.ImportResultItems, 0),
			failedItems:  make(model.ImportResultItems, 0),
		}

		handler.processBatch(ctx, task, batch, result)

		assert.Equal(t, 0, result.successCount)
		assert.Equal(t, 1, result.failCount)
		require.Len(t, result.failedItems, 1)
		assert.Contains(t, result.failedItems[0].Reason, "卡验证失败")
	})

	t.Run("无指定卡时创建设备成功", func(t *testing.T) {
		task := &model.DeviceImportTask{
			BatchNo: "TEST_BATCH_004",
		}
		task.Creator = 1

		batch := []utils.DeviceRow{
			{Line: 5, DeviceNo: "DEV-OWNER-004", MaxSimSlots: 4, ICCIDs: []string{}},
		}
		result := &deviceImportResult{
			skippedItems: make(model.ImportResultItems, 0),
			failedItems:  make(model.ImportResultItems, 0),
		}

		handler.processBatch(ctx, task, batch, result)

		assert.Equal(t, 1, result.successCount)
		assert.Equal(t, 0, result.failCount)
	})

	t.Run("多张卡全部可用-成功", func(t *testing.T) {
		newCard1 := &model.IotCard{ICCID: "89860012345670001010", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: nil}
		newCard2 := &model.IotCard{ICCID: "89860012345670001011", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: nil}
		require.NoError(t, cardStore.Create(ctx, newCard1))
		require.NoError(t, cardStore.Create(ctx, newCard2))

		task := &model.DeviceImportTask{
			BatchNo: "TEST_BATCH_005",
		}
		task.Creator = 1

		batch := []utils.DeviceRow{
			{Line: 6, DeviceNo: "DEV-OWNER-005", MaxSimSlots: 4, ICCIDs: []string{"89860012345670001010", "89860012345670001011"}},
		}
		result := &deviceImportResult{
			skippedItems: make(model.ImportResultItems, 0),
			failedItems:  make(model.ImportResultItems, 0),
		}

		handler.processBatch(ctx, task, batch, result)

		assert.Equal(t, 1, result.successCount)
		assert.Equal(t, 0, result.failCount)
	})
}

func TestDeviceImportHandler_ProcessImport_AllOrNothing(t *testing.T) {
	tx := newTaskTestTransaction(t)
	rdb := getTaskTestRedis(t)
	cleanTaskTestRedisKeys(t, rdb)

	logger := zap.NewNop()
	importTaskStore := postgres.NewDeviceImportTaskStore(tx, rdb)
	deviceStore := postgres.NewDeviceStore(tx, rdb)
	bindingStore := postgres.NewDeviceSimBindingStore(tx, rdb)
	cardStore := postgres.NewIotCardStore(tx, rdb)

	handler := NewDeviceImportHandler(tx, rdb, importTaskStore, deviceStore, bindingStore, cardStore, nil, logger)
	ctx := context.Background()

	shopID := uint(200)
	platformCard1 := &model.IotCard{ICCID: "89860012345680001001", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: nil}
	platformCard2 := &model.IotCard{ICCID: "89860012345680001002", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: nil}
	shopCard := &model.IotCard{ICCID: "89860012345680001003", CardType: "data_card", CarrierID: 1, Status: 1, ShopID: &shopID}
	require.NoError(t, cardStore.Create(ctx, platformCard1))
	require.NoError(t, cardStore.Create(ctx, platformCard2))
	require.NoError(t, cardStore.Create(ctx, shopCard))

	task := &model.DeviceImportTask{
		BatchNo: "TEST_PROCESS_IMPORT",
	}
	task.Creator = 1

	rows := []utils.DeviceRow{
		{Line: 2, DeviceNo: "DEV-PI-001", MaxSimSlots: 4, ICCIDs: []string{"89860012345680001001"}},
		{Line: 3, DeviceNo: "DEV-PI-002", MaxSimSlots: 4, ICCIDs: []string{"89860012345680001002", "89860012345680001003"}},
		{Line: 4, DeviceNo: "DEV-PI-003", MaxSimSlots: 4, ICCIDs: []string{"89860012345680001003", "89860012345680009999"}},
	}

	result := handler.processImport(ctx, task, rows, len(rows))

	assert.Equal(t, 1, result.successCount, "只有第一个设备应该成功（所有卡都可用）")
	assert.Equal(t, 2, result.failCount, "第二和第三个设备应该失败（有卡不可用）")

	assert.Len(t, result.failedItems, 2)
	assert.Equal(t, 3, result.failedItems[0].Line)
	assert.Contains(t, result.failedItems[0].Reason, "已分配给店铺")
	assert.Equal(t, 4, result.failedItems[1].Line)
	assert.Contains(t, result.failedItems[1].Reason, "卡验证失败")
}
