package com.skr.mdm.api.admin.service.impl;

import cn.hutool.core.lang.Validator;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.skr.mdm.api.admin.service.AdminService;
import com.skr.mdm.bean.qo.admin.AdminInfoQO;
import com.skr.mdm.bean.qo.admin.AdminQO;
import com.skr.mdm.bean.vo.admin.AdminVO;
import com.skr.mdm.bean.vo.role.AllRoleVO;
import com.skr.mdm.dao.*;
import com.skr.mdm.dto.LoginAdminDTO;
import com.skr.mdm.entity.*;
import com.skr.mdm.enums.LogAdminTypeEnum;
import com.skr.mdm.enums.ResultCodeEnum;
import com.skr.mdm.handle.DownloadCounterHandler;
import com.skr.mdm.handle.LogAdminHandler;
import com.skr.mdm.result.ResponseResult;
import com.skr.mdm.util.PageUtil;
import com.skr.mdm.util.RedisGetKeyUtil;
import com.skr.mdm.util.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;

/**
 * @author nfq
 * @date 2020/9/9 15:36
 */
@Service
@Slf4j
public class AdminServiceImpl implements AdminService {

    private final String MODULE = "管理员管理";

    @Autowired
    private AuRoleDao roleDao;
    @Autowired
    private AuAdminDao adminDao;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AuAdminRoleDao adminRoleDao;
    @Autowired
    private LogAdminHandler logAdminHandler;
    @Autowired
    private AuDepartmentDao departmentDao;
    @Autowired
    private AuAdminDepartmentDao adminDepartmentDao;
    @Autowired
    private RedisUtils redisUtils;
    @Autowired
    private AuCompanyDao companyDao;
    @Autowired
    private DownloadCounterHandler downloadCounterHandler;

