package enterprise_card

import (
	"context"
	"testing"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"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"
)

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

	logger, _ := zap.NewDevelopment()

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	iotCardStore := postgres.NewIotCardStore(tx, rdb)
	authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)

	service := NewAuthorizationService(enterpriseStore, iotCardStore, authStore, logger)

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

	enterprise := &model.Enterprise{
		BaseModel:      model.BaseModel{Creator: 1, Updater: 1},
		EnterpriseName: "测试企业",
		EnterpriseCode: "TEST_ENT_001",
		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)

	unboundCard := &model.IotCard{
		ICCID:     "UNBOUND_CARD_001",
		CardType:  "normal",
		CarrierID: carrier.ID,
		Status:    2,
		ShopID:    &shop.ID,
	}
	require.NoError(t, tx.Create(unboundCard).Error)

	boundCard := &model.IotCard{
		ICCID:     "BOUND_CARD_001",
		CardType:  "normal",
		CarrierID: carrier.ID,
		Status:    2,
		ShopID:    &shop.ID,
	}
	require.NoError(t, tx.Create(boundCard).Error)

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

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

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

	t.Run("绑定设备的卡被拒绝授权", func(t *testing.T) {
		req := BatchAuthorizeRequest{
			EnterpriseID:   enterprise.ID,
			CardIDs:        []uint{boundCard.ID},
			AuthorizerID:   1,
			AuthorizerType: constants.UserTypePlatform,
			Remark:         "测试授权",
		}

		err := service.BatchAuthorize(ctx, req)

		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok, "应返回 AppError 类型")
		assert.Equal(t, errors.CodeCannotAuthorizeBoundCard, appErr.Code)
		assert.Contains(t, appErr.Message, "已绑定设备")
	})

	t.Run("未绑定设备的卡可以授权", func(t *testing.T) {
		req := BatchAuthorizeRequest{
			EnterpriseID:   enterprise.ID,
			CardIDs:        []uint{unboundCard.ID},
			AuthorizerID:   1,
			AuthorizerType: constants.UserTypePlatform,
			Remark:         "测试授权",
		}

		err := service.BatchAuthorize(ctx, req)

		require.NoError(t, err)

		auths, err := authStore.ListByCards(ctx, []uint{unboundCard.ID}, false)
		require.NoError(t, err)
		assert.Len(t, auths, 1)
		assert.Equal(t, enterprise.ID, auths[0].EnterpriseID)
	})

	t.Run("混合卡列表中有绑定卡时整体拒绝", func(t *testing.T) {
		unboundCard2 := &model.IotCard{
			ICCID:     "UNBOUND_CARD_002",
			CardType:  "normal",
			CarrierID: carrier.ID,
			Status:    2,
			ShopID:    &shop.ID,
		}
		require.NoError(t, tx.Create(unboundCard2).Error)

		req := BatchAuthorizeRequest{
			EnterpriseID:   enterprise.ID,
			CardIDs:        []uint{unboundCard2.ID, boundCard.ID},
			AuthorizerID:   1,
			AuthorizerType: constants.UserTypePlatform,
			Remark:         "测试授权",
		}

		err := service.BatchAuthorize(ctx, req)

		require.Error(t, err)
		appErr, ok := err.(*errors.AppError)
		require.True(t, ok, "应返回 AppError 类型")
		assert.Equal(t, errors.CodeCannotAuthorizeBoundCard, appErr.Code)

		auths, err := authStore.ListByCards(ctx, []uint{unboundCard2.ID}, false)
		require.NoError(t, err)
		assert.Len(t, auths, 0, "混合列表中的未绑定卡也不应被授权")
	})
}
