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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
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.controller.erp.use.msg.MsgContant;
import com.hys.app.controller.erp.use.msg.MsgUtilClient;
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.security.TokenManager;
import com.hys.app.framework.security.model.Admin;
import com.hys.app.framework.util.*;
import com.hys.app.mapper.system.AdminUserMapper;
import com.hys.app.mapper.system.DeptMapper;
import com.hys.app.model.erp.entity.CompanyErp;
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.erp.CompanyBandMsgManager;
import com.hys.app.service.erp.CompanyErpManager;
import com.hys.app.service.system.AdminUserManager;
import com.hys.app.service.system.RoleManager;
import com.hys.app.service.system.SystemLogsManager;
import lombok.AllArgsConstructor;
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.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
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
@AllArgsConstructor
public class AdminUserManagerImpl implements AdminUserManager {

    private RoleManager roleManager;
    private AdminUserMapper adminUserMapper;
    private TokenManager tokenManager;
    private SystemLogsManager systemLogsManager;
    private CompanyErpManager companyManager;
    private DeptMapper deptMapper;
    private MsgUtilClient msgUtilClient;
    private CompanyBandMsgManager companyBandMsgManager;

    /**
     * 查询平台管理员列表
     *
     * @param page      页码
     * @param pageSize  每页数量
     * @param userState
     * @return WebPage
     */
    @Override
    public WebPage list(long page, long pageSize, String keyword, Integer userState) {
        Long companyId = AdminUserContext.getCompanyId();
        IPage<AdminUserDTO> iPage = adminUserMapper.selectPageDto(new Page<>(page, pageSize), keyword, userState, AdminUserContext.getCompanyId());

        return PageConvert.convert(iPage);
    }

    /**
     * 添加平台管理员
     *
     * @param adminUserVO 平台管理员
     * @return AdminUser 平台管理员
     */
    @Override
    @Transactional(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(), "密码格式不正确");
//        }
        String psd = adminUserVO.getPassword();
//        DeptDO deptDO = deptMapper.selectById(adminUserVO.getDeptId());
//        if (ObjectUtil.isNull(deptDO)) {
//            throw new ServiceException("部门不存在");
//        }
//        adminUserVO.setRoleId(deptDO.getRoleId());

        //校验用户名称是否重复
        QueryWrapper<AdminUser> wrapper = new QueryWrapper<>();
        wrapper.eq("username", adminUserVO.getUsername()).eq("user_state", 0);
        AdminUser user = adminUserMapper.selectOne(wrapper);

        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("所属权限不存在");
//            }
//        }
        CompanyErp company = companyManager.getById(AdminUserContext.getCompanyId());
        Long count = adminUserMapper.selectCount(new LambdaQueryWrapper<AdminUser>().eq(AdminUser::getCompanyId, company.getId()));
        if (count + 1 > company.getUserNum()) {
            throw new ServiceException("超过最大账号创建数量，如有需要请联系平台管理员更换套餐");
        }
        //管理员信息入库
        String password = adminUserVO.getPassword();
        AdminUser adminUser = new AdminUser();
        adminUser.setCompanyId(company.getId());
        BeanUtil.copyProperties(adminUserVO, adminUser);
        adminUser.setPassword(StringUtil.md5(adminUserVO.getUsername() + password + company.getId()).toLowerCase());
        adminUser.setDateLine(DateUtil.getDateline());
        adminUser.setUserState(0);
        adminUser.setFirstPassword(psd);
        adminUser.setFounder(0);
        adminUserMapper.insert(adminUser);
        //发消息
        List<String> companyBandMsg = companyBandMsgManager.getCompanyBandMsgCode(adminUser.getCompanyId());
        msgUtilClient.sendSys(MsgContant.CREATE_USER_SYSTEM, adminUser, adminUser.getUsername(), psd);
        if (companyBandMsg.contains(MsgContant.CREATE_USER_MAIL)) {
            msgUtilClient.sendMail(MsgContant.CREATE_USER_MAIL, adminUser, adminUser.getUsername(), psd);
        }
        if (companyBandMsg.contains(MsgContant.CREATE_USER_SMS)) {
            msgUtilClient.sendSms(MsgContant.CREATE_USER_SMS, adminUser, adminUser.getUsername(), psd);
        }
        if (companyBandMsg.contains(MsgContant.CREATE_USER_OFFICIAL)) {
            msgUtilClient.sendOfficial(MsgContant.CREATE_USER_OFFICIAL, adminUser, adminUser.getUsername(), psd);
        }
        return adminUser;
    }

    /**
     * 修改平台管理员
     *
     * @param adminUserVO 平台管理员
     * @param id          平台管理员主键
     * @return AdminUser 平台管理员
     */
    @Override
    @Transactional(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 ("admin".equals(adminUser.getUsername()) && !"admin".equals(adminUserVO.getUsername())) {
//            throw new ServiceException("admin 登录名称不允许修改");
//        }
        //管理员原密码
        String password = adminUser.getPassword();
        String newPassword;
        //对管理员是否修改密码进行校验
        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(adminUser.getUsername() + adminUserVO.getPassword() + adminUser.getCompanyId()));
            adminUserVO.setFirstPassword(adminUserVO.getPassword());
            newPassword = adminUserVO.getPassword();
        } else {
            newPassword = adminUser.getFirstPassword();
            adminUserVO.setPassword(password);
        }
        //修改管理员名称
        adminUserVO.setUsername(adminUser.getUsername());
        //发消息
        List<String> companyBandMsg = new ArrayList<>();
        if (ObjectUtil.isNotNull(adminUser.getCompanyId())) {
            companyBandMsg = companyBandMsgManager.getCompanyBandMsgCode(adminUser.getCompanyId());
        }
        msgUtilClient.sendSys(MsgContant.UPDATE_USER_SYSTEM, adminUser, adminUser.getUsername(), adminUser.getPassword());
        if (companyBandMsg.contains(MsgContant.UPDATE_USER_MAIL) || AdminUserContext.hasFound()) {
            msgUtilClient.sendMail(MsgContant.UPDATE_USER_MAIL, adminUser, LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE), adminUser.getUsername(), newPassword);
        }
        if (companyBandMsg.contains(MsgContant.UPDATE_USER_SMS) || AdminUserContext.hasFound()) {
            msgUtilClient.sendSms(MsgContant.UPDATE_USER_SMS, adminUser, LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE), adminUser.getUsername(), newPassword);
        }
        if (companyBandMsg.contains(MsgContant.UPDATE_USER_OFFICIAL) || AdminUserContext.hasFound()) {
            msgUtilClient.sendOfficial(MsgContant.UPDATE_USER_OFFICIAL, adminUser, LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE), adminUser.getUsername(), newPassword);
        }
        BeanUtil.copyProperties(adminUserVO, adminUser);
        adminUserMapper.updateById(adminUser);
        return adminUser;
    }


    /**
     * 删除平台管理员
     *
     * @param id 平台管理员主键
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void delete(Long id) {
        //校验当前管理员是否存在
        AdminUser adminUser = this.getModel(id);
        if (adminUser == null) {
            throw new ResourceNotFoundException("当前管理员不存在");
        }
        if ("admin".equals(adminUser.getUsername())) {
            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);
    }



    @Override
    public AdminLoginVO loginByPhone(String phone, String companyName, String type) {
        CompanyErp company = null;
        if ("com".equals(type) && StrUtil.isNotBlank(companyName)) {
            if (StrUtil.isBlank(companyName)) {
                throw new ServiceException("非平台工作人员公司必填");
            }
            company = companyManager.getOne(new LambdaQueryWrapper<CompanyErp>().eq(CompanyErp::getName,companyName));
            if (ObjectUtil.isNull(company)) {
                throw new ServiceException("该公司未注册");
            }
            //0
            if (company.getStatus() != 1) {
                throw new ServiceException("公司状态异常，限制登录，联系管理员申请解除限制");
            }
            if (new Date().compareTo(company.getEndUseTime()) > 0) {
                throw new ServiceException("该公司使用已到期，请续费");
            }
        }

        //查询管理员信息
        LambdaQueryWrapper<AdminUser> queryWrapper = new LambdaQueryWrapper<AdminUser>()
                .eq(AdminUser::getPhone, phone)
                .eq(AdminUser::getUserState, 0);
        if ("com".equals(type)) {
            queryWrapper.eq(AdminUser::getCompanyId, company.getId());
        }else if ("sys".equals(type)){
            queryWrapper.isNull(AdminUser::getCompanyId);
            queryWrapper.eq(AdminUser::getFounder,1);
        }

        AdminUser adminUser = adminUserMapper.selectOne(queryWrapper);
        //管理员信息不存在
        if (adminUser == null ) {
            throw new ServiceException(SystemErrorCode.E918.code(), "账号不存在");
        }
        if (adminUser.getFounder() != 1) {
            if (!adminUser.getCompanyId().equals(company.getId())) {
                throw new ServiceException("此账号不属于该公司");
            }
        }
//        if ("admin".equals(name) && password.equals(adminUser.getFirstPassword())){
//            throw new ServiceException("第一次登录需修改密码");
//        }
        //返回管理员信息
        AdminLoginVO adminLoginVO = new AdminLoginVO();
        adminLoginVO.setUid(adminUser.getId());

        adminLoginVO.setUsername(adminUser.getUsername());
        adminLoginVO.setCompanyVo(company);
        adminLoginVO.setDepartment(adminUser.getDepartment());
        adminLoginVO.setFace(adminUser.getFace());
        adminLoginVO.setRoleId(adminUser.getRoleId());
        adminLoginVO.setFounder(adminUser.getFounder());
        adminLoginVO.setDeptId(adminUser.getDeptId());
        adminLoginVO.setHasDeptManager(adminUser.getHasDeptManager());
        // 设置访问token的失效时间维持管理员在线状态
        if (adminUser.getFounder() != 1) {
            adminUser.setCompanyId(company.getId());
        }
        Token token = createToken(adminUser);

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

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

        //记录登录日志
        addLoginLog(adminUser, phone, null);

        return adminLoginVO;
    }




    /**
     * 管理员登录
     *
     * @param name     管理员名称
     * @param password 管理员密码
     * @return
     */
    @Override
    public AdminLoginVO login(String name, String password, String companyName, String type) {

        CompanyErp company = null;
        if ("com".equals(type) && StrUtil.isNotBlank(companyName)) {
            if (StrUtil.isBlank(companyName)) {
                throw new ServiceException("非平台工作人员公司必填");
            }
            company = companyManager.getOne(new LambdaQueryWrapper<CompanyErp>().eq(CompanyErp::getName,companyName));
            if (ObjectUtil.isNull(company)) {
                throw new ServiceException("该公司未注册");
            }
            if (company.getStatus() != 1) {
                throw new ServiceException("公司状态异常，限制登录，联系管理员申请解除限制");
            }
            if (new Date().compareTo(company.getEndUseTime()) > 0) {
                throw new ServiceException("该公司使用已到期，请续费");
            }
        }

        //查询管理员信息
        LambdaQueryWrapper<AdminUser> queryWrapper = new LambdaQueryWrapper<AdminUser>()
                .eq(AdminUser::getUsername, name)
                .eq(AdminUser::getUserState, 0);
        if ("com".equals(type)) {
            queryWrapper.eq(AdminUser::getCompanyId, company.getId());
            queryWrapper.eq(AdminUser::getPassword, StringUtil.md5(name + password + company.getId()).toLowerCase());
        } else {
            queryWrapper.eq(AdminUser::getPassword, StringUtil.md5(name + password).toLowerCase());
        }
        AdminUser adminUser = adminUserMapper.selectOne(queryWrapper);
        //管理员信息不存在
        if (adminUser == null || !StringUtil.equals(adminUser.getUsername(), name)) {
            throw new ServiceException(SystemErrorCode.E918.code(), "管理员账号密码错误");
        }
        if (adminUser.getFounder() != 1) {
            if (!adminUser.getCompanyId().equals(company.getId())) {
                throw new ServiceException("此账号不属于该公司");
            }
        }
//        if ("admin".equals(name) && password.equals(adminUser.getFirstPassword())){
//            throw new ServiceException("第一次登录需修改密码");
//        }
        //返回管理员信息
        AdminLoginVO adminLoginVO = new AdminLoginVO();
        adminLoginVO.setUid(adminUser.getId());

        adminLoginVO.setUsername(name);
        adminLoginVO.setCompanyVo(company);
        adminLoginVO.setDepartment(adminUser.getDepartment());
        adminLoginVO.setFace(adminUser.getFace());
        adminLoginVO.setRoleId(adminUser.getRoleId());
        adminLoginVO.setFounder(adminUser.getFounder());
        adminLoginVO.setDeptId(adminUser.getDeptId());
        adminLoginVO.setHasDeptManager(adminUser.getHasDeptManager());
        // 设置访问token的失效时间维持管理员在线状态
        if (adminUser.getFounder() != 1) {
            adminUser.setCompanyId(company.getId());
        }
        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.setCompanyId(adminUser.getCompanyId());
        admin.setUsername(adminUser.getUsername());
        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;
    }

    @Override
    public List<AdminUser> getUserByCompany() {
        //找出所有人子部门下的所有人
        List<AdminUser> adminUsers = adminUserMapper.selectList(new LambdaQueryWrapper<AdminUser>()
                .eq(ObjectUtil.isNotNull(AdminUserContext.getCompanyId()), AdminUser::getCompanyId, AdminUserContext.getCompanyId()));

        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());
        systemLogs.setCompanyId(AdminUserContext.getCompanyId());
        systemLogsManager.add(systemLogs);
    }
}