    @Override
    public ResponseResult adminInfo(Integer id) {
        AuAdministratorDO administratorDO = adminDao.selectById(id);
        if (administratorDO == null) {
            return ResponseResult.failure(ResultCodeEnum.LOGIN_EXPIRE);
        }
        AdminVO adminVO = new AdminVO();
        BeanUtils.copyProperties(administratorDO, adminVO);
        String roleName = roleDao.getRoleNameByAdminId(id);
        adminVO.setRoleName(roleName);
        AuCompanyDO companyDO = companyDao.selectById(administratorDO.getCompanyId());
        if (companyDO != null) {
            adminVO.setCompanyName(companyDO.getCompanyName());
        }
        return ResponseResult.success(adminVO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult updateAdminInfo(AdminInfoQO adminInfoQO, LoginAdminDTO loginAdminDTO) {
        ResponseResult updateCheck = updateCheck(adminInfoQO.getId(), adminInfoQO.getEmail(), null);
        if (updateCheck != null) {
            return updateCheck;
        }
        AuAdministratorDO administratorDO = adminDao.selectById(adminInfoQO.getId());
        if (administratorDO != null) {
            // 校验原密码
            boolean matches = passwordEncoder.matches(adminInfoQO.getOldPassword(), administratorDO.getPassword());
            if (!matches) {
                return ResponseResult.failure(ResultCodeEnum.PASSWORD_FAILURE);
            }
        }
        AuAdministratorDO auAdministratorDO = new AuAdministratorDO();
        auAdministratorDO.setId(adminInfoQO.getId());
        auAdministratorDO.setEmail(adminInfoQO.getEmail());
        auAdministratorDO.setPassword(passwordEncoder.encode(adminInfoQO.getNewPassword()));
        adminDao.updateById(auAdministratorDO);

        String content = "修改管理员信息(密码邮箱)";
        String module = "管理员信息";
        logAdminHandler.log(loginAdminDTO, loginAdminDTO.getAdminName(), LogAdminTypeEnum.OTHER_TYPE.getLogType(), content, module);
        return ResponseResult.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult allRoles(Integer companyId, Integer roleId) {
        AuRoleDO auRoleDO = roleDao.selectById(roleId);
        Integer level = auRoleDO.getLevel();
        LambdaQueryChainWrapper<AuRoleDO> queryChainWrapper = new LambdaQueryChainWrapper<>(roleDao);
        List<AuRoleDO> roleDOList = queryChainWrapper
                .eq(AuRoleDO::getCompanyId, companyId)
                .gt(AuRoleDO::getLevel, level)
                .list();
        List<AllRoleVO> allRoleVOList = new ArrayList<>(roleDOList.size());
        if (CollectionUtils.isNotEmpty(roleDOList)) {
            roleDOList.forEach(roleDO -> {
                AllRoleVO allRoleVO = new AllRoleVO();
                BeanUtils.copyProperties(roleDO, allRoleVO);
                allRoleVOList.add(allRoleVO);
            });
        }
        return ResponseResult.success(allRoleVOList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult addAdmin(AdminQO adminQO, LoginAdminDTO loginAdminDTO) {
        ResponseResult check = addCheck(adminQO.getEmail(), adminQO.getAdminName());
        if (check != null) {
            return check;
        }
        AuAdministratorDO administratorDO = new AuAdministratorDO();
        administratorDO.setAdminName(adminQO.getAdminName());
        administratorDO.setPassword(passwordEncoder.encode(adminQO.getPassword()));
        administratorDO.setEmail(adminQO.getEmail());
        administratorDO.setCompanyId(loginAdminDTO.getCompanyId());
        administratorDO.setDeleted(0);
        administratorDO.setUsable(1);
        AuDepartmentDO departmentDO = new LambdaQueryChainWrapper<>(departmentDao)
                .eq(AuDepartmentDO::getCompanyId, loginAdminDTO.getCompanyId())
                .eq(AuDepartmentDO::getIsDefault, 1)
                .one();
        Integer deptId = null;
        if (departmentDO == null) {
            deptId = loginAdminDTO.getDepartmentId();
        } else {
            deptId = departmentDO.getId();
        }
        administratorDO.setDepartmentId(deptId);
        adminDao.insert(administratorDO);

        AuAdminRoleDO adminRoleDO = new AuAdminRoleDO();
        adminRoleDO.setAdminId(administratorDO.getId());
        adminRoleDO.setRoleId(adminQO.getRoleId());
        adminRoleDao.insert(adminRoleDO);

        adminDepartmentDao.insertBatch(administratorDO.getId(), adminQO.getDepartmentIdList());

        if (loginAdminDTO.getId() != null) {
            String content = "添加管理员";
            logAdminHandler.log(loginAdminDTO, adminQO.getAdminName(), LogAdminTypeEnum.OTHER_TYPE.getLogType(), content, MODULE);
        }
        return ResponseResult.success();
    }

    @Override
    public ResponseResult listAdmin(Integer pageNum, Integer pageSize, Integer companyId, Integer searchType, String searchValue, Integer adminId) {
        Integer adminLevel = roleDao.getAdminLevel(adminId);
        PageHelper.startPage(pageNum, pageSize);
        List<AdminVO> adminVOList = adminDao.listAdmin(companyId, searchType, searchValue, adminLevel);
        PageInfo<AdminVO> pageInfo = new PageInfo<>(adminVOList);
        return ResponseResult.success(PageUtil.getPageResult(pageInfo));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult updateAdmin(AdminQO adminQO, LoginAdminDTO loginAdminDTO) {
        ResponseResult updateCheck = updateCheck(adminQO.getId(), adminQO.getEmail(), adminQO.getAdminName());
        if (updateCheck != null) {
            return updateCheck;
        }
        String password = "";
        if (StringUtils.isNotBlank(adminQO.getPassword())) {
            password = passwordEncoder.encode(adminQO.getPassword());
        }
        LambdaUpdateChainWrapper<AuAdministratorDO> updateChainWrapper = new LambdaUpdateChainWrapper<>(adminDao);
        updateChainWrapper
                .set(StringUtils.isNotBlank(adminQO.getAdminName()), AuAdministratorDO::getAdminName, adminQO.getAdminName())
                .set(StringUtils.isNotBlank(adminQO.getEmail()), AuAdministratorDO::getEmail, adminQO.getEmail())
                .set(StringUtils.isNotBlank(adminQO.getPassword()), AuAdministratorDO::getPassword, password)
                .eq(AuAdministratorDO::getId, adminQO.getId())
                .update();

        if (adminQO.getRoleId() != null) {
            LambdaUpdateChainWrapper<AuAdminRoleDO> chainWrapper = new LambdaUpdateChainWrapper<>(adminRoleDao);
            chainWrapper.set(AuAdminRoleDO::getRoleId, adminQO.getRoleId())
                    .eq(AuAdminRoleDO::getAdminId, adminQO.getId())
                    .update();
        }

        if (CollectionUtils.isNotEmpty(adminQO.getDepartmentIdList())) {
            LambdaQueryWrapper<AuAdminDepartmentDO> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(AuAdminDepartmentDO::getAdminId, adminQO.getId());
            adminDepartmentDao.delete(queryWrapper);
            adminDepartmentDao.insertBatch(adminQO.getId(), adminQO.getDepartmentIdList());
        }
        String content = "编辑管理员";
        logAdminHandler.log(loginAdminDTO, adminQO.getAdminName(), LogAdminTypeEnum.OTHER_TYPE.getLogType(), content, MODULE);
        return ResponseResult.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ResponseResult deleteAdmin(Integer id, LoginAdminDTO loginAdminDTO) {
        AuAdministratorDO administratorDO = adminDao.selectById(id);
        if (administratorDO == null) {
            return ResponseResult.failure();
        }

        String adminName = administratorDO.getAdminName();
        adminDao.deleteById(id);
        adminRoleDao.delete(Wrappers.lambdaQuery(AuAdminRoleDO.class).eq(AuAdminRoleDO::getAdminId, id));
        adminDepartmentDao.delete(Wrappers.lambdaQuery(AuAdminDepartmentDO.class).eq(AuAdminDepartmentDO::getAdminId, id));

        String content = "删除管理员";
        logAdminHandler.log(loginAdminDTO, adminName, LogAdminTypeEnum.OTHER_TYPE.getLogType(), content, MODULE);
        return ResponseResult.success();
    }

    @Override
    public ResponseResult lockOrUnlock(Integer id, Integer usable, LoginAdminDTO loginAdminDTO) {
        AuAdministratorDO administratorDO = adminDao.selectById(id);
        if (administratorDO == null) {
            return ResponseResult.failure();
        }

        redisUtils.del(RedisGetKeyUtil.getAdminTokenKey(administratorDO.getToken()));
        redisUtils.del(RedisGetKeyUtil.getAdminRefreshToken(administratorDO.getRefreshToken()));
        redisUtils.del(RedisGetKeyUtil.getAdminLoginIdKey(administratorDO.getId().toString()));

        String adminName = administratorDO.getAdminName();
        LambdaUpdateChainWrapper<AuAdministratorDO> updateChainWrapper = new LambdaUpdateChainWrapper<>(adminDao);
        updateChainWrapper
                .set(AuAdministratorDO::getUsable, usable)
                .set(AuAdministratorDO::getToken, null)
                .set(AuAdministratorDO::getRefreshToken, null)
                .eq(AuAdministratorDO::getId, id)
                .update();

        String content = "冻结";
        if (usable == 1) {
            content = "解冻";
        }
        logAdminHandler.log(loginAdminDTO, adminName, LogAdminTypeEnum.OTHER_TYPE.getLogType(), content, MODULE);
        return ResponseResult.success();
    }

    private ResponseResult updateCheck(Integer id, String email, String adminName) {
        boolean isEmail = Validator.isEmail(email);
        // 邮箱格式校验
        if (!isEmail) {
            return ResponseResult.failure(ResultCodeEnum.EMAIL_ERROR);
        }
        LambdaQueryChainWrapper<AuAdministratorDO> queryChainWrapper = new LambdaQueryChainWrapper<>(adminDao);
        // 管理员名称判重
        if (StringUtils.isNotBlank(adminName)) {
            Long count = queryChainWrapper.eq(AuAdministratorDO::getAdminName, adminName)
                    .ne(AuAdministratorDO::getId, id).count();
            if (count > 0) {
                return ResponseResult.failure(ResultCodeEnum.ADMIN_NAME_REPEAT);
            }
        }
        // 邮箱判重
        Long countEmail = queryChainWrapper.eq(AuAdministratorDO::getEmail, email)
                .ne(AuAdministratorDO::getId, id).count();
        if (countEmail > 0) {
            return ResponseResult.failure(ResultCodeEnum.EMAIL_REPEAT);
        }
        return null;
    }

    @Override
    public ResponseResult addCheck(String email, String adminName) {
        if (StringUtils.isNotBlank(email)) {
            boolean isEmail = Validator.isEmail(email);
            if (!isEmail) {
                return ResponseResult.failure(ResultCodeEnum.EMAIL_ERROR);
            }
        }
        LambdaQueryChainWrapper<AuAdministratorDO> queryChainWrapper = new LambdaQueryChainWrapper<>(adminDao);
        Long count = queryChainWrapper.eq(AuAdministratorDO::getAdminName, adminName).count();
        if (count > 0) {
            return ResponseResult.failure(ResultCodeEnum.ADMIN_NAME_REPEAT);
        }
        Long countEmail = queryChainWrapper.eq(AuAdministratorDO::getEmail, email).count();
        if (countEmail > 0) {
            return ResponseResult.failure(ResultCodeEnum.EMAIL_REPEAT);
        }
        return null;
    }

}