package unit

import (
	"context"
	"testing"
	"time"

	pkggorm "github.com/break/junhong_cmp_fiber/pkg/gorm"
	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/service/enterprise_card"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/tests/testutils"
)

func createAgentContext(userID, shopID uint) context.Context {
	ctx := context.Background()
	ctx = context.WithValue(ctx, constants.ContextKeyUserID, userID)
	ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypeAgent)
	ctx = context.WithValue(ctx, constants.ContextKeyShopID, shopID)
	return ctx
}

func createPlatformContext(userID uint) context.Context {
	ctx := context.Background()
	ctx = context.WithValue(ctx, constants.ContextKeyUserID, userID)
	ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypePlatform)
	ctx = context.WithValue(ctx, constants.ContextKeyShopID, uint(0))
	return ctx
}

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

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	iotCardStore := postgres.NewIotCardStore(tx, rdb)
	authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)

	shop1ID := uint(100)
	shop2ID := uint(200)

	ent := &model.Enterprise{
		EnterpriseName: "代理1的企业",
		EnterpriseCode: "ENT_PERM_001",
		OwnerShopID:    &shop1ID,
		Status:         constants.StatusEnabled,
	}
	ent.Creator = 1
	ent.Updater = 1
	err := tx.Create(ent).Error
	require.NoError(t, err)

	card1 := &model.IotCard{ICCID: "PERM_CARD_001", MSISDN: "13800001001", Status: 1, ShopID: &shop1ID}
	card2 := &model.IotCard{ICCID: "PERM_CARD_002", MSISDN: "13800001002", Status: 1, ShopID: &shop2ID}
	err = tx.Create(card1).Error
	require.NoError(t, err)
	err = tx.Create(card2).Error
	require.NoError(t, err)

	t.Run("代理可以授权自己店铺的卡", func(t *testing.T) {
		ctx := createAgentContext(1, shop1ID)
		err := authService.BatchAuthorize(ctx, enterprise_card.BatchAuthorizeRequest{
			EnterpriseID:   ent.ID,
			CardIDs:        []uint{card1.ID},
			AuthorizerID:   1,
			AuthorizerType: constants.UserTypeAgent,
		})
		assert.NoError(t, err)
	})

	t.Run("代理不能授权其他店铺的卡", func(t *testing.T) {
		ctx := createAgentContext(1, shop1ID)
		err := authService.BatchAuthorize(ctx, enterprise_card.BatchAuthorizeRequest{
			EnterpriseID:   ent.ID,
			CardIDs:        []uint{card2.ID},
			AuthorizerID:   1,
			AuthorizerType: constants.UserTypeAgent,
		})
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "不属于您的店铺")
	})
}

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

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	iotCardStore := postgres.NewIotCardStore(tx, rdb)
	authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)

	shop1ID := uint(101)
	shop2ID := uint(201)

	ent1 := &model.Enterprise{
		EnterpriseName: "代理1的企业",
		EnterpriseCode: "ENT_PERM_101",
		OwnerShopID:    &shop1ID,
		Status:         constants.StatusEnabled,
	}
	ent1.Creator = 1
	ent1.Updater = 1
	err := tx.Create(ent1).Error
	require.NoError(t, err)

	ent2 := &model.Enterprise{
		EnterpriseName: "代理2的企业",
		EnterpriseCode: "ENT_PERM_201",
		OwnerShopID:    &shop2ID,
		Status:         constants.StatusEnabled,
	}
	ent2.Creator = 2
	ent2.Updater = 2
	err = tx.Create(ent2).Error
	require.NoError(t, err)

	card := &model.IotCard{ICCID: "PERM_CARD_101", MSISDN: "13800002001", Status: 1, ShopID: &shop1ID}
	err = tx.Create(card).Error
	require.NoError(t, err)

	t.Run("代理可以授权给自己的企业", func(t *testing.T) {
		ctx := createAgentContext(1, shop1ID)
		err := authService.BatchAuthorize(ctx, enterprise_card.BatchAuthorizeRequest{
			EnterpriseID:   ent1.ID,
			CardIDs:        []uint{card.ID},
			AuthorizerID:   1,
			AuthorizerType: constants.UserTypeAgent,
		})
		assert.NoError(t, err)
	})

	card2 := &model.IotCard{ICCID: "PERM_CARD_102", MSISDN: "13800002002", Status: 1, ShopID: &shop1ID}
	err = tx.Create(card2).Error
	require.NoError(t, err)

	t.Run("代理不能授权给其他代理的企业", func(t *testing.T) {
		ctx := createAgentContext(1, shop1ID)
		err := authService.BatchAuthorize(ctx, enterprise_card.BatchAuthorizeRequest{
			EnterpriseID:   ent2.ID,
			CardIDs:        []uint{card2.ID},
			AuthorizerID:   1,
			AuthorizerType: constants.UserTypeAgent,
		})
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "只能授权给自己的企业")
	})
}

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

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	iotCardStore := postgres.NewIotCardStore(tx, rdb)
	authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)

	shop1ID := uint(301)
	shop2ID := uint(302)

	ent := &model.Enterprise{
		EnterpriseName: "平台测试企业",
		EnterpriseCode: "ENT_PLAT_001",
		OwnerShopID:    &shop1ID,
		Status:         constants.StatusEnabled,
	}
	ent.Creator = 1
	ent.Updater = 1
	err := tx.Create(ent).Error
	require.NoError(t, err)

	card1 := &model.IotCard{ICCID: "PLAT_CARD_001", MSISDN: "13800003001", Status: 1, ShopID: &shop1ID}
	card2 := &model.IotCard{ICCID: "PLAT_CARD_002", MSISDN: "13800003002", Status: 1, ShopID: &shop2ID}
	err = tx.Create(card1).Error
	require.NoError(t, err)
	err = tx.Create(card2).Error
	require.NoError(t, err)

	ctx := createPlatformContext(1)

	t.Run("平台可以授权任意店铺的卡", func(t *testing.T) {
		err := authService.BatchAuthorize(ctx, enterprise_card.BatchAuthorizeRequest{
			EnterpriseID:   ent.ID,
			CardIDs:        []uint{card1.ID, card2.ID},
			AuthorizerID:   1,
			AuthorizerType: constants.UserTypePlatform,
		})
		assert.NoError(t, err)
	})
}

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

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	iotCardStore := postgres.NewIotCardStore(tx, rdb)
	authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)

	shopID := uint(401)
	ent := &model.Enterprise{
		EnterpriseName: "绑定测试企业",
		EnterpriseCode: "ENT_BOUND_001",
		OwnerShopID:    &shopID,
		Status:         constants.StatusEnabled,
	}
	ent.Creator = 1
	ent.Updater = 1
	err := tx.Create(ent).Error
	require.NoError(t, err)

	card := &model.IotCard{
		ICCID:  "BOUND_CARD_001",
		MSISDN: "13800004001",
		Status: 1,
		ShopID: &shopID,
	}
	err = tx.Create(card).Error
	require.NoError(t, err)

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

	ctx := createPlatformContext(1)
	err = authService.BatchAuthorize(ctx, enterprise_card.BatchAuthorizeRequest{
		EnterpriseID:   ent.ID,
		CardIDs:        []uint{card.ID},
		AuthorizerID:   1,
		AuthorizerType: constants.UserTypePlatform,
	})
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "已绑定设备")
}

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

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	iotCardStore := postgres.NewIotCardStore(tx, rdb)
	authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)

	ent := &model.Enterprise{
		EnterpriseName: "未分销测试企业",
		EnterpriseCode: "ENT_UNDIST_001",
		Status:         constants.StatusEnabled,
	}
	ent.Creator = 1
	ent.Updater = 1
	err := tx.Create(ent).Error
	require.NoError(t, err)

	card := &model.IotCard{
		ICCID:  "UNDIST_CARD_001",
		MSISDN: "13800005001",
		Status: 1,
		ShopID: nil,
	}
	err = tx.Create(card).Error
	require.NoError(t, err)

	ctx := createPlatformContext(1)
	err = authService.BatchAuthorize(ctx, enterprise_card.BatchAuthorizeRequest{
		EnterpriseID:   ent.ID,
		CardIDs:        []uint{card.ID},
		AuthorizerID:   1,
		AuthorizerType: constants.UserTypePlatform,
	})
	assert.Error(t, err)
	assert.Contains(t, err.Error(), "未分销")
}

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

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	iotCardStore := postgres.NewIotCardStore(tx, rdb)
	authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)

	shopID := uint(501)
	ent := &model.Enterprise{
		EnterpriseName: "回收测试企业",
		EnterpriseCode: "ENT_REVOKE_001",
		OwnerShopID:    &shopID,
		Status:         constants.StatusEnabled,
	}
	ent.Creator = 1
	ent.Updater = 1
	err := tx.Create(ent).Error
	require.NoError(t, err)

	card := &model.IotCard{ICCID: "REVOKE_CARD_001", MSISDN: "13800006001", Status: 1, ShopID: &shopID}
	err = tx.Create(card).Error
	require.NoError(t, err)

	now := time.Now()
	auth := &model.EnterpriseCardAuthorization{
		EnterpriseID:   ent.ID,
		CardID:         card.ID,
		AuthorizedBy:   1,
		AuthorizedAt:   now,
		AuthorizerType: constants.UserTypeAgent,
	}
	err = authStore.Create(context.Background(), auth)
	require.NoError(t, err)

	t.Run("代理可以回收自己创建的授权", func(t *testing.T) {
		ctx := createAgentContext(1, shopID)
		err := authService.RevokeAuthorizations(ctx, enterprise_card.RevokeAuthorizationsRequest{
			EnterpriseID: ent.ID,
			CardIDs:      []uint{card.ID},
			RevokedBy:    1,
		})
		assert.NoError(t, err)
	})

	card2 := &model.IotCard{ICCID: "REVOKE_CARD_002", MSISDN: "13800006002", Status: 1, ShopID: &shopID}
	err = tx.Create(card2).Error
	require.NoError(t, err)

	auth2 := &model.EnterpriseCardAuthorization{
		EnterpriseID:   ent.ID,
		CardID:         card2.ID,
		AuthorizedBy:   999,
		AuthorizedAt:   now,
		AuthorizerType: constants.UserTypeAgent,
	}
	err = authStore.Create(context.Background(), auth2)
	require.NoError(t, err)

	t.Run("代理不能回收其他人创建的授权", func(t *testing.T) {
		ctx := createAgentContext(1, shopID)
		err := authService.RevokeAuthorizations(ctx, enterprise_card.RevokeAuthorizationsRequest{
			EnterpriseID: ent.ID,
			CardIDs:      []uint{card2.ID},
			RevokedBy:    1,
		})
		assert.Error(t, err)
		assert.Contains(t, err.Error(), "只能回收自己创建的授权")
	})

	t.Run("平台可以回收任何授权", func(t *testing.T) {
		ctx := createPlatformContext(2)
		err := authService.RevokeAuthorizations(ctx, enterprise_card.RevokeAuthorizationsRequest{
			EnterpriseID: ent.ID,
			CardIDs:      []uint{card2.ID},
			RevokedBy:    2,
		})
		assert.NoError(t, err)
	})
}

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

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	iotCardStore := postgres.NewIotCardStore(tx, rdb)
	authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)

	shopID := uint(600)
	ent := &model.Enterprise{
		EnterpriseName: "列表测试企业",
		EnterpriseCode: "ENT_LIST_001",
		OwnerShopID:    &shopID,
		Status:         constants.StatusEnabled,
	}
	ent.Creator = 1
	ent.Updater = 1
	err := tx.Create(ent).Error
	require.NoError(t, err)

	card1 := &model.IotCard{ICCID: "LIST_CARD_001", MSISDN: "13800007001", Status: 1, ShopID: &shopID}
	card2 := &model.IotCard{ICCID: "LIST_CARD_002", MSISDN: "13800007002", Status: 1, ShopID: &shopID}
	err = tx.Create(card1).Error
	require.NoError(t, err)
	err = tx.Create(card2).Error
	require.NoError(t, err)

	account := &model.Account{
		Username: "test_authorizer",
		Phone:    "13800008001",
		Password: "hashed",
		UserType: constants.UserTypePlatform,
		Status:   constants.StatusEnabled,
	}
	account.Creator = 1
	account.Updater = 1
	err = tx.Create(account).Error
	require.NoError(t, err)

	now := time.Now()
	auth1 := &model.EnterpriseCardAuthorization{
		EnterpriseID:   ent.ID,
		CardID:         card1.ID,
		AuthorizedBy:   account.ID,
		AuthorizedAt:   now,
		AuthorizerType: constants.UserTypePlatform,
		Remark:         "测试备注1",
	}
	auth2 := &model.EnterpriseCardAuthorization{
		EnterpriseID:   ent.ID,
		CardID:         card2.ID,
		AuthorizedBy:   account.ID,
		AuthorizedAt:   now,
		AuthorizerType: constants.UserTypePlatform,
		Remark:         "测试备注2",
	}
	err = authStore.Create(context.Background(), auth1)
	require.NoError(t, err)
	err = authStore.Create(context.Background(), auth2)
	require.NoError(t, err)

	ctx := pkggorm.SkipDataPermission(context.Background())

	t.Run("分页查询授权记录", func(t *testing.T) {
		resp, err := authService.ListRecords(ctx, enterprise_card.ListRecordsRequest{
			Page:     1,
			PageSize: 10,
		})
		require.NoError(t, err)
		assert.GreaterOrEqual(t, resp.Total, int64(2))
		assert.GreaterOrEqual(t, len(resp.Items), 2)
	})

	t.Run("按企业ID筛选", func(t *testing.T) {
		resp, err := authService.ListRecords(ctx, enterprise_card.ListRecordsRequest{
			EnterpriseID: &ent.ID,
			Page:         1,
			PageSize:     10,
		})
		require.NoError(t, err)
		assert.Equal(t, int64(2), resp.Total)
		for _, item := range resp.Items {
			assert.Equal(t, ent.ID, item.EnterpriseID)
		}
	})

	t.Run("按ICCID筛选", func(t *testing.T) {
		resp, err := authService.ListRecords(ctx, enterprise_card.ListRecordsRequest{
			ICCID:    "LIST_CARD_001",
			Page:     1,
			PageSize: 10,
		})
		require.NoError(t, err)
		assert.Equal(t, int64(1), resp.Total)
		assert.Equal(t, "LIST_CARD_001", resp.Items[0].ICCID)
	})

	t.Run("按状态筛选-有效授权", func(t *testing.T) {
		status := 1
		resp, err := authService.ListRecords(ctx, enterprise_card.ListRecordsRequest{
			EnterpriseID: &ent.ID,
			Status:       &status,
			Page:         1,
			PageSize:     10,
		})
		require.NoError(t, err)
		assert.Equal(t, int64(2), resp.Total)
		for _, item := range resp.Items {
			assert.Equal(t, 1, item.Status)
		}
	})
}

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

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	iotCardStore := postgres.NewIotCardStore(tx, rdb)
	authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)

	shopID := uint(700)
	ent := &model.Enterprise{
		EnterpriseName: "详情测试企业",
		EnterpriseCode: "ENT_DETAIL_001",
		OwnerShopID:    &shopID,
		Status:         constants.StatusEnabled,
	}
	ent.Creator = 1
	ent.Updater = 1
	err := tx.Create(ent).Error
	require.NoError(t, err)

	card := &model.IotCard{ICCID: "DETAIL_CARD_001", MSISDN: "13800009001", Status: 1, ShopID: &shopID}
	err = tx.Create(card).Error
	require.NoError(t, err)

	account := &model.Account{
		Username: "detail_authorizer",
		Phone:    "13800009002",
		Password: "hashed",
		UserType: constants.UserTypePlatform,
		Status:   constants.StatusEnabled,
	}
	account.Creator = 1
	account.Updater = 1
	err = tx.Create(account).Error
	require.NoError(t, err)

	auth := &model.EnterpriseCardAuthorization{
		EnterpriseID:   ent.ID,
		CardID:         card.ID,
		AuthorizedBy:   account.ID,
		AuthorizedAt:   time.Now(),
		AuthorizerType: constants.UserTypePlatform,
		Remark:         "详情测试备注",
	}
	err = authStore.Create(context.Background(), auth)
	require.NoError(t, err)

	ctx := pkggorm.SkipDataPermission(context.Background())

	t.Run("获取授权记录详情", func(t *testing.T) {
		detail, err := authService.GetRecordDetail(ctx, auth.ID)
		require.NoError(t, err)
		assert.Equal(t, auth.ID, detail.ID)
		assert.Equal(t, ent.ID, detail.EnterpriseID)
		assert.Equal(t, "详情测试企业", detail.EnterpriseName)
		assert.Equal(t, card.ID, detail.CardID)
		assert.Equal(t, "DETAIL_CARD_001", detail.ICCID)
		assert.Equal(t, "详情测试备注", detail.Remark)
		assert.Equal(t, 1, detail.Status)
	})

	t.Run("获取不存在的记录", func(t *testing.T) {
		_, err := authService.GetRecordDetail(ctx, 99999)
		assert.Error(t, err)
	})
}

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

	enterpriseStore := postgres.NewEnterpriseStore(tx, rdb)
	iotCardStore := postgres.NewIotCardStore(tx, rdb)
	authStore := postgres.NewEnterpriseCardAuthorizationStore(tx, rdb)
	authService := enterprise_card.NewAuthorizationService(enterpriseStore, iotCardStore, authStore, nil)

	shopID := uint(800)
	ent := &model.Enterprise{
		EnterpriseName: "备注测试企业",
		EnterpriseCode: "ENT_REMARK_001",
		OwnerShopID:    &shopID,
		Status:         constants.StatusEnabled,
	}
	ent.Creator = 1
	ent.Updater = 1
	err := tx.Create(ent).Error
	require.NoError(t, err)

	card := &model.IotCard{ICCID: "REMARK_CARD_001", MSISDN: "13800010001", Status: 1, ShopID: &shopID}
	err = tx.Create(card).Error
	require.NoError(t, err)

	account := &model.Account{
		Username: "remark_authorizer",
		Phone:    "13800010002",
		Password: "hashed",
		UserType: constants.UserTypePlatform,
		Status:   constants.StatusEnabled,
	}
	account.Creator = 1
	account.Updater = 1
	err = tx.Create(account).Error
	require.NoError(t, err)

	auth := &model.EnterpriseCardAuthorization{
		EnterpriseID:   ent.ID,
		CardID:         card.ID,
		AuthorizedBy:   account.ID,
		AuthorizedAt:   time.Now(),
		AuthorizerType: constants.UserTypePlatform,
		Remark:         "原始备注",
	}
	err = authStore.Create(context.Background(), auth)
	require.NoError(t, err)

	ctx := pkggorm.SkipDataPermission(context.Background())
	ctx = context.WithValue(ctx, constants.ContextKeyUserID, account.ID)
	ctx = context.WithValue(ctx, constants.ContextKeyUserType, constants.UserTypePlatform)

	t.Run("更新授权备注", func(t *testing.T) {
		updated, err := authService.UpdateRecordRemark(ctx, auth.ID, "更新后的备注")
		require.NoError(t, err)
		assert.Equal(t, "更新后的备注", updated.Remark)
	})

	t.Run("更新不存在的记录", func(t *testing.T) {
		_, err := authService.UpdateRecordRemark(ctx, 99999, "不会更新")
		assert.Error(t, err)
	})
}
