package rbac

import (
	"context"
	"sync"

	"github.com/tidbcloud/account/commons/config"
	"github.com/tidbcloud/account/commons/database"
	"github.com/tidbcloud/account/commons/ddb"

	"github.com/tidbcloud/account/internel/dao"
	ddbDao "github.com/tidbcloud/account/internel/dao/ddb"
	"github.com/tidbcloud/account/internel/dao/entity"
	"gorm.io/gorm"
)

type RbacRolePrivilegeIface interface {
	CreateRbacRolePrivilege(ctx context.Context, roleID uint64, privilegeIDs []uint64) error
	DeleteRbacRolePrivilege(ctx context.Context, roleID uint64, privilegeID uint64) error
	ListRbacRolePrivilege(ctx context.Context, roleID uint64) ([]entity.RbacRolePrivilege, error)
	AddRbacRolePrivilege(ctx context.Context, roleID uint64, privilegeIDs []uint64) error
	DeleteRbacRolePrivilegeByPrivilegeID(ctx context.Context, privilegeID uint64) error
	DeleteRbacRolePrivilegeByRoleID(ctx context.Context, roleId uint64) error
}

var (
	rbacRolePrivilegeInitOnce sync.Once
	rbacRolePrivilegeSrv      RbacRolePrivilegeIface
	rbacRolePrivilegeInitErr  error
)

func GetRbacRolePrivilegeSvc() (RbacRolePrivilegeIface, error) {
	rbacRolePrivilegeInitOnce.Do(func() {
		dynanoDB, err := ddb.NewDynamoDB(config.Global())
		if err != nil {
			rbacRolePrivilegeInitErr = err
			return
		}
		rbacRolePrivilegeSrv = NewRbacRolePrivilegesSvc(database.DBConn.DB, dynanoDB, dao.GetDaoHub())

	})
	return rbacRolePrivilegeSrv, rbacRolePrivilegeInitErr
}

type RbacRolePrivilegeSvc struct {
	db       *gorm.DB
	dynamodb *ddbDao.DynamoDBClient
	hub      *dao.DaoHub
}

func NewRbacRolePrivilegesSvc(db *gorm.DB, dynamodb *ddbDao.DynamoDBClient, hub *dao.DaoHub) RbacRolePrivilegeIface {
	return &RbacRolePrivilegeSvc{
		db:       db,
		dynamodb: dynamodb,
		hub:      hub,
	}
}

func (r *RbacRolePrivilegeSvc) CreateRbacRolePrivilege(ctx context.Context, roleID uint64, privilegeIDs []uint64) error {
	err := r.hub.Rbac.DeleteRbacRolePrivilegeByRoleID(ctx, r.db, r.dynamodb, roleID)
	if err != nil {
		return err
	}
	return r.hub.Rbac.CreateRbacRolePrivilege(ctx, r.db, r.dynamodb, roleID, privilegeIDs)
}

func (r *RbacRolePrivilegeSvc) AddRbacRolePrivilege(ctx context.Context, roleID uint64, privilegeIDs []uint64) error {
	return r.hub.Rbac.CreateRbacRolePrivilege(ctx, r.db, r.dynamodb, roleID, privilegeIDs)
}

func (r *RbacRolePrivilegeSvc) DeleteRbacRolePrivilege(ctx context.Context, roleID uint64, privilegeID uint64) error {

	return r.hub.Rbac.DeleteRbacRolePrivilege(ctx, r.db, r.dynamodb, roleID, privilegeID)
}

func (r *RbacRolePrivilegeSvc) ListRbacRolePrivilege(ctx context.Context, roleID uint64) ([]entity.RbacRolePrivilege, error) {
	var ret []entity.RbacRolePrivilege

	privilegeIDs, err := r.hub.Rbac.ListRbacPrivilegesIDsByRoleID(ctx, r.db, []uint64{roleID})
	if err != nil {
		return ret, err
	}
	for _, privilegeID := range privilegeIDs {
		rp := entity.RbacRolePrivilege{
			RbacRoleID:      entity.ID(roleID),
			RbacPrivilegeID: privilegeID,
		}
		ret = append(ret, rp)
	}
	return ret, nil
}

func (r *RbacRolePrivilegeSvc) DeleteRbacRolePrivilegeByPrivilegeID(ctx context.Context, privilegeID uint64) error {
	return r.hub.Rbac.DeleteRbacRolePrivilegeByPrivilegeID(ctx, r.db, r.dynamodb, privilegeID)
}

func (r *RbacRolePrivilegeSvc) DeleteRbacRolePrivilegeByRoleID(ctx context.Context, roleId uint64) error {
	return r.hub.Rbac.DeleteRbacRolePrivilegeByRoleID(ctx, r.db, r.dynamodb, roleId)
}
