package service

import (
	"github.com/tiptok/gocomm/pkg/log"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/application/factory"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/application/rbac/command"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/application/rbac/query"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/domain"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/infrastructure/dao"
	"gitlab.fjmaimaimai.com/mmm-go/godevp/pkg/protocol"
)

type RbacService struct {
}

func (svr *RbacService) Access(header *protocol.RequestHeader, request *query.AccessRequest) (rsp interface{}, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
	)
	rsp = &query.AccessResponse{}
	if err = request.ValidateCommand(); err != nil {
		err = protocol.NewCustomMessage(2, err.Error())
		return
	}
	if err = transactionContext.StartTransaction(); err != nil {
		log.Error(err)
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	var AccessRepository, _ = factory.CreateAccessRepository(transactionContext)
	var access []*domain.Access
	if _, access, err = AccessRepository.Find(map[string]interface{}{"sortByParentId": "ASC", "sortBySort": "ASC"}); err != nil {
		return
	}
	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,
	}

	err = transactionContext.CommitTransaction()
	return
}

func (svr *RbacService) RoleAccess(header *protocol.RequestHeader, request *query.RoleAccessRequest) (rsp interface{}, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
		RoleAccessDao, _      = dao.NewRoleAccessDao(transactionContext)
		RoleRepository, _     = factory.CreateRoleRepository(transactionContext)
		role                  *domain.Role
	)
	rsp = &query.RoleAccessResponse{}
	if err = request.ValidateCommand(); err != nil {
		err = protocol.NewCustomMessage(2, err.Error())
		return
	}
	if err = transactionContext.StartTransaction(); err != nil {
		log.Error(err)
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	if role, err = RoleRepository.FindOne(map[string]interface{}{"id": request.RoleId}); err != nil {
		log.Error(err)
		err = protocol.NewCustomMessage(1, "角色不存在")
		return
	}
	accessIds, _ := RoleAccessDao.GetRoleAccess(request.RoleId)
	rsp = map[string]interface{}{
		"roleId":    role.Id,
		"roleName":  role.RoleName,
		"accessIds": accessIds,
	}

	err = transactionContext.CommitTransaction()
	return
}

func (svr *RbacService) SetRoleAccess(header *protocol.RequestHeader, request *command.SetRoleAccessRequest) (rsp *command.SetRoleAccessResponse, err error) {
	var (
		transactionContext, _ = factory.CreateTransactionContext(nil)
		AccessRepository, _   = factory.CreateAccessRepository(transactionContext)
		RoleRepository, _     = factory.CreateRoleRepository(transactionContext)
		RoleAccessDao, _      = dao.NewRoleAccessDao(transactionContext)
	)
	rsp = &command.SetRoleAccessResponse{}
	if err = request.ValidateCommand(); err != nil {
		err = protocol.NewCustomMessage(2, err.Error())
	}
	if err = transactionContext.StartTransaction(); err != nil {
		log.Error(err)
		return nil, err
	}
	defer func() {
		transactionContext.RollbackTransaction()
	}()

	if _, err = RoleRepository.FindOne(map[string]interface{}{"id": request.RoleId}); err != nil {
		log.Error(err)
		err = protocol.NewCustomMessage(1, "角色不存在")
		return
	}

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

	if err = RoleAccessDao.DeleteRoleAccess(request.RoleId); err != nil {
		return
	}
	if len(request.AccessIds) > 0 {
		var roleAccess []*domain.RoleAccess
		for _, v := range request.AccessIds {
			item := &domain.RoleAccess{
				RoleId:   request.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
		}
	}
	err = transactionContext.CommitTransaction()
	return
}

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