package enterprise_device

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

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"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"
)

func uniqueServiceTestPrefix() string {
	return fmt.Sprintf("SVC%d", time.Now().UnixNano()%1000000000)
}

func createTestContext(userID uint, userType int, shopID uint, enterpriseID uint) context.Context {
	ctx := context.Background()
	return middleware.SetUserContext(ctx, &middleware.UserContextInfo{
		UserID:       userID,
		UserType:     userType,
		ShopID:       shopID,
		EnterpriseID: enterpriseID,
	})
}

type testEnv struct {
	service    *Service
	enterprise *model.Enterprise
	shop       *model.Shop
	devices    []*model.Device
	cards      []*model.IotCard
	bindings   []*model.DeviceSimBinding
	carrier    *model.Carrier
}

func setupTestEnv(t *testing.T, prefix string) *testEnv {
	tx := testutils.NewTestTransaction(t)
	rdb := testutils.GetTestRedis(t)
	testutils.CleanTestRedisKeys(t, rdb)

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	deviceStore := postgres.NewDeviceStore(tx, rdb)
	deviceSimBindingStore := postgres.NewDeviceSimBindingStore(tx, rdb)
	enterpriseDeviceAuthStore := postgres.NewEnterpriseDeviceAuthorizationStore(tx, rdb)
	enterpriseCardAuthStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	logger := zap.NewNop()

	svc := New(tx, enterpriseStore, deviceStore, deviceSimBindingStore, enterpriseDeviceAuthStore, enterpriseCardAuthStore, logger)

	shop := &model.Shop{
		ShopName: prefix + "_测试店铺",
		ShopCode: prefix,
		Level:    1,
		Status:   1,
	}
	require.NoError(t, tx.Create(shop).Error)

	enterprise := &model.Enterprise{
		EnterpriseName: prefix + "_测试企业",
		EnterpriseCode: prefix,
		OwnerShopID:    &shop.ID,
		Status:         1,
	}
	require.NoError(t, tx.Create(enterprise).Error)

	carrier := &model.Carrier{
		CarrierName: "测试运营商",
		CarrierType: "CMCC",
		Status:      1,
	}
	require.NoError(t, tx.Create(carrier).Error)

	devices := make([]*model.Device, 3)
	for i := 0; i < 3; i++ {
		devices[i] = &model.Device{
			DeviceNo:   fmt.Sprintf("%s_D%03d", prefix, i+1),
			DeviceName: fmt.Sprintf("测试设备%d", i+1),
			Status:     2,
			ShopID:     &shop.ID,
		}
		require.NoError(t, tx.Create(devices[i]).Error)
	}

	cards := make([]*model.IotCard, 4)
	for i := 0; i < 4; i++ {
		cards[i] = &model.IotCard{
			ICCID:     fmt.Sprintf("%s%04d", prefix, i+1),
			CardType:  "normal",
			CarrierID: carrier.ID,
			Status:    2,
			ShopID:    &shop.ID,
		}
		require.NoError(t, tx.Create(cards[i]).Error)
	}

	now := time.Now()
	bindings := []*model.DeviceSimBinding{
		{DeviceID: devices[0].ID, IotCardID: cards[0].ID, SlotPosition: 1, BindStatus: 1, BindTime: &now},
		{DeviceID: devices[0].ID, IotCardID: cards[1].ID, SlotPosition: 2, BindStatus: 1, BindTime: &now},
		{DeviceID: devices[1].ID, IotCardID: cards[2].ID, SlotPosition: 1, BindStatus: 1, BindTime: &now},
	}
	for _, b := range bindings {
		require.NoError(t, tx.Create(b).Error)
	}

	return &testEnv{
		service:    svc,
		enterprise: enterprise,
		shop:       shop,
		devices:    devices,
		cards:      cards,
		bindings:   bindings,
		carrier:    carrier,
	}
}

func TestService_AllocateDevices(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	tests := []struct {
		name        string
		ctx         context.Context
		req         *dto.AllocateDevicesReq
		wantSuccess int
		wantFail    int
		wantErr     bool
	}{
		{
			name: "平台用户成功授权设备",
			ctx:  createTestContext(1, constants.UserTypePlatform, 0, 0),
			req: &dto.AllocateDevicesReq{
				DeviceNos: []string{env.devices[0].DeviceNo},
				Remark:    "测试授权",
			},
			wantSuccess: 1,
			wantFail:    0,
			wantErr:     false,
		},
		{
			name: "代理用户成功授权自己店铺的设备",
			ctx:  createTestContext(2, constants.UserTypeAgent, env.shop.ID, 0),
			req: &dto.AllocateDevicesReq{
				DeviceNos: []string{env.devices[1].DeviceNo},
			},
			wantSuccess: 1,
			wantFail:    0,
			wantErr:     false,
		},
		{
			name: "设备不存在时记录失败",
			ctx:  createTestContext(1, constants.UserTypePlatform, 0, 0),
			req: &dto.AllocateDevicesReq{
				DeviceNos: []string{"NOT_EXIST_DEVICE"},
			},
			wantSuccess: 0,
			wantFail:    1,
			wantErr:     false,
		},
		{
			name: "未授权用户返回错误",
			ctx:  context.Background(),
			req: &dto.AllocateDevicesReq{
				DeviceNos: []string{env.devices[2].DeviceNo},
			},
			wantSuccess: 0,
			wantFail:    0,
			wantErr:     true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			resp, err := env.service.AllocateDevices(tt.ctx, env.enterprise.ID, tt.req)
			if tt.wantErr {
				require.Error(t, err)
				return
			}
			require.NoError(t, err)
			assert.Equal(t, tt.wantSuccess, resp.SuccessCount)
			assert.Equal(t, tt.wantFail, resp.FailCount)
		})
	}
}

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

	prefix := uniqueServiceTestPrefix()

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	deviceStore := postgres.NewDeviceStore(tx, rdb)
	deviceSimBindingStore := postgres.NewDeviceSimBindingStore(tx, rdb)
	enterpriseDeviceAuthStore := postgres.NewEnterpriseDeviceAuthorizationStore(tx, rdb)
	enterpriseCardAuthStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	logger := zap.NewNop()

	svc := New(tx, enterpriseStore, deviceStore, deviceSimBindingStore, enterpriseDeviceAuthStore, enterpriseCardAuthStore, logger)

	enterprise := &model.Enterprise{
		EnterpriseName: prefix + "_测试企业",
		EnterpriseCode: prefix,
		Status:         1,
	}
	require.NoError(t, tx.Create(enterprise).Error)

	inStockDevice := &model.Device{
		DeviceNo:   prefix + "_INSTOCK",
		DeviceName: "在库设备",
		Status:     1,
	}
	require.NoError(t, tx.Create(inStockDevice).Error)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)

	t.Run("设备状态不是已分销时失败", func(t *testing.T) {
		req := &dto.AllocateDevicesReq{
			DeviceNos: []string{inStockDevice.DeviceNo},
		}

		resp, err := svc.AllocateDevices(ctx, enterprise.ID, req)
		require.NoError(t, err)
		assert.Equal(t, 0, resp.SuccessCount)
		assert.Equal(t, 1, resp.FailCount)
		assert.Contains(t, resp.FailedItems[0].Reason, "状态不正确")
	})
}

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

	prefix := uniqueServiceTestPrefix()

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	deviceStore := postgres.NewDeviceStore(tx, rdb)
	deviceSimBindingStore := postgres.NewDeviceSimBindingStore(tx, rdb)
	enterpriseDeviceAuthStore := postgres.NewEnterpriseDeviceAuthorizationStore(tx, rdb)
	enterpriseCardAuthStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	logger := zap.NewNop()

	svc := New(tx, enterpriseStore, deviceStore, deviceSimBindingStore, enterpriseDeviceAuthStore, enterpriseCardAuthStore, logger)

	shop1 := &model.Shop{ShopName: prefix + "_店铺1", ShopCode: prefix + "1", Level: 1, Status: 1}
	require.NoError(t, tx.Create(shop1).Error)

	shop2 := &model.Shop{ShopName: prefix + "_店铺2", ShopCode: prefix + "2", Level: 1, Status: 1}
	require.NoError(t, tx.Create(shop2).Error)

	enterprise := &model.Enterprise{
		EnterpriseName: prefix + "_测试企业",
		EnterpriseCode: prefix,
		Status:         1,
	}
	require.NoError(t, tx.Create(enterprise).Error)

	device := &model.Device{
		DeviceNo:   prefix + "_D001",
		DeviceName: "测试设备",
		Status:     2,
		ShopID:     &shop1.ID,
	}
	require.NoError(t, tx.Create(device).Error)

	t.Run("代理用户无法授权其他店铺的设备", func(t *testing.T) {
		ctx := createTestContext(1, constants.UserTypeAgent, shop2.ID, 0)
		req := &dto.AllocateDevicesReq{
			DeviceNos: []string{device.DeviceNo},
		}

		resp, err := svc.AllocateDevices(ctx, enterprise.ID, req)
		require.NoError(t, err)
		assert.Equal(t, 0, resp.SuccessCount)
		assert.Equal(t, 1, resp.FailCount)
		assert.Contains(t, resp.FailedItems[0].Reason, "无权操作")
	})
}

func TestService_AllocateDevices_DuplicateAuthorization(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)

	req := &dto.AllocateDevicesReq{
		DeviceNos: []string{env.devices[0].DeviceNo},
	}
	resp, err := env.service.AllocateDevices(ctx, env.enterprise.ID, req)
	require.NoError(t, err)
	assert.Equal(t, 1, resp.SuccessCount)

	t.Run("重复授权同一设备时失败", func(t *testing.T) {
		resp2, err := env.service.AllocateDevices(ctx, env.enterprise.ID, req)
		require.NoError(t, err)
		assert.Equal(t, 0, resp2.SuccessCount)
		assert.Equal(t, 1, resp2.FailCount)
		assert.Contains(t, resp2.FailedItems[0].Reason, "已授权")
	})
}

func TestService_AllocateDevices_CascadeCardAuthorization(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)

	t.Run("授权设备时级联授权绑定的卡", func(t *testing.T) {
		req := &dto.AllocateDevicesReq{
			DeviceNos: []string{env.devices[0].DeviceNo},
		}

		resp, err := env.service.AllocateDevices(ctx, env.enterprise.ID, req)
		require.NoError(t, err)
		assert.Equal(t, 1, resp.SuccessCount)
		assert.Len(t, resp.AuthorizedDevices, 1)
		assert.Equal(t, 2, resp.AuthorizedDevices[0].CardCount)
	})
}

func TestService_RecallDevices(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)

	allocateReq := &dto.AllocateDevicesReq{
		DeviceNos: []string{env.devices[0].DeviceNo, env.devices[1].DeviceNo},
	}
	_, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq)
	require.NoError(t, err)

	tests := []struct {
		name        string
		req         *dto.RecallDevicesReq
		wantSuccess int
		wantFail    int
		wantErr     bool
	}{
		{
			name: "成功撤销授权",
			req: &dto.RecallDevicesReq{
				DeviceNos: []string{env.devices[0].DeviceNo},
			},
			wantSuccess: 1,
			wantFail:    0,
			wantErr:     false,
		},
		{
			name: "设备不存在时失败",
			req: &dto.RecallDevicesReq{
				DeviceNos: []string{"NOT_EXIST"},
			},
			wantSuccess: 0,
			wantFail:    1,
			wantErr:     false,
		},
		{
			name: "设备未授权时失败",
			req: &dto.RecallDevicesReq{
				DeviceNos: []string{env.devices[2].DeviceNo},
			},
			wantSuccess: 0,
			wantFail:    1,
			wantErr:     false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			resp, err := env.service.RecallDevices(ctx, env.enterprise.ID, tt.req)
			if tt.wantErr {
				require.Error(t, err)
				return
			}
			require.NoError(t, err)
			assert.Equal(t, tt.wantSuccess, resp.SuccessCount)
			assert.Equal(t, tt.wantFail, resp.FailCount)
		})
	}
}

func TestService_RecallDevices_Unauthorized(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	t.Run("未授权用户返回错误", func(t *testing.T) {
		req := &dto.RecallDevicesReq{
			DeviceNos: []string{env.devices[0].DeviceNo},
		}

		_, err := env.service.RecallDevices(context.Background(), env.enterprise.ID, req)
		require.Error(t, err)
	})
}

