package com.hys.app.service.system.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hys.app.framework.auth.Token;
import com.hys.app.framework.context.request.ThreadContextHolder;
import com.hys.app.framework.context.user.AdminUserContext;
import com.hys.app.framework.database.WebPage;
import com.hys.app.framework.exception.ResourceNotFoundException;
import com.hys.app.framework.exception.ServiceException;
import com.hys.app.framework.redis.RedisChannel;
import com.hys.app.framework.security.TokenManager;
import com.hys.app.framework.security.message.UserDisableMsg;
import com.hys.app.framework.security.model.Admin;
import com.hys.app.framework.security.model.Role;
import com.hys.app.framework.util.*;
import com.hys.app.mapper.system.AdminUserMapper;
import com.hys.app.model.errorcode.SystemErrorCode;
import com.hys.app.model.support.LogClient;
import com.hys.app.model.support.validator.annotation.LogLevel;
import com.hys.app.model.system.dos.AdminUser;
import com.hys.app.model.system.dos.DeptDO;
import com.hys.app.model.system.dos.RoleDO;
import com.hys.app.model.system.dos.SystemLogs;
import com.hys.app.model.system.dto.AdminUserDTO;
import com.hys.app.model.system.vo.AdminLoginVO;
import com.hys.app.model.system.vo.AdminUserVO;
import com.hys.app.service.system.AdminUserManager;
import com.hys.app.service.system.DeptManager;
import com.hys.app.service.system.RoleManager;
import com.hys.app.service.system.SystemLogsManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 平台管理员业务类
 *
 * @author zh
 * @version v7.0
 * @since v7.0.0
 * 2018-06-20 20:38:26
 */
@Service
public class AdminUserManagerImpl implements AdminUserManager {

    @Autowired
    private RoleManager roleManager;
    @Autowired
    private AdminUserMapper adminUserMapper;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private TokenManager tokenManager;
    @Autowired
    private SystemLogsManager systemLogsManager;

    private List<Long> ids = new ArrayList<>();

    /**
     * 查询平台管理员列表
     *
     * @param page      页码
     * @param pageSize  每页数量
     * @param userState
     * @return WebPage
     */
    @Override
    public WebPage list(long page, long pageSize, String keyword, Integer userState) {

        IPage<AdminUserDTO> iPage = adminUserMapper.selectPageDto(new Page<>(page, pageSize), keyword, userState);
        return PageConvert.convert(iPage);
    }

    /**
     * 添加平台管理员
     *
     * @param adminUserVO 平台管理员
     * @return AdminUser 平台管理员
     */
    @Override
    @Transactional(value = "systemTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public AdminUser add(AdminUserVO adminUserVO) {
        //校验密码格式
        boolean bool = Pattern.matches("[a-fA-F0-9]{32}", adminUserVO.getPassword());
        if (!bool) {
            throw new ServiceException(SystemErrorCode.E917.code(), "密码格式不正确");
        }
        //校验用户名称是否重复
        AdminUser user = adminUserMapper.selectOne(new LambdaQueryWrapper<AdminUser>().eq(AdminUser::getUsername, adminUserVO.getUsername()).eq(AdminUser::getUserState, 0));

        if (user != null) {
            throw new ServiceException(SystemErrorCode.E915.code(), "管理员名称重复");
        }
        //不是超级管理员的情况下再校验权限是否存在
        if (!adminUserVO.getFounder().equals(1)) {
            RoleDO roleDO = roleManager.getModel(adminUserVO.getRoleId());
            if (roleDO == null) {
                throw new ResourceNotFoundException("所属权限不存在");
            }
        }
        //管理员信息入库
        String password = adminUserVO.getPassword();
        AdminUser adminUser = new AdminUser();
        BeanUtil.copyProperties(adminUserVO, adminUser);
        adminUser.setPassword(StringUtil.md5(password + adminUser.getUsername().toLowerCase()));
        adminUser.setDateLine(DateUtil.getDateline());
        adminUser.setUserState(0);
        adminUserMapper.insert(adminUser);
        return adminUser;
    }

    /**
     * 修改平台管理员
     *
     * @param adminUserVO 平台管理员
     * @param id          平台管理员主键
     * @return AdminUser 平台管理员
     */
    @Override
    @Transactional(value = "systemTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public AdminUser edit(AdminUserVO adminUserVO, Long id) {
        //对要修改的管理员是否存在进行校验
        AdminUser adminUser = this.getModel(id);
        if (adminUser == null) {
            throw new ResourceNotFoundException("当前管理员不存在");
        }
        //如果修改的是从超级管理员到普通管理员 需要校验此管理员是否是最后一个超级管理员
        if (adminUser.getFounder().equals(1) && !adminUserVO.getFounder().equals(1)) {

            QueryWrapper<AdminUser> wrapper = new QueryWrapper<>();
            wrapper.eq("founder", 1).eq("user_state", 0);
            List<AdminUser> adminUsers = adminUserMapper.selectList(wrapper);

            if (adminUsers.size() <= 1) {
                throw new ServiceException(SystemErrorCode.E916.code(), "必须保留一个超级管理员");
            }
        }
        if (!adminUserVO.getFounder().equals(1)) {
            RoleDO roleDO = roleManager.getModel(adminUserVO.getRoleId());
            if (roleDO == null) {
                throw new ResourceNotFoundException("所属权限不存在");
            }
        } else {
            adminUserVO.setRoleId(0L);
        }
        //管理员原密码
        String password = adminUser.getPassword();
        //对管理员是否修改密码进行校验
        if (!StringUtil.isEmpty(adminUserVO.getPassword())) {
            boolean bool = Pattern.matches("[a-fA-F0-9]{32}", adminUserVO.getPassword());
            if (!bool) {
                throw new ServiceException(SystemErrorCode.E917.code(), "密码格式不正确");
            }
            adminUserVO.setPassword(StringUtil.md5(adminUserVO.getPassword() + adminUser.getUsername().toLowerCase()));
        } else {
            adminUserVO.setPassword(password);
        }
        //修改管理员名称
        adminUserVO.setUsername(adminUser.getUsername());
        BeanUtil.copyProperties(adminUserVO, adminUser);
        adminUserMapper.updateById(adminUser);
        return adminUser;
    }


    /**
     * 删除平台管理员
     *
     * @param id 平台管理员主键
     */
    @Override
    @Transactional(value = "systemTransactionManager", propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void delete(Long id) {
        //校验当前管理员是否存在
        AdminUser adminUser = this.getModel(id);
        if (adminUser == null) {
            throw new ResourceNotFoundException("当前管理员不存在");
        }
        //校验要删除的管理员是否是最后一个超级管理员
        QueryWrapper<AdminUser> wrapper = new QueryWrapper<>();
        wrapper.eq("founder", 1).eq("user_state", 0);
        List<AdminUser> adminUsers = adminUserMapper.selectList(wrapper);

        if (adminUsers.size() <= 1 && adminUser.getFounder().equals(1)) {
            throw new ServiceException(SystemErrorCode.E916.code(), "必须保留一个超级管理员");
        }
        // 设置管理员状态为删除
        adminUser.setUserState(-1);
        adminUserMapper.updateById(adminUser);

        //发送redis订阅消息,通知各个节点此用户已经禁用
        UserDisableMsg userDisableMsg = new UserDisableMsg(id, Role.ADMIN, UserDisableMsg.ADD);
        String msgJson = JsonUtil.objectToJson(userDisableMsg);
        redisTemplate.convertAndSend(RedisChannel.USER_DISABLE, msgJson);

    }

    /**
     * 获取平台管理员
     *
     * @param id 平台管理员主键
     * @return AdminUser  平台管理员
     */
    @Override
    public AdminUser getModel(Long id) {
        return adminUserMapper.selectById(id);
    }

    @Override
    public AdminUser getModelNormalStatus(Long id) {

        QueryWrapper<AdminUser> wrapper = new QueryWrapper<>();
        wrapper.eq("user_state", 0).eq("id", id);
        return adminUserMapper.selectOne(wrapper);
    }

    /**
     * 管理员登录
     *
     * @param name     管理员名称
     * @param password 管理员密码
     * @return
     */
    @Override
    public AdminLoginVO login(String name, String password) {
        //查询管理员信息
        QueryWrapper<AdminUser> wrapper = new QueryWrapper<>();
        wrapper.eq("username", name).eq("password", StringUtil.md5(password + name.toLowerCase())).eq("user_state", 0);
        AdminUser adminUser = adminUserMapper.selectOne(wrapper);
        //管理员信息不存在
        if (adminUser == null || !StringUtil.equals(adminUser.getUsername(), name)) {
            throw new ServiceException(SystemErrorCode.E918.code(), "管理员账号密码错误");
        }
        //返回管理员信息
        AdminLoginVO adminLoginVO = new AdminLoginVO();
        adminLoginVO.setUid(adminUser.getId());
        adminLoginVO.setUsername(name);
        adminLoginVO.setDepartment(adminUser.getDepartment());
        adminLoginVO.setFace(adminUser.getFace());
        adminLoginVO.setRoleId(adminUser.getRoleId());
        adminLoginVO.setFounder(adminUser.getFounder());
        adminLoginVO.setDeptId(adminUser.getDeptId());
        // 设置访问token的失效时间维持管理员在线状态
        Token token = createToken(adminUser);

        String accessToken = token.getAccessToken();
        String refreshToken = token.getRefreshToken();

        adminLoginVO.setAccessToken(accessToken);
        adminLoginVO.setRefreshToken(refreshToken);

        //记录登录日志
        addLoginLog(adminUser, name, password);

        return adminLoginVO;
    }

    /**
     * 通过refreshToken重新获取accessToken
     *
     * @param refreshToken
     * @return
     */
    @Override
    public String exchangeToken(String refreshToken) {
        if (refreshToken != null) {
            Admin admin = tokenManager.parse(Admin.class, refreshToken);

            Long uid = admin.getUid();

            //获取uuid
            String uuid = ThreadContextHolder.getHttpRequest().getHeader("uuid");
            //根据id获取管理员 校验当前管理员是否存在
            AdminUser adminUser = this.getModelNormalStatus(uid);
            if (adminUser == null) {
                throw new ResourceNotFoundException("当前管理员不存在或已删除");
            }
            //重新获取token
            Token token = createToken(adminUser);

            String newAccessToken = token.getAccessToken();
            String newRefreshToken = token.getRefreshToken();

            Map map = new HashMap(16);
            map.put("accessToken", newAccessToken);
            map.put("refreshToken", newRefreshToken);

            return JsonUtil.objectToJson(map);

        }
        throw new ResourceNotFoundException("当前管理员不存在");
    }


    /**
     * 使用adminUser 创建token
     *
     * @param adminUser
     * @return
     */
    private Token createToken(AdminUser adminUser) {
        Admin admin = new Admin();
        admin.setUid(adminUser.getId());
        admin.setUsername(adminUser.getUsername());
//        admin.setPlatformShopId(platform.getShopId());
//        admin.setPlatformShopName(platform.getShopName());
        admin.setFounder(adminUser.getFounder());
        if (adminUser.getFounder().equals(1)) {
            admin.add("SUPER_ADMIN");
        } else {
            RoleDO roleDO = this.roleManager.getModel(adminUser.getRoleId());
            admin.add(roleDO.getRoleName());
        }

        return tokenManager.create(admin);

    }

    /**
     * 管理员注销登录
     *
     * @param uid 会员id
     */
    @Override
    public void logout(Long uid) {

    }

    @Override
    public Long countByDeptId(Long deptId) {
        return new LambdaQueryChainWrapper<>(adminUserMapper)
                .eq(AdminUser::getDeptId, deptId)
                .count();
    }

    @Override
    public AdminUser getCurrUser() {
        return getModel(AdminUserContext.getAdminUserId());
    }

    @Override
    public void recover(Long id) {
        //校验当前管理员是否存在
        AdminUser adminUser = this.getModel(id);
        if (adminUser == null) {
            throw new ResourceNotFoundException("当前管理员不存在");
        }

        adminUser.setUserState(0);
        adminUserMapper.updateById(adminUser);

        //发送redis订阅消息,通知各个节点此用户已经恢复
        UserDisableMsg userDisableMsg = new UserDisableMsg(id, Role.ADMIN, UserDisableMsg.DELETE);
        String msgJson = JsonUtil.objectToJson(userDisableMsg);
        redisTemplate.convertAndSend(RedisChannel.USER_DISABLE, msgJson);
    }

    @Override
    public long countByPostId(Long postId) {
        return new LambdaQueryChainWrapper<>(adminUserMapper).eq(AdminUser::getPostId, postId).count();
    }

    @Override
    public String getCurrUserName() {
        AdminUser currUser = getCurrUser();
        return currUser.getRealName();
    }

    @Override
    public Map<Long, String> getNameMapByIds(List<Long> ids) {
        if (CollUtil.isEmpty(ids)) {
            return Collections.emptyMap();
        }
        return new LambdaQueryChainWrapper<>(adminUserMapper)
                .in(AdminUser::getId, ids)
                .list()
                .stream().collect(Collectors.toMap(AdminUser::getId, AdminUser::getRealName));
    }

    @Override
    public List<AdminUser> getUserByDept() {
        AdminUser byId = adminUserMapper.selectById(AdminUserContext.getAdminUserId());
        if (byId.getFounder() == 1){
           return adminUserMapper.selectList(new LambdaQueryWrapper<>());
        }
        //获取所有的部门
        List<Long> deptIds = adminUserMapper.getAllSubDept(byId.getDeptId());
        //找出所有人子部门下的所有人
        List<AdminUser> adminUsers = adminUserMapper.selectList(new LambdaQueryWrapper<AdminUser>().in(AdminUser::getDeptId, deptIds));
        return adminUsers;
    }


    /**
     * 记录登录日志
     *
     * @param adminUser
     * @param name
     * @param password
     */
    private void addLoginLog(AdminUser adminUser, String name, String password) {
        SystemLogs systemLogs = new SystemLogs();
        systemLogs.setOperateDetail(ObjectUtil.isNotEmpty(adminUser.getRealName()) ? adminUser.getUsername() + "[" + adminUser.getRealName() + "]登录成功" : adminUser.getUsername() + "登录成功");
        systemLogs.setOperateIp(StringUtil.getIpAddress());
        systemLogs.setParams("name=" + name + "&password=" + password);
        systemLogs.setMethod("login");
        systemLogs.setOperateTime(DateUtil.getDateline());
        systemLogs.setOperatorId(adminUser.getId());
        systemLogs.setOperatorName(adminUser.getUsername());
        systemLogs.setSellerId(0L);
        systemLogs.setLevel(LogLevel.important.name());
        systemLogs.setClient(LogClient.admin.name());
        systemLogsManager.add(systemLogs);
    }
}
