package postgres

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

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/tests/testutils"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

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

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

	store := NewEnterpriseCardAuthorizationStore(tx, rdb)
	ctx := context.Background()

	prefix := uniqueCardAuthTestPrefix()

	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)

	cards := []*model.IotCard{
		{ICCID: prefix + "0001", CardType: "normal", CarrierID: carrier.ID, Status: 2},
		{ICCID: prefix + "0002", CardType: "normal", CarrierID: carrier.ID, Status: 2},
		{ICCID: prefix + "0003", CardType: "normal", CarrierID: carrier.ID, Status: 2},
	}
	for _, c := range cards {
		require.NoError(t, tx.Create(c).Error)
	}

	deviceAuthID := uint(12345)
	now := time.Now()
	auths := []*model.EnterpriseCardAuthorization{
		{EnterpriseID: enterprise.ID, CardID: cards[0].ID, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: 2, DeviceAuthID: &deviceAuthID},
		{EnterpriseID: enterprise.ID, CardID: cards[1].ID, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: 2, DeviceAuthID: &deviceAuthID},
		{EnterpriseID: enterprise.ID, CardID: cards[2].ID, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: 2, DeviceAuthID: nil},
	}
	for _, auth := range auths {
		require.NoError(t, store.Create(ctx, auth))
	}

	t.Run("成功撤销指定设备授权ID关联的卡授权", func(t *testing.T) {
		revokerID := uint(2)
		err := store.RevokeByDeviceAuthID(ctx, deviceAuthID, revokerID)
		require.NoError(t, err)

		result, err := store.ListByEnterprise(ctx, enterprise.ID, false)
		require.NoError(t, err)
		assert.Len(t, result, 1)
		assert.Equal(t, cards[2].ID, result[0].CardID)

		revokedResult, err := store.ListByEnterprise(ctx, enterprise.ID, true)
		require.NoError(t, err)
		assert.Len(t, revokedResult, 3)

		for _, auth := range revokedResult {
			if auth.DeviceAuthID != nil && *auth.DeviceAuthID == deviceAuthID {
				assert.NotNil(t, auth.RevokedAt)
				assert.NotNil(t, auth.RevokedBy)
				assert.Equal(t, revokerID, *auth.RevokedBy)
			}
		}
	})

	t.Run("设备授权ID不存在时不报错", func(t *testing.T) {
		err := store.RevokeByDeviceAuthID(ctx, 99999, uint(1))
		require.NoError(t, err)
	})
}

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

	store := NewEnterpriseCardAuthorizationStore(tx, rdb)
	ctx := context.Background()

	prefix := uniqueCardAuthTestPrefix()

	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)

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

	t.Run("成功创建卡授权记录", func(t *testing.T) {
		auth := &model.EnterpriseCardAuthorization{
			EnterpriseID:   enterprise.ID,
			CardID:         card.ID,
			AuthorizedBy:   1,
			AuthorizedAt:   time.Now(),
			AuthorizerType: 2,
			Remark:         "测试授权",
		}

		err := store.Create(ctx, auth)
		require.NoError(t, err)
		assert.NotZero(t, auth.ID)
	})
}

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

	store := NewEnterpriseCardAuthorizationStore(tx, rdb)
	ctx := context.Background()

	prefix := uniqueCardAuthTestPrefix()

	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)

	cards := []*model.IotCard{
		{ICCID: prefix + "0001", CardType: "normal", CarrierID: carrier.ID, Status: 2},
		{ICCID: prefix + "0002", CardType: "normal", CarrierID: carrier.ID, Status: 2},
	}
	for _, c := range cards {
		require.NoError(t, tx.Create(c).Error)
	}

	t.Run("成功批量创建卡授权记录", func(t *testing.T) {
		now := time.Now()
		auths := []*model.EnterpriseCardAuthorization{
			{EnterpriseID: enterprise.ID, CardID: cards[0].ID, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: 2},
			{EnterpriseID: enterprise.ID, CardID: cards[1].ID, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: 2},
		}

		err := store.BatchCreate(ctx, auths)
		require.NoError(t, err)

		for _, auth := range auths {
			assert.NotZero(t, auth.ID)
		}
	})

	t.Run("空列表不报错", func(t *testing.T) {
		err := store.BatchCreate(ctx, []*model.EnterpriseCardAuthorization{})
		require.NoError(t, err)
	})
}

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

	store := NewEnterpriseCardAuthorizationStore(tx, rdb)
	ctx := context.Background()

	prefix := uniqueCardAuthTestPrefix()

	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)

	cards := []*model.IotCard{
		{ICCID: prefix + "0001", CardType: "normal", CarrierID: carrier.ID, Status: 2},
		{ICCID: prefix + "0002", CardType: "normal", CarrierID: carrier.ID, Status: 2},
	}
	for _, c := range cards {
		require.NoError(t, tx.Create(c).Error)
	}

	now := time.Now()
	auths := []*model.EnterpriseCardAuthorization{
		{EnterpriseID: enterprise.ID, CardID: cards[0].ID, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: 2},
		{EnterpriseID: enterprise.ID, CardID: cards[1].ID, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: 2, RevokedBy: ptrUintCA(1), RevokedAt: &now},
	}
	for _, auth := range auths {
		require.NoError(t, store.Create(ctx, auth))
	}

	t.Run("获取未撤销的授权记录", func(t *testing.T) {
		result, err := store.ListByEnterprise(ctx, enterprise.ID, false)
		require.NoError(t, err)
		assert.Len(t, result, 1)
		assert.Equal(t, cards[0].ID, result[0].CardID)
	})

	t.Run("获取所有授权记录包括已撤销", func(t *testing.T) {
		result, err := store.ListByEnterprise(ctx, enterprise.ID, true)
		require.NoError(t, err)
		assert.Len(t, result, 2)
	})
}

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

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

	store := NewEnterpriseCardAuthorizationStore(tx, rdb)
	ctx := context.Background()

	prefix := uniqueCardAuthTestPrefix()

	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)

	cards := []*model.IotCard{
		{ICCID: prefix + "0001", CardType: "normal", CarrierID: carrier.ID, Status: 2},
		{ICCID: prefix + "0002", CardType: "normal", CarrierID: carrier.ID, Status: 2},
		{ICCID: prefix + "0003", CardType: "normal", CarrierID: carrier.ID, Status: 2},
	}
	for _, c := range cards {
		require.NoError(t, tx.Create(c).Error)
	}

	now := time.Now()
	auths := []*model.EnterpriseCardAuthorization{
		{EnterpriseID: enterprise.ID, CardID: cards[0].ID, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: 2},
		{EnterpriseID: enterprise.ID, CardID: cards[1].ID, AuthorizedBy: 1, AuthorizedAt: now, AuthorizerType: 2, RevokedBy: ptrUintCA(1), RevokedAt: &now},
	}
	for _, auth := range auths {
		require.NoError(t, store.Create(ctx, auth))
	}

	t.Run("获取有效授权的卡ID映射", func(t *testing.T) {
		cardIDs := []uint{cards[0].ID, cards[1].ID, cards[2].ID}
		result, err := store.GetActiveAuthsByCardIDs(ctx, enterprise.ID, cardIDs)
		require.NoError(t, err)

		assert.True(t, result[cards[0].ID])
		assert.False(t, result[cards[1].ID])
		assert.False(t, result[cards[2].ID])
	})

	t.Run("空卡ID列表返回空映射", func(t *testing.T) {
		result, err := store.GetActiveAuthsByCardIDs(ctx, enterprise.ID, []uint{})
		require.NoError(t, err)
		assert.Empty(t, result)
	})
}