func TestService_ListDevices(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)

	allocateReq := &dto.AllocateDevicesReq{
		DeviceNos: []string{env.devices[0].DeviceNo, env.devices[1].DeviceNo},
	}
	_, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq)
	require.NoError(t, err)

	tests := []struct {
		name      string
		req       *dto.EnterpriseDeviceListReq
		wantTotal int64
		wantLen   int
	}{
		{
			name:      "获取所有授权设备",
			req:       &dto.EnterpriseDeviceListReq{Page: 1, PageSize: 10},
			wantTotal: 2,
			wantLen:   2,
		},
		{
			name:      "分页查询",
			req:       &dto.EnterpriseDeviceListReq{Page: 1, PageSize: 1},
			wantTotal: 2,
			wantLen:   1,
		},
		{
			name:      "按设备号搜索",
			req:       &dto.EnterpriseDeviceListReq{Page: 1, PageSize: 10, DeviceNo: env.devices[0].DeviceNo},
			wantTotal: 2,
			wantLen:   1,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			resp, err := env.service.ListDevices(ctx, env.enterprise.ID, tt.req)
			require.NoError(t, err)
			assert.Equal(t, tt.wantTotal, resp.Total)
			assert.Len(t, resp.List, tt.wantLen)
		})
	}
}

func TestService_ListDevices_EnterpriseNotFound(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)

	t.Run("企业不存在返回错误", func(t *testing.T) {
		req := &dto.EnterpriseDeviceListReq{Page: 1, PageSize: 10}
		_, err := env.service.ListDevices(ctx, 99999, req)
		require.Error(t, err)
	})
}

func TestService_ListDevicesForEnterprise(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)
	allocateReq := &dto.AllocateDevicesReq{
		DeviceNos: []string{env.devices[0].DeviceNo},
	}
	_, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq)
	require.NoError(t, err)

	t.Run("企业用户获取自己的授权设备", func(t *testing.T) {
		enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, env.enterprise.ID)
		req := &dto.EnterpriseDeviceListReq{Page: 1, PageSize: 10}

		resp, err := env.service.ListDevicesForEnterprise(enterpriseCtx, req)
		require.NoError(t, err)
		assert.Equal(t, int64(1), resp.Total)
	})

	t.Run("未设置企业ID返回错误", func(t *testing.T) {
		req := &dto.EnterpriseDeviceListReq{Page: 1, PageSize: 10}
		_, err := env.service.ListDevicesForEnterprise(context.Background(), req)
		require.Error(t, err)
	})
}

func TestService_GetDeviceDetail(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)
	allocateReq := &dto.AllocateDevicesReq{
		DeviceNos: []string{env.devices[0].DeviceNo},
	}
	_, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq)
	require.NoError(t, err)

	enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, env.enterprise.ID)

	t.Run("成功获取设备详情", func(t *testing.T) {
		resp, err := env.service.GetDeviceDetail(enterpriseCtx, env.devices[0].ID)
		require.NoError(t, err)
		assert.Equal(t, env.devices[0].ID, resp.Device.DeviceID)
		assert.Equal(t, env.devices[0].DeviceNo, resp.Device.DeviceNo)
		assert.Len(t, resp.Cards, 2)
	})

	t.Run("设备未授权时返回错误", func(t *testing.T) {
		_, err := env.service.GetDeviceDetail(enterpriseCtx, env.devices[1].ID)
		require.Error(t, err)
	})

	t.Run("未设置企业ID返回错误", func(t *testing.T) {
		_, err := env.service.GetDeviceDetail(context.Background(), env.devices[0].ID)
		require.Error(t, err)
	})
}

func TestService_SuspendCard(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)
	allocateReq := &dto.AllocateDevicesReq{
		DeviceNos: []string{env.devices[0].DeviceNo},
	}
	_, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq)
	require.NoError(t, err)

	enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, env.enterprise.ID)

	t.Run("成功停机", func(t *testing.T) {
		req := &dto.DeviceCardOperationReq{Reason: "测试停机"}
		resp, err := env.service.SuspendCard(enterpriseCtx, env.devices[0].ID, env.cards[0].ID, req)
		require.NoError(t, err)
		assert.True(t, resp.Success)
	})

	t.Run("卡不属于设备时返回错误", func(t *testing.T) {
		req := &dto.DeviceCardOperationReq{Reason: "测试停机"}
		_, err := env.service.SuspendCard(enterpriseCtx, env.devices[0].ID, env.cards[3].ID, req)
		require.Error(t, err)
	})

	t.Run("设备未授权时返回错误", func(t *testing.T) {
		req := &dto.DeviceCardOperationReq{Reason: "测试停机"}
		_, err := env.service.SuspendCard(enterpriseCtx, env.devices[1].ID, env.cards[2].ID, req)
		require.Error(t, err)
	})

	t.Run("未设置企业ID返回错误", func(t *testing.T) {
		req := &dto.DeviceCardOperationReq{Reason: "测试停机"}
		_, err := env.service.SuspendCard(context.Background(), env.devices[0].ID, env.cards[0].ID, req)
		require.Error(t, err)
	})
}

func TestService_ResumeCard(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)
	allocateReq := &dto.AllocateDevicesReq{
		DeviceNos: []string{env.devices[0].DeviceNo},
	}
	_, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq)
	require.NoError(t, err)

	enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, env.enterprise.ID)

	t.Run("成功复机", func(t *testing.T) {
		req := &dto.DeviceCardOperationReq{Reason: "测试复机"}
		resp, err := env.service.ResumeCard(enterpriseCtx, env.devices[0].ID, env.cards[0].ID, req)
		require.NoError(t, err)
		assert.True(t, resp.Success)
	})

	t.Run("卡不属于设备时返回错误", func(t *testing.T) {
		req := &dto.DeviceCardOperationReq{Reason: "测试复机"}
		_, err := env.service.ResumeCard(enterpriseCtx, env.devices[0].ID, env.cards[3].ID, req)
		require.Error(t, err)
	})

	t.Run("设备未授权时返回错误", func(t *testing.T) {
		req := &dto.DeviceCardOperationReq{Reason: "测试复机"}
		_, err := env.service.ResumeCard(enterpriseCtx, env.devices[1].ID, env.cards[2].ID, req)
		require.Error(t, err)
	})

	t.Run("未设置企业ID返回错误", func(t *testing.T) {
		req := &dto.DeviceCardOperationReq{Reason: "测试复机"}
		_, err := env.service.ResumeCard(context.Background(), env.devices[0].ID, env.cards[0].ID, req)
		require.Error(t, err)
	})
}

func TestService_ListDevices_EmptyResult(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)

	t.Run("企业无授权设备时返回空列表", func(t *testing.T) {
		req := &dto.EnterpriseDeviceListReq{Page: 1, PageSize: 10}
		resp, err := env.service.ListDevices(ctx, env.enterprise.ID, req)
		require.NoError(t, err)
		assert.Equal(t, int64(0), resp.Total)
		assert.Empty(t, resp.List)
	})
}

func TestService_GetDeviceDetail_WithCarrierInfo(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)
	allocateReq := &dto.AllocateDevicesReq{
		DeviceNos: []string{env.devices[0].DeviceNo},
	}
	_, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq)
	require.NoError(t, err)

	enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, env.enterprise.ID)

	t.Run("获取设备详情包含运营商信息", func(t *testing.T) {
		resp, err := env.service.GetDeviceDetail(enterpriseCtx, env.devices[0].ID)
		require.NoError(t, err)
		assert.Len(t, resp.Cards, 2)
		for _, card := range resp.Cards {
			assert.NotEmpty(t, card.CarrierName)
		}
	})
}

