package sysRule

import (
	"context"

	"kami/internal/dao"
	"kami/internal/model"
	"kami/internal/model/do"
	"kami/internal/model/entity"
	"kami/internal/service"
	"kami/utility/config"
	"kami/utility/utils"

	"github.com/gogf/gf/v2/database/gdb"
	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/util/gconv"
)

func init() {
	service.RegisterSysRole(New())
}

func New() *sSysRole {
	return &sSysRole{}
}

type sSysRole struct{}

func (s *sSysRole) GetRoleListSearch(ctx context.Context, req *model.RoleListInput) (res *model.RoleListOutput, err error) {
	res = new(model.RoleListOutput)
	m := dao.V1SysRole.Ctx(ctx).DB(config.GetDatabaseV1())
	if req.RoleName != "" {
		m = m.Where(dao.V1SysRole.Columns().Name, utils.OrmLike(req.RoleName))
	}
	if req.Status != "" {
		m = m.Where(dao.V1SysRole.Columns().Status, gconv.Int(req.Status))
	}
	err = m.Page(req.Current, req.PageSize).OrderAsc(dao.V1SysRole.Columns().Id).ScanAndCount(&res.List, &res.Total, true)
	return
}

// GetRoleList 获取角色列表
func (s *sSysRole) GetRoleList(ctx context.Context) (list []*entity.V1SysRole, err error) {
	//cache := commonService.Cache()
	////从缓存获取
	//iList := cache.GetOrSetFuncLock(ctx, consts.CacheSysRole, s.getRoleListFromDb, 0, consts.CacheSysAuthTag)
	//if iList != nil {
	//	err = gconv.Struct(iList, &list)
	//}
	iList, err := s.getRoleListFromDb(ctx)
	if err != nil {
		return
	}
	err = gconv.Struct(iList, &list)
	return
}

// 从数据库获取所有角色
func (s *sSysRole) getRoleListFromDb(ctx context.Context) (value interface{}, err error) {
	var v []*entity.V1SysRole
	// 从数据库获取
	err = dao.V1SysRole.Ctx(ctx).DB(config.GetDatabaseV1()).
		OrderAsc(dao.V1SysRole.Columns().ListOrder).
		OrderAsc(dao.V1SysRole.Columns().Id).
		Scan(&v)
	value = v
	return
}

// AddRoleRule 添加角色权限
func (s *sSysRole) AddRoleRule(ctx context.Context, ruleIds []uint, roleId int64) (err error) {
	casbinService := service.Casbin()
	enforcer, err := casbinService.CasbinEnforcer(ctx)
	if err != nil {
		return
	}
	ruleIdsStr := gconv.Strings(ruleIds)
	for _, v := range ruleIdsStr {
		_, err = enforcer.AddPolicy(gconv.String(roleId), v, "All")
		if err != nil {
			return
		}
	}
	return
}

// DelRoleRule 删除角色权限
func (s *sSysRole) DelRoleRule(ctx context.Context, roleId int64) (err error) {
	casbinService := service.Casbin()
	enforcer, err := casbinService.CasbinEnforcer(ctx)
	if err != nil {
		return
	}
	_, err = enforcer.RemoveFilteredPolicy(0, gconv.String(roleId))
	return
}

func (s *sSysRole) AddRole(ctx context.Context, req *model.RoleAddInput) (err error) {
	err = config.GetDatabaseV1().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		err = g.Try(ctx, func(ctx context.Context) {
			roleId, err2 := dao.V1SysRole.Ctx(ctx).DB(config.GetDatabaseV1()).
				TX(tx).InsertAndGetId(req)
			if err2 != nil {
				return
			}
			// 添加角色权限
			err2 = s.AddRoleRule(ctx, req.MenuIds, roleId)
			if err2 != nil {
				return
			}
		})
		return err
	})
	return
}

func (s *sSysRole) Get(ctx context.Context, id uint) (res *entity.V1SysRole, err error) {
	err = dao.V1SysRole.Ctx(ctx).DB(config.GetDatabaseV1()).WherePri(id).Scan(&res)
	return
}

// GetFilteredNamedPolicy 获取角色关联的菜单规则
func (s *sSysRole) GetFilteredNamedPolicy(ctx context.Context, id uint) (gpSlice []int, err error) {
	casbinService := service.Casbin()
	enforcer, err := casbinService.CasbinEnforcer(ctx)
	if err != nil {
		return
	}
	gp, err := enforcer.GetFilteredNamedPolicy("p", 0, gconv.String(id))
	if err != nil {
		return
	}
	gpSlice = make([]int, len(gp))
	for k, v := range gp {
		gpSlice[k] = gconv.Int(v[1])
	}
	return
}

// EditRole 修改角色
func (s *sSysRole) EditRole(ctx context.Context, req *model.RoleEditInput) (err error) {
	_, err = dao.V1SysRole.Ctx(ctx).WherePri(req.Id).Data(&do.V1SysRole{
		Status:    req.Status,
		ListOrder: req.ListOrder,
		Name:      req.Name,
		Remark:    req.Remark,
	}).Update()
	if err != nil {
		return
	}
	// 删除角色权限
	err = s.DelRoleRule(ctx, req.Id)
	if err != nil {
		return
	}
	// 添加角色权限
	err = s.AddRoleRule(ctx, req.MenuIds, req.Id)
	// 清除缓存
	return
}

// DeleteByIds 删除角色
func (s *sSysRole) DeleteByIds(ctx context.Context, ids []int64) (err error) {
	err = config.GetDatabaseV1().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
		_, err = dao.V1SysRole.Ctx(ctx).TX(tx).WhereIn(dao.V1SysRole.Columns().Id, ids).Delete()
		if err != nil {
			return err
		}
		// 删除角色权限
		for _, v := range ids {
			err = s.DelRoleRule(ctx, v)
			if err != nil {
				return err
			}
		}
		// 清除缓存
		return nil
	})
	return
}
