package com.engine.salary.service.auth;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.engine.core.impl.Service;
import com.engine.hrmelog.entity.dto.LoggerContext;
import com.engine.salary.config.SalaryElogConfig;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.salary.entity.auth.dto.AuthRoleEmpDTO;
import com.engine.salary.entity.auth.param.AuthMemberQueryParam;
import com.engine.salary.entity.auth.param.AuthMemberSaveParam;
import com.engine.salary.entity.auth.param.AuthSyncParam;
import com.engine.salary.entity.auth.po.AuthMemberPO;
import com.engine.salary.entity.auth.po.AuthRoleEmpPO;
import com.engine.salary.entity.auth.po.AuthRolePO;
import com.engine.salary.enums.OperateTypeEnum;
import com.engine.salary.enums.auth.MemberTargetTypeEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.auth.AuthMemberMapper;
import com.engine.salary.mapper.auth.AuthRoleEmpMapper;
import com.engine.salary.mapper.auth.AuthRoleMapper;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.db.IdGenerator;
import com.engine.salary.util.db.MapperProxyFactory;
import com.google.common.collect.Lists;

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

public class AuthMemberServiceImpl extends Service implements AuthMemberService {


    private AuthMemberMapper getAuthMemberMapper() {
        return MapperProxyFactory.getProxy(AuthMemberMapper.class);
    }

    private AuthRoleMapper getAuthRoleMapper() {
        return MapperProxyFactory.getProxy(AuthRoleMapper.class);
    }

    private AuthRoleEmpMapper getAuthRoleEmpMapper() {
        return MapperProxyFactory.getProxy(AuthRoleEmpMapper.class);
    }


    @Override
    public List<AuthMemberPO> list(Long roleId) {
        return getAuthMemberMapper().listSome(AuthMemberPO.builder().roleId(roleId).build());
    }