func TestService_GetDeviceDetail_NetworkStatus(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)
	allocateReq := &dto.AllocateDevicesReq{
		DeviceNos: []string{env.devices[0].DeviceNo},
	}
	_, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq)
	require.NoError(t, err)

	enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, env.enterprise.ID)

	t.Run("网络状态名称正确", func(t *testing.T) {
		resp, err := env.service.GetDeviceDetail(enterpriseCtx, env.devices[0].ID)
		require.NoError(t, err)
		for _, card := range resp.Cards {
			if card.NetworkStatus == 1 {
				assert.Equal(t, "开机", card.NetworkStatusName)
			} else {
				assert.Equal(t, "停机", card.NetworkStatusName)
			}
		}
	})
}

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

	prefix := uniqueServiceTestPrefix()

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	deviceStore := postgres.NewDeviceStore(tx, rdb)
	deviceSimBindingStore := postgres.NewDeviceSimBindingStore(tx, rdb)
	enterpriseDeviceAuthStore := postgres.NewEnterpriseDeviceAuthorizationStore(tx, rdb)
	enterpriseCardAuthStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	logger := zap.NewNop()

	svc := New(tx, enterpriseStore, deviceStore, deviceSimBindingStore, enterpriseDeviceAuthStore, enterpriseCardAuthStore, logger)

	enterprise := &model.Enterprise{
		EnterpriseName: prefix + "_测试企业",
		EnterpriseCode: prefix,
		Status:         1,
	}
	require.NoError(t, tx.Create(enterprise).Error)

	device := &model.Device{
		DeviceNo:   prefix + "_D001",
		DeviceName: "无卡设备",
		Status:     2,
	}
	require.NoError(t, tx.Create(device).Error)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)
	allocateReq := &dto.AllocateDevicesReq{
		DeviceNos: []string{device.DeviceNo},
	}
	_, err := svc.AllocateDevices(ctx, enterprise.ID, allocateReq)
	require.NoError(t, err)

	t.Run("设备无绑定卡时返回空卡列表", func(t *testing.T) {
		enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, enterprise.ID)
		resp, err := svc.GetDeviceDetail(enterpriseCtx, device.ID)
		require.NoError(t, err)
		assert.Equal(t, device.ID, resp.Device.DeviceID)
		assert.Empty(t, resp.Cards)
	})
}

func TestService_RecallDevices_CascadeRevoke(t *testing.T) {
	prefix := uniqueServiceTestPrefix()
	env := setupTestEnv(t, prefix)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)

	allocateReq := &dto.AllocateDevicesReq{
		DeviceNos: []string{env.devices[0].DeviceNo},
	}
	resp, err := env.service.AllocateDevices(ctx, env.enterprise.ID, allocateReq)
	require.NoError(t, err)
	assert.Equal(t, 2, resp.AuthorizedDevices[0].CardCount)

	t.Run("撤销设备授权时级联撤销卡授权", func(t *testing.T) {
		recallReq := &dto.RecallDevicesReq{
			DeviceNos: []string{env.devices[0].DeviceNo},
		}

		recallResp, err := env.service.RecallDevices(ctx, env.enterprise.ID, recallReq)
		require.NoError(t, err)
		assert.Equal(t, 1, recallResp.SuccessCount)
	})
}

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

	prefix := uniqueServiceTestPrefix()

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	deviceStore := postgres.NewDeviceStore(tx, rdb)
	deviceSimBindingStore := postgres.NewDeviceSimBindingStore(tx, rdb)
	enterpriseDeviceAuthStore := postgres.NewEnterpriseDeviceAuthorizationStore(tx, rdb)
	enterpriseCardAuthStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	logger := zap.NewNop()

	svc := New(tx, enterpriseStore, deviceStore, deviceSimBindingStore, enterpriseDeviceAuthStore, enterpriseCardAuthStore, logger)

	enterprise := &model.Enterprise{
		EnterpriseName: prefix + "_测试企业",
		EnterpriseCode: prefix,
		Status:         1,
	}
	require.NoError(t, tx.Create(enterprise).Error)

	carrier := &model.Carrier{
		CarrierName: "测试运营商",
		CarrierType: "CMCC",
		Status:      1,
	}
	require.NoError(t, tx.Create(carrier).Error)

	device := &model.Device{
		DeviceNo:   prefix + "_D001",
		DeviceName: "测试设备",
		Status:     2,
	}
	require.NoError(t, tx.Create(device).Error)

	card := &model.IotCard{
		ICCID:         prefix + "0001",
		CardType:      "normal",
		CarrierID:     carrier.ID,
		Status:        2,
		NetworkStatus: 1,
	}
	require.NoError(t, tx.Create(card).Error)

	now := time.Now()
	binding := &model.DeviceSimBinding{
		DeviceID:     device.ID,
		IotCardID:    card.ID,
		SlotPosition: 1,
		BindStatus:   1,
		BindTime:     &now,
	}
	require.NoError(t, tx.Create(binding).Error)

	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)
	allocateReq := &dto.AllocateDevicesReq{
		DeviceNos: []string{device.DeviceNo},
	}
	_, err := svc.AllocateDevices(ctx, enterprise.ID, allocateReq)
	require.NoError(t, err)

	t.Run("开机状态卡显示正确", func(t *testing.T) {
		enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, enterprise.ID)
		resp, err := svc.GetDeviceDetail(enterpriseCtx, device.ID)
		require.NoError(t, err)
		assert.Len(t, resp.Cards, 1)
		assert.Equal(t, 1, resp.Cards[0].NetworkStatus)
		assert.Equal(t, "开机", resp.Cards[0].NetworkStatusName)
	})
}

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

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	deviceStore := postgres.NewDeviceStore(tx, rdb)
	deviceSimBindingStore := postgres.NewDeviceSimBindingStore(tx, rdb)
	enterpriseDeviceAuthStore := postgres.NewEnterpriseDeviceAuthorizationStore(tx, rdb)
	enterpriseCardAuthStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	logger := zap.NewNop()

	svc := New(tx, enterpriseStore, deviceStore, deviceSimBindingStore, enterpriseDeviceAuthStore, enterpriseCardAuthStore, logger)
	ctx := createTestContext(1, constants.UserTypePlatform, 0, 0)

	t.Run("AllocateDevices企业不存在", func(t *testing.T) {
		req := &dto.AllocateDevicesReq{DeviceNos: []string{"D001"}}
		_, err := svc.AllocateDevices(ctx, 99999, req)
		require.Error(t, err)
	})

	t.Run("RecallDevices企业不存在", func(t *testing.T) {
		req := &dto.RecallDevicesReq{DeviceNos: []string{"D001"}}
		_, err := svc.RecallDevices(ctx, 99999, req)
		require.Error(t, err)
	})
}

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

	prefix := uniqueServiceTestPrefix()

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	deviceStore := postgres.NewDeviceStore(tx, rdb)
	deviceSimBindingStore := postgres.NewDeviceSimBindingStore(tx, rdb)
	enterpriseDeviceAuthStore := postgres.NewEnterpriseDeviceAuthorizationStore(tx, rdb)
	enterpriseCardAuthStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	logger := zap.NewNop()

	svc := New(tx, enterpriseStore, deviceStore, deviceSimBindingStore, enterpriseDeviceAuthStore, enterpriseCardAuthStore, logger)

	enterprise := &model.Enterprise{
		EnterpriseName: prefix + "_测试企业",
		EnterpriseCode: prefix,
		Status:         1,
	}
	require.NoError(t, tx.Create(enterprise).Error)

	carrier := &model.Carrier{
		CarrierName: "测试运营商",
		CarrierType: "CMCC",
		Status:      1,
	}
	require.NoError(t, tx.Create(carrier).Error)

	device := &model.Device{
		DeviceNo:   prefix + "_D001",
		DeviceName: "测试设备",
		Status:     2,
	}
	require.NoError(t, tx.Create(device).Error)

	card := &model.IotCard{
		ICCID:     prefix + "0001",
		CardType:  "normal",
		CarrierID: carrier.ID,
		Status:    2,
	}
	require.NoError(t, tx.Create(card).Error)

	now := time.Now()
	binding := &model.DeviceSimBinding{
		DeviceID:     device.ID,
		IotCardID:    card.ID,
		SlotPosition: 1,
		BindStatus:   1,
		BindTime:     &now,
	}
	require.NoError(t, tx.Create(binding).Error)

	deviceAuth := &model.EnterpriseDeviceAuthorization{
		EnterpriseID:   enterprise.ID,
		DeviceID:       device.ID,
		AuthorizedBy:   1,
		AuthorizedAt:   now,
		AuthorizerType: 2,
		RevokedBy:      ptrUintED(1),
		RevokedAt:      &now,
	}
	require.NoError(t, tx.Create(deviceAuth).Error)

	t.Run("已撤销的设备授权无法操作卡", func(t *testing.T) {
		enterpriseCtx := createTestContext(1, constants.UserTypeEnterprise, 0, enterprise.ID)
		req := &dto.DeviceCardOperationReq{Reason: "测试"}
		_, err := svc.SuspendCard(enterpriseCtx, device.ID, card.ID, req)
		require.Error(t, err)
	})
}

func ptrUintED(v uint) *uint {
	return &v
}
