package service

import (
	"github.com/linmadan/egglib-go/core/application"
	"github.com/linmadan/egglib-go/transaction/pg"
	"github.com/tiptok/godevp/pkg/application/factory"
	"github.com/tiptok/godevp/pkg/application/rbac/command"
	"github.com/tiptok/godevp/pkg/application/rbac/query"
	"github.com/tiptok/godevp/pkg/domain"
	role2 "github.com/tiptok/godevp/pkg/domain/role"
	"github.com/tiptok/godevp/pkg/infrastructure/dao"
)

// 权限服务
type RbacService struct {
}

// 获取菜单列表
func (rbacService *RbacService) Access(accessQuery *query.AccessQuery) (interface{}, error) {
	if err := accessQuery.ValidateQuery(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	var AccessRepository, _ = factory.CreateAccessRepository(map[string]interface{}{"transactionContext": transactionContext})
	var access []*domain.Access
	if _, access, err = AccessRepository.Find(map[string]interface{}{"sortByParentId": "ASC", "sortBySort": "ASC"}); err != nil {
		return nil, err
	}
	var rspList []interface{}
	for _, item := range access {
		rspList = append(rspList, map[string]interface{}{
			"id":       item.Id,
			"name":     item.AccessName,
			"icon":     "",
			"parentId": item.ParentId,
			"sort":     item.Sort,
			"code":     item.AccessCode,
		})
	}
	rsp := map[string]interface{}{
		"lists": rspList,
	}

	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return rsp, nil
}

// 角色权限
func (rbacService *RbacService) RoleAccess(roleAccessQuery *query.RoleAccessQuery) (interface{}, error) {
	if err := roleAccessQuery.ValidateQuery(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	RoleAccessDao, _ := dao.NewRoleAccessDao(transactionContext.(*pg.TransactionContext))
	RoleRepository, _ := factory.CreateRoleRepository(map[string]interface{}{"transactionContext": transactionContext})
	var role *role2.Role

	if role, err = RoleRepository.FindOne(map[string]interface{}{"id": roleAccessQuery.RoleId}); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, "角色不存在")
	}
	accessIds, _ := RoleAccessDao.GetRoleAccess(roleAccessQuery.RoleId)
	rsp := map[string]interface{}{
		"roleId":    role.Id,
		"roleName":  role.RoleName,
		"accessIds": accessIds,
	}

	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return rsp, nil
}

// 设置角色权限
func (rbacService *RbacService) SetRoleAccess(setRoleAccessCommand *command.SetRoleAccessCommand) (interface{}, error) {
	if err := setRoleAccessCommand.ValidateCommand(); err != nil {
		return nil, application.ThrowError(application.ARG_ERROR, err.Error())
	}
	transactionContext, err := factory.CreateTransactionContext(nil)
	if err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	if err := transactionContext.StartTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	AccessRepository, _ := factory.CreateAccessRepository(map[string]interface{}{"transactionContext": transactionContext})
	RoleRepository, _ := factory.CreateRoleRepository(map[string]interface{}{"transactionContext": transactionContext})
	RoleAccessDao, _ := dao.NewRoleAccessDao(transactionContext.(*pg.TransactionContext))

	if _, err = RoleRepository.FindOne(map[string]interface{}{"id": setRoleAccessCommand.RoleId}); err != nil {
		return nil, application.ThrowError(application.RES_NO_FIND_ERROR, "角色不存在")
	}

	var accessMap = make(map[int64]*domain.Access)
	_, access, _ := AccessRepository.Find(map[string]interface{}{"inAccessIds": setRoleAccessCommand.AccessIds})
	for _, v := range access {
		accessMap[v.Id] = v
	}

	if err = RoleAccessDao.DeleteRoleAccess(setRoleAccessCommand.RoleId); err != nil {
		return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error())
	}
	if len(setRoleAccessCommand.AccessIds) > 0 {
		var roleAccess []*domain.RoleAccess
		for _, v := range setRoleAccessCommand.AccessIds {
			item := &domain.RoleAccess{
				RoleId:   setRoleAccessCommand.RoleId,
				AccessId: v,
			}
			if accessItem, ok := accessMap[v]; ok {
				item.Object = accessItem.Object
				item.Action = accessItem.Action
				item.Option = accessItem.AccessCode
			}
			roleAccess = append(roleAccess, item)
		}
		if err = RoleAccessDao.SaveRoleAccess(roleAccess); err != nil {
			return nil, application.ThrowError(application.BUSINESS_ERROR, err.Error())
		}
	}

	if err := transactionContext.CommitTransaction(); err != nil {
		return nil, application.ThrowError(application.TRANSACTION_ERROR, err.Error())
	}
	return nil, nil
}

func NewRbacService(options map[string]interface{}) *RbacService {
	newRbacService := &RbacService{}
	return newRbacService
}