// Package handlers add by blacknc <blacknc@163.com> at 2024/05/20 15:56:26
package handlers

import (
	"context"
	"dataservices/commons/config"
	"dataservices/commons/constants"
	"dataservices/commons/logger"
	service "dataservices/internal/service/common"
	ddbcacheworker "dataservices/worker/ddbcache"
	"fmt"
	"strings"

	"github.com/aws/aws-sdk-go-v2/feature/dynamodbstreams/attributevalue"
	"go.uber.org/zap"
)

func init() {
	ddbcacheworker.RegisterHandler(func() string { return config.Global().RBACConf.PrivilegeRoleTableName }, AccountPrivilegeRoleHandler)
	ddbcacheworker.RegisterHandler(func() string { return config.Global().RBACConf.ApiKeyTableName }, AccountUserApikeyHandler)
}

type UserApikey struct {
	AccessKey  string              `dynamodbav:"identity"`
	PrivateKey string              `dynamodbav:"private_key"`
	AppRoleMap map[uint64][]uint64 `dynamodbav:"role_map"`
}

type PrivilegeRole struct {
	ResourceUri string `dynamodbav:"resource_uri"`
	RoleID      uint64 `dynamodbav:"role_id"`
	PrivilegeID uint64 `dynamodbav:"privilege_id"`
}

func AccountUserApikeyHandler(ctx context.Context, event ddbcacheworker.Event, cacheManager service.CacheManager) error {

	record := event.Data
	var images [2]UserApikey
	if err := attributevalue.UnmarshalMap(record.Dynamodb.OldImage, &images[0]); err != nil {
		return fmt.Errorf("failed to unmarshal account user apikey event old record:%v", err)
	}
	if err := attributevalue.UnmarshalMap(record.Dynamodb.NewImage, &images[1]); err != nil {
		return fmt.Errorf("failed to unmarshal account user apikey event new record:%v", err)
	}

	for i := range images {
		publicKey := strings.ReplaceAll(images[i].AccessKey, "api_key_", "")
		for appID := range images[i].AppRoleMap {
			if err := cacheManager.ClearApikeyPermission(ctx, service.ApikeyModeRW, publicKey, appID); err != nil {
				logger.Error(ctx, "failed to clear apikey permission cache",
					zap.String("publicKey", publicKey),
					zap.Uint64("dataapp_id", appID),
					zap.String("permission", service.ApikeyModeRW),
					zap.Error(err))
			}
			if err := cacheManager.ClearApikeyPermission(ctx, service.ApikeyModeRO, publicKey, appID); err != nil {
				logger.Error(ctx, "failed to clear apikey permission cache",
					zap.String("publicKey", publicKey),
					zap.Uint64("dataapp_id", appID),
					zap.String("permission", service.ApikeyModeRO),
					zap.Error(err))
			}
		}
	}
	return nil
}

func AccountPrivilegeRoleHandler(ctx context.Context, event ddbcacheworker.Event, cacheManager service.CacheManager) error {

	record := event.Data
	var images [2]PrivilegeRole
	if err := attributevalue.UnmarshalMap(record.Dynamodb.OldImage, &images[0]); err != nil {
		return fmt.Errorf("failed to unmarshal account privilege role event old record:%v", err)
	}
	if err := attributevalue.UnmarshalMap(record.Dynamodb.NewImage, &images[1]); err != nil {
		return fmt.Errorf("failed to unmarshal account privilege role event new record:%v", err)
	}

	for i := range images {
		var err error
		resource := images[i].ResourceUri
		switch resource {
		case constants.ApikeyResourceRO:
			err = cacheManager.BatchClearApikeyPermission(ctx, service.ApikeyModeRO)
		case constants.ApikeyResourceRW:
			err = cacheManager.BatchClearApikeyPermission(ctx, service.ApikeyModeRW)
		}
		if err != nil {
			logger.Error(ctx, "failed to clear apikey resource permission cache",
				zap.String("resource", resource),
				zap.Error(err))
		}
	}
	return nil
}
