package cn.qinys.platform.upms.api.service.impl;

import cn.qinys.platform.base.redis.RedisKeyEnum;
import cn.qinys.platform.base.security.utils.CurrentUtils;
import cn.qinys.platform.base.utils.RedisUtils;
import cn.qinys.platform.base.vo.LoginUserInfo;
import cn.qinys.platform.entity.upms.UpmsMenu;
import cn.qinys.platform.entity.upms.UpmsMenuBase;
import cn.qinys.platform.entity.upms.UpmsRole;
import cn.qinys.platform.entity.upms.UpmsUser;
import cn.qinys.platform.upms.api.dto.RolesDTO;
import cn.qinys.platform.upms.api.mapper.*;
import cn.qinys.platform.upms.api.req.CurrentUserSwitchRoleReq;
import cn.qinys.platform.upms.api.req.CurrentUserUpdateSelfReq;
import cn.qinys.platform.upms.api.resp.AdminTokenResp;
import cn.qinys.platform.upms.api.resp.CurrentUserInfoResp;
import cn.qinys.platform.upms.api.resp.LeftMenuResp;
import cn.qinys.platform.upms.api.service.ICurrentUserService;
import cn.qinys.platform.upms.api.service.IRoleService;
import cn.qinys.platform.upms.constants.UpmsConstants;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Description:
 *
 * @author tanlie
 * Date: 2024/2/27 21:24
 */
@Service
@AllArgsConstructor
public class CurrentUserServiceImpl implements ICurrentUserService {

    private final RedisUtils redisUtils;
    private final UpmsUserMapper userMapper;
    private final UpmsRoleMapper roleMapper;
    private final IRoleService roleService;
    private final UpmsRoleMenusMapper roleMenusMapper;
    private final UpmsMenuMapper menuMapper;
    private final UpmsMenuBaseMapper menuBaseMapper;


    @Override
    public CurrentUserInfoResp getCurrentUserInfo() {
        LoginUserInfo userInfo = CurrentUtils.getCurrentUserInfo();
        String key = UpmsConstants.RedisKey.UPMS_USER_INFO.getCode() + userInfo.getId();
        if (redisUtils.exists(key)) {
            return (CurrentUserInfoResp) redisUtils.get(key);
        }
        UpmsUser user = userMapper.selectById(userInfo.getId());
        CurrentUserInfoResp resp = new CurrentUserInfoResp();
        resp.setId(user.getId());
        resp.setUsername(user.getUsername());
        resp.setFullName(user.getFullName());
        resp.setSex(user.getSex());
        resp.setLoginRoleName(userInfo.getLoginRoleName());
        resp.setLoginRoleId(userInfo.getLoginRoleId());
        resp.setMobile(user.getMobile());
        resp.setAvatar(user.getAvatar());
        List<RolesDTO> roles = roleMapper.getRoleListDTO(user.getId());
        resp.setUserRoles(roles);
        resp.setEmail(user.getEmail());
        redisUtils.set(key, resp, UpmsConstants.RedisKey.UPMS_USER_INFO.getExpireTime());
        return resp;
    }

    @Override
    public AdminTokenResp switchRole(CurrentUserSwitchRoleReq req) {
        LoginUserInfo userInfo = CurrentUtils.getCurrentUserInfo();
        UpmsRole role = roleMapper.selectById(req.getRoleId());
        userInfo.setLoginRoleId(role.getId());
        userInfo.setLoginRoleName(role.getRoleCnName());
        userInfo.setPermissionCodes(roleService.getPermissionCodes(role.getId(),role.getSuperAdmin()));
        userInfo.setSuperAdmin(role.getSuperAdmin());
        CurrentUtils.setCurrentUserInfo(userInfo, CurrentUtils.getToken());
        this.refreshUserInfo(userInfo.getId());
        //修改默认角色
        roleService.updateUserActiveRole(userInfo.getId(), req.getRoleId());
        // 不换token
        AdminTokenResp resp = new AdminTokenResp();
        resp.setToken(CurrentUtils.getToken());
        resp.setTtl(RedisKeyEnum.CURRENT_USER.getExpireTime());
        resp.setPermissionCodes(roleService.getPermissionCodes(role.getId(),role.getSuperAdmin()));
        return resp;
    }

    @Override
    public void refreshUserInfo(String userId) {
        String key = UpmsConstants.RedisKey.UPMS_USER_INFO.getCode() + userId;
        redisUtils.delete(key);
    }

    @Override
    public void updateSelf(CurrentUserUpdateSelfReq req) {
        String userId = CurrentUtils.getCurrentUserId();
        UpdateWrapper<UpmsUser> wrapper = new UpdateWrapper<>();
        wrapper.eq("id", userId);
        UpmsUser entity = new UpmsUser();
        entity.setEmail(req.getEmail());
        entity.setFullName(req.getFullName());
        entity.setSex(req.getSex());
        if (StringUtils.hasLength(req.getAvatar())) {
            entity.setAvatar(req.getAvatar());
        }
        userMapper.update(entity, wrapper);
        //更新缓存
        this.refreshUserInfo(userId);
    }

    @Override
    public String checkPassword() {
        String userId = CurrentUtils.getCurrentUserId();
        UpmsUser user = userMapper.selectById(userId);
        if (user.getPwdChangeTime() == null) {
            return "1";
        }
        LocalDate start = user.getPwdChangeTime().toLocalDate();//开始时间
        LocalDate end = LocalDate.now();//当前时间
        long days = end.toEpochDay() - start.toEpochDay();//天数差
        return days > 90 ? "1" : "0";
    }

    @Override
    public List<LeftMenuResp> getAuthMenuTree() {
        String roleId = CurrentUtils.getCurrentUserInfo().getLoginRoleId();
        String key = UpmsConstants.RedisKey.UPMS_AUTH_MENUS.getCode() + roleId;
        if (redisUtils.exists(key)) {
            Object exist = redisUtils.get(key);
            return this.castList(exist, LeftMenuResp.class);
        }
        UpmsRole role = roleMapper.selectById(roleId);
        QueryWrapper<UpmsMenu> wrapper = new QueryWrapper<>();
        // 超级管理员不校验菜单
        if (!"1".equals(role.getSuperAdmin())) {
            List<Integer> authMenuIds = roleMenusMapper.selectMenuIdsByRole(roleId);
            if (authMenuIds == null || authMenuIds.isEmpty()) {
                wrapper.eq("path", "personal-center"); // 默认给个人中心权限
            } else {
                wrapper.in("id", authMenuIds);
            }
        }

        wrapper.orderByAsc("ord", "id");
        List<UpmsMenu> menuList = menuMapper.selectList(wrapper);
        List<LeftMenuResp> resp = this.getTree(menuList);
        redisUtils.set(key, resp, UpmsConstants.RedisKey.UPMS_AUTH_MENUS.getExpireTime());
        return resp;
    }

    @Override
    public List<LeftMenuResp> getDevAdminAuthMenus() {
        QueryWrapper<UpmsMenuBase> wrapper = new QueryWrapper<>();
        wrapper.in("id", Arrays.asList(1, 12))
                .or().in("parent_id", Arrays.asList(1, 12));
        wrapper.orderByAsc("ord", "id");
        List<UpmsMenuBase> menuBaseList = menuBaseMapper.selectList(wrapper);
        List<UpmsMenu> menuList = new ArrayList<>();
        for (UpmsMenuBase upmsMenuBase : menuBaseList) {
            UpmsMenu temp = new UpmsMenu();
            BeanUtils.copyProperties(upmsMenuBase, temp);
            menuList.add(temp);
        }
        return this.getTree(menuList);
    }


    /**
     * obj 转set对象
     *
     * @param obj
     * @param clazz
     * @param <T>
     * @return
     */
    protected <T> List<T> castList(Object obj, Class<T> clazz) {
        List<T> result = new ArrayList<>();
        if (obj instanceof List<?>) {
            for (Object o : (List<?>) obj) {
                result.add(clazz.cast(o));
            }
            return result;
        }
        return null;
    }

    private List<LeftMenuResp> getTree(List<UpmsMenu> menuList) {
        List<UpmsMenu> firstLevel = new ArrayList<>();
        menuList.forEach(menu -> {
            if (menu.getParentId() == 0) {
                firstLevel.add(menu);
            }
        });
        List<LeftMenuResp> resp = new ArrayList<>();
        for (UpmsMenu menu : firstLevel) {
            LeftMenuResp root = new LeftMenuResp();
            root.setId(menu.getId());
            root.setTitle(menu.getTitle());
            root.setHidden(menu.getHidden());
            root.setComponent(menu.getComponent());
            root.setIcon(menu.getIcon());
            root.setOrd(menu.getOrd());
            root.setKeepAlive(menu.getKeepAlive());
            root.setPath(menu.getPath());
            root.setChildren(this.getAuthMenuChildren(menu.getId(), menuList));
            resp.add(root);
        }
        return resp;
    }

    private List<LeftMenuResp> getAuthMenuChildren(Integer parentId, List<UpmsMenu> menuList) {
        List<LeftMenuResp> children = new ArrayList<>();
        for (UpmsMenu menu : menuList) {
            if (parentId.equals(menu.getParentId())) {
                LeftMenuResp child = new LeftMenuResp();
                child.setId(menu.getId());
                child.setTitle(menu.getTitle());
                child.setHidden(menu.getHidden());
                child.setComponent(menu.getComponent());
                child.setIcon(menu.getIcon());
                child.setOrd(menu.getOrd());
                child.setKeepAlive(menu.getKeepAlive());
                child.setPath(menu.getPath());
                child.setChildren(this.getAuthMenuChildren(child.getId(), menuList));
                children.add(child);
            }
        }
        return children;
    }


}
