package service

import (
	"cold-delivery/common/actions"
	cDto "cold-delivery/common/dto"
	"cold-delivery/common/global"
	"errors"
	"fmt"
	"github.com/casbin/casbin/v2"
	"gogs.baozhida.cn/zoie/OAuth-core/pkg"
	"gogs.baozhida.cn/zoie/OAuth-core/pkg/utils"
	"gogs.baozhida.cn/zoie/OAuth-core/service"
	"strings"

	"cold-delivery/app/admin/model"
	"cold-delivery/app/admin/service/dto"
	"gorm.io/gorm"
)

type SysRole struct {
	service.Service
}

// GetPage 获取SysRole列表
func (e *SysRole) GetPage(c *dto.SysRoleGetPageReq, list *[]model.SysRole, count *int64, p *actions.DataPermission) error {
	var err error
	var data model.SysRole

	err = e.Orm.Model(&data).
		Scopes(
			cDto.MakeCondition(c.GetNeedSearch()),
			cDto.Paginate(c.GetPageSize(), c.GetPageIndex()),
			actions.Permission(data.TableName(), p),
		).
		Find(list).Limit(-1).Offset(-1).
		Count(count).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		return global.GetFailedErr
	}
	return nil
}

// Get 获取SysRole对象
func (e *SysRole) Get(d *dto.SysRoleGetReq, roleModel *model.SysRole, p *actions.DataPermission) error {
	err := e.Orm.
		Scopes(actions.Permission(roleModel.TableName(), p)).
		First(roleModel, d.GetId()).Error

	if err != nil {
		e.Log.Errorf("db error: %s", err)
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return global.GetNotFoundOrNoPermissionErr
		}
		return global.GetFailedErr
	}
	roleModel.MenuIds, err = e.GetRoleMenuId(roleModel.Id)
	if err != nil {
		e.Log.Errorf("get menuIds error, %s", err)
		return global.GetFailedErr
	}

	return nil
}

// Insert 创建SysRole对象
func (e *SysRole) Insert(c *dto.SysRoleInsertReq) error {
	var err error
	var data model.SysRole

	tx := e.Orm.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	var roleKey string
	for {
		var count int64
		roleKey = utils.GetRandString(8, "", 0)
		var i int64
		err = tx.Model(&data).Where("role_key = ?", roleKey).Count(&count).Error
		if err != nil {
			continue
		}
		if i == 0 {
			break
		}
	}
	// 添加角色
	c.Generate(&data)
	data.RoleKey = roleKey
	err = tx.Create(&data).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		return global.CreateFailedErr
	}
	c.Id = data.Id

	// 添加角色菜单关联
	var menuList []model.SysMenu
	err = e.Orm.Where("id in (?)", c.MenuIds).Find(&menuList).Error
	if err != nil {
		return global.GetFailedErr
	}
	if len(menuList) == 0 {
		return errors.New("菜单不存在！")
	}

	var roleMenuList []model.SysRoleMenu
	// 添加角色关联的菜单
	for _, v := range menuList {
		roleMenuObj := model.SysRoleMenu{
			RoleKey: data.RoleKey,
			MenuId:  v.Id,
		}
		roleMenuObj.SetCreateBy(c.CreateBy)
		roleMenuList = append(roleMenuList, roleMenuObj)

	}
	err = tx.Save(&roleMenuList).Error
	if err != nil {
		e.Log.Errorf("save menuIds error, %s", err)
		return global.UpdateFailedErr
	}
	return nil

}

// Update 修改SysRole对象
func (e *SysRole) Update(c *dto.SysRoleUpdateReq, p *actions.DataPermission) error {
	var err error

	tx := e.Orm.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	var roleModel = model.SysRole{}
	// 查询角色是否存在
	err = e.Orm.Scopes(actions.Permission(roleModel.TableName(), p)).
		First(&roleModel, c.GetId()).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return global.UpdateNotFoundOrNoPermissionErr
		}
		return global.UpdateFailedErr
	}

	c.Generate(&roleModel)
	err = tx.Save(&roleModel).Error
	if err != nil {
		if errors.Is(err, model.ErrForbidUpdateSysRole) {
			return err
		}
		e.Log.Errorf("db error: %s", err)
		return global.UpdateFailedErr
	}

	// 删除角色关联的菜单
	err = tx.Where("role_key = ?", roleModel.RoleKey).Delete(&model.SysRoleMenu{}).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		return global.UpdateFailedErr
	}
	var menuList []model.SysMenu
	err = e.Orm.Where("id in (?)", c.MenuIds).Find(&menuList).Error
	if err != nil {
		return global.GetFailedErr
	}
	if len(menuList) == 0 {
		return errors.New("菜单不存在！")
	}

	var roleMenuList []model.SysRoleMenu
	// 添加角色关联的菜单
	for _, v := range menuList {
		roleMenuObj := model.SysRoleMenu{
			RoleKey: roleModel.RoleKey,
			MenuId:  v.Id,
		}
		roleMenuObj.SetCreateBy(c.UpdateBy)
		roleMenuList = append(roleMenuList, roleMenuObj)

	}
	err = tx.Save(&roleMenuList).Error
	if err != nil {
		e.Log.Errorf("save menuIds error, %s", err)
		return global.UpdateFailedErr
	}
	if err := model.DeleteRoleMenuCache(roleModel.RoleKey); err != nil {
		e.Log.Errorf("delete role menu cache error, %s", err)
		return global.UpdateFailedErr
	}
	model.DeleteRoleMenuCache(model.GetRoleMenuCacheKey(roleModel.RoleKey) + "-0")
	model.DeleteRoleMenuCache(model.GetRoleMenuCacheKey(roleModel.RoleKey) + "-1")
	//redisClient := storage.GetRedisClient()
	////获取相似的 Key
	//keys, err := redisClient.Keys("/" + model.GetRoleMenuCacheKey(roleModel.RoleKey) + "*").Result()
	//if err != nil {
	//	return global.UpdateFailedErr
	//}
	////删除相似的 Key
	//if len(keys) > 0 {
	//	_, err = redisClient.Del(keys...).Result()
	//	if err != nil {
	//		return global.UpdateFailedErr
	//	}
	//}

	c.Id = roleModel.Id

	return nil
}

// Remove 删除SysRole
func (e *SysRole) Remove(c *dto.SysRoleDeleteReq, p *actions.DataPermission, cb *casbin.SyncedEnforcer) error {
	var err error

	tx := e.Orm.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()

	var userList = make([]model.SysUser, 0)
	var roleModel model.SysRole
	err = e.Orm.Where("role_id = ?", c.Id).Find(&userList).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		return global.DeleteFailedErr
	}

	// 统计与用户关联的角色名
	if len(userList) > 0 {
		var roleNameStr string
		for i := 0; i < len(userList); i++ {
			roleNameStr += fmt.Sprintf(" %s,", userList[i].Username)
		}
		if !pkg.IsEmptyStr(roleNameStr) {
			// eg: role1,role2有用户关联，禁止删除！
			return errors.New(strings.TrimRight(roleNameStr, ",") + "有用户关联，禁止删除！")
		}
	}

	// 查询角色是否存在
	err = e.Orm.Scopes(actions.Permission(roleModel.TableName(), p)).
		First(&roleModel, c.GetId()).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return global.DeleteNotFoundOrNoPermissionErr
		}
		return global.DeleteFailedErr
	}
	db := tx.Delete(&roleModel)

	if err = db.Error; err != nil {
		if errors.Is(err, model.ErrForbidDeleteSysRole) {
			return err
		}
		e.Log.Errorf("db error: %s", err)
		return global.DeleteFailedErr
	}
	if db.RowsAffected == 0 {
		return global.DeleteNotFoundOrNoPermissionErr
	}

	// 删除之前的角色关联的菜单
	var roleMenu model.SysRoleMenu
	err = tx.Where("role_key = ?", roleModel.RoleKey).Delete(&roleMenu).Error
	if err != nil {
		return global.UpdateFailedErr
	}

	// 清除 sys_casbin_rule 权限表里 当前角色的所有记录
	_, _ = cb.RemoveFilteredPolicy(0, roleModel.RoleKey)

	return nil
}

// GetRoleMenuId 获取角色对应的菜单ids
func (e *SysRole) GetRoleMenuId(roleId int) ([]int, error) {
	var err error
	var roleModel model.SysRole
	var menuIds []int
	err = e.Orm.Where("id = ?", roleId).First(&roleModel).Error
	if err != nil {
		return []int{}, global.GetFailedErr
	}

	err = e.Orm.Model(&model.SysRoleMenu{}).Select("menu_id").Where("role_key = ? ", roleModel.RoleKey).Scan(&menuIds).Error
	if err != nil {
		return []int{}, global.GetFailedErr
	}
	return menuIds, nil
}

// GetWithName 获取SysRole对象
func (e *SysRole) GetWithName(d *dto.SysRoleByName, roleModel *model.SysRole) *SysRole {
	err := e.Orm.Where("name = ?", d.RoleName).First(roleModel).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		if errors.Is(err, gorm.ErrRecordNotFound) {
			err = global.GetNotFoundOrNoPermissionErr
		} else {
			err = global.GetFailedErr
		}
		_ = e.AddError(err)
		return e
	}

	//roleModel.MenuIds, err = e.GetRoleMenuId(roleModel.Id)
	if err != nil {
		e.Log.Errorf("get menuIds error, %s", err.Error())
		_ = e.AddError(global.GetFailedErr)
		return e
	}
	return e
}

// GetById 获取SysRole对象
func (e *SysRole) GetById(roleId int) ([]string, error) {
	permissions := make([]string, 0)
	roleModel := model.SysRole{}
	roleModel.Id = roleId
	err := e.Orm.Model(&roleModel).First(&roleModel).Error
	if err != nil {
		e.Log.Errorf("db error: %s", err)
		if errors.Is(err, gorm.ErrRecordNotFound) {
			err = global.GetNotFoundOrNoPermissionErr
		} else {
			err = global.GetFailedErr
		}
		return nil, err
	}
	//l := *roleModel.SysMenu
	//for i := 0; i < len(l); i++ {
	//	permissions = append(permissions, l[i].Title)
	//}
	return permissions, nil
}

// UpdateRoleMenu 修改角色绑定的菜单
func (e *SysRole) UpdateRoleMenu(d *dto.SysRoleUpdateRoleMenuReq) error {
	var err error
	tx := e.Orm.Begin()
	defer func() {
		if err != nil {
			tx.Rollback()
		} else {
			tx.Commit()
		}
	}()
	var roleModel model.SysRole
	err = e.Orm.Where("id = ?", d.GetId()).First(&roleModel).Error
	if err != nil {
		return global.GetFailedErr
	}

	var menuList []model.SysMenu
	err = e.Orm.Where("id in (?)", d.MenuIds).Find(&menuList).Error
	if err != nil {
		return global.GetFailedErr
	}
	if len(menuList) == 0 {
		return errors.New("菜单不存在！")
	}

	// 删除之前的角色关联的菜单
	var roleMenu model.SysRoleMenu
	err = tx.Where("role_key = ?", roleModel.RoleKey).Delete(&roleMenu).Error
	if err != nil {
		return global.UpdateFailedErr
	}
	var roleMenuList []model.SysRoleMenu
	// 添加角色关联的菜单
	for _, v := range menuList {
		roleMenuObj := model.SysRoleMenu{
			RoleKey: roleModel.RoleKey,
			MenuId:  v.Id,
		}
		roleMenuObj.SetCreateBy(d.CreateBy)
		roleMenuList = append(roleMenuList, roleMenuObj)

	}
	err = tx.Save(&roleMenuList).Error
	if err != nil {
		e.Log.Errorf("save menuIds error, %s", err)
		return global.UpdateFailedErr
	}
	return nil
}