    @Override
    public void save(List<AuthMemberSaveParam> params) {
        params.forEach(param -> {
            AuthRolePO rolePO = getAuthRoleMapper().getById(param.getRoleId());
            if (rolePO == null) {
                throw new SalaryRunTimeException("角色不存在！");
            }

            Date now = new Date();
            if (param.getId() == null) {
                AuthMemberPO po = AuthMemberPO.builder()
                        .id(IdGenerator.generate())
                        .roleId(param.getRoleId())
                        .target(param.getTarget())
                        .targetType(param.getTargetType().getValue())
                        .targetName(param.getTargetName())
                        .creator((long) user.getUID())
                        .createTime(now)
                        .updateTime(now)
                        .deleteType(0)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .build();
                getAuthMemberMapper().insertIgnoreNull(po);

                LoggerContext<AuthMemberPO> loggerContext = new LoggerContext<>();
                loggerContext.setUser(user);
                loggerContext.setTargetId(rolePO.getId() + "");
                loggerContext.setTargetName(rolePO.getName() + "成员：" + po.getId());
                loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
                loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "新增成员"));
                loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "新增成员"));
                loggerContext.setNewValues(po);
                SalaryElogConfig.authLinkLoggerTemplate.write(loggerContext);
            } else {
                AuthMemberPO oldPO = getAuthMemberMapper().getById(param.getId());
                AuthMemberPO newPo = AuthMemberPO.builder()
                        .id(param.getId())
                        .target(param.getTarget())
                        .targetType(param.getTargetType().getValue())
                        .targetName(param.getTargetName())
                        .creator((long) user.getUID())
                        .updateTime(now)
                        .deleteType(0)
                        .build();
                getAuthMemberMapper().updateIgnoreNull(newPo);

                LoggerContext<AuthMemberPO> loggerContext = new LoggerContext<>();
                loggerContext.setUser(user);
                loggerContext.setTargetId(rolePO.getId() + "");
                loggerContext.setTargetName(rolePO.getName() + "成员：" + newPo.getId());
                loggerContext.setOperateType(OperateTypeEnum.ADD.getValue());
                loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "编辑成员"));
                loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "编辑成员"));
                loggerContext.setOldValues(oldPO);
                loggerContext.setNewValues(newPo);
                SalaryElogConfig.authLinkLoggerTemplate.write(loggerContext);
            }

        });
    }

    @Override
    public void delete(List<Long> ids) {

        ids.forEach(id -> {
            AuthMemberPO po = getAuthMemberMapper().getById(id);
            if (po == null) {
                throw new SalaryRunTimeException("成员不存在！");
            }

            getAuthMemberMapper().deleteByIds(Collections.singleton(id));

            AuthRolePO rolePO = getAuthRoleMapper().getById(po.getRoleId());
            LoggerContext<AuthMemberPO> loggerContext = new LoggerContext<>();
            loggerContext.setUser(user);
            loggerContext.setTargetId(rolePO.getId() + "");
            loggerContext.setTargetName(rolePO.getName() + "成员：" + po.getId());
            loggerContext.setOperateType(OperateTypeEnum.DELETE.getValue());
            loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "删除成员"));
            loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "删除成员"));
            loggerContext.setNewValues(po);
            SalaryElogConfig.authLinkLoggerTemplate.write(loggerContext);
        });


    }

    @Override
    public void sync(AuthSyncParam param) {
        Long roleId = param.getRoleId();
        AuthRolePO rolePO = getAuthRoleMapper().getById(roleId);
        if (rolePO == null) {
            throw new SalaryRunTimeException("角色不存在！");
        }

        //1、获取成员
        List<AuthMemberPO> members = getAuthMemberMapper().listSome(AuthMemberPO.builder().roleId(roleId).build());
        Map<Integer, Set<String>> targetTypeMap = SalaryEntityUtil.group2Map(members, AuthMemberPO::getTargetType, AuthMemberPO::getTarget);

        //2、获取人员
        Set<Long> empIds = new HashSet<>();
        for (Integer targetType : targetTypeMap.keySet()) {
            Set<String> targetIds = targetTypeMap.get(targetType);
            List<Long> ids = MemberTargetTypeEnum.parseByValue(targetType).getEmpIds(targetIds);
            empIds.addAll(ids);
        }

        //3、更新成员关系
        getAuthRoleEmpMapper().deleteByRoleId(roleId);
        Date now = new Date();
        List<AuthRoleEmpPO> roleEmpPOS = empIds.stream()
                .map(empId -> AuthRoleEmpPO.builder()
                        .id(IdGenerator.generate())
                        .employeeId(empId)
                        .roleId(roleId)
                        .creator((long) user.getUID())
                        .createTime(now)
                        .updateTime(now)
                        .deleteType(0)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .build())
                .collect(Collectors.toList());
        if (CollUtil.isNotEmpty(roleEmpPOS)) {
            List<List<AuthRoleEmpPO>> partition = Lists.partition(roleEmpPOS, 100);
            partition.forEach(list -> getAuthRoleEmpMapper().batchInsert(list));
        }

        LoggerContext<AuthMemberPO> loggerContext = new LoggerContext<>();
        loggerContext.setUser(user);
        loggerContext.setTargetId(rolePO.getId() + "");
        loggerContext.setTargetName(rolePO.getName());
        loggerContext.setOperateType(OperateTypeEnum.DELETE.getValue());
        loggerContext.setOperateTypeName(SalaryI18nUtil.getI18nLabel(0, "同步成员"));
        loggerContext.setOperatedesc(SalaryI18nUtil.getI18nLabel(0, "同步成员"));
        SalaryElogConfig.authLinkLoggerTemplate.write(loggerContext);
    }

    @Override
    public void deleteByRoleId(Long roleId) {
        getAuthMemberMapper().deleteByRoleId(roleId);
        getAuthRoleEmpMapper().deleteByRoleId(roleId);
    }

    @Override
    public List<AuthRoleEmpDTO> listRoleEmp(AuthMemberQueryParam param) {
        List<AuthRoleEmpDTO> empDTOS = getAuthRoleEmpMapper().getByRoleId(param.getRoleId());
        if(StrUtil.isNotEmpty(param.getUsername())){
            empDTOS =  empDTOS.stream().filter(item -> item.getUsername().contains(param.getUsername())).collect(Collectors.toList());
        }

        return empDTOS;
    }
}
