package com.engine.salary.service.auth;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.engine.core.impl.Service;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.salary.entity.auth.dto.AuthRoleDataDTO;
import com.engine.salary.entity.auth.param.AuthDataQueryParam;
import com.engine.salary.entity.auth.param.AuthDataSaveParam;
import com.engine.salary.entity.auth.param.AuthSyncParam;
import com.engine.salary.entity.auth.po.AuthDataPO;
import com.engine.salary.entity.auth.po.AuthRoleDataPO;
import com.engine.salary.entity.auth.po.AuthRolePO;
import com.engine.salary.enums.auth.DataLinkEnum;
import com.engine.salary.enums.auth.DataTargetTypeEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.auth.AuthDataMapper;
import com.engine.salary.mapper.auth.AuthRoleDataMapper;
import com.engine.salary.mapper.auth.AuthRoleEmpMapper;
import com.engine.salary.mapper.auth.AuthRoleMapper;
import com.engine.salary.util.db.IdGenerator;
import com.engine.salary.util.db.MapperProxyFactory;
import com.google.common.collect.Lists;

import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

public class AuthDataServiceImpl extends Service implements AuthDataService {


    private AuthDataMapper getAuthDataMapper() {
        return MapperProxyFactory.getProxy(AuthDataMapper.class);
    }

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

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

    private AuthRoleDataMapper getAuthRoleDataMapper() {
        return MapperProxyFactory.getProxy(AuthRoleDataMapper.class);
    }


    @Override
    public List<AuthDataPO> list(Long roleId) {
        AuthRolePO rolePO = getAuthRoleMapper().getById(roleId);
        if (rolePO == null) {
            throw new SalaryRunTimeException("角色不存在！");
        }
        return getAuthDataMapper().listSome(AuthDataPO.builder().roleId(roleId).build());
    }

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

            if (param.getId() == null) {
                AuthDataPO dataPO = AuthDataPO.builder()
                        .id(IdGenerator.generate())
                        .roleId(param.getRoleId())
                        .link(param.getLink().getValue())
                        .targetType(param.getTargetType().getValue())
                        .target(param.getTarget())
                        .targetName(param.getTargetName())
                        .sortedIndex(param.getSortedIndex() == null ? 0 : param.getSortedIndex())
                        .creator((long) user.getUID())
                        .createTime(now)
                        .updateTime(now)
                        .deleteType(0)
                        .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                        .build();
                getAuthDataMapper().insertIgnoreNull(dataPO);
            } else {
                getAuthDataMapper().getById(param.getId());
                AuthDataPO dataPO = AuthDataPO.builder()
                        .id(param.getId())
                        .link(param.getLink().getValue())
                        .targetType(param.getTargetType().getValue())
                        .target(param.getTarget())
                        .targetName(param.getTargetName())
                        .sortedIndex(param.getSortedIndex() == null ? 0 : param.getSortedIndex())
                        .creator((long) user.getUID())
                        .updateTime(now)
                        .deleteType(0)
                        .build();
                getAuthDataMapper().updateIgnoreNull(dataPO);
            }
        });
    }

    @Override
    public void delete(List<Long> ids) {
        if (CollectionUtil.isNotEmpty(ids)) {
            getAuthDataMapper().deleteByIds(ids);
        }
    }

    @Override
    public void sync(AuthSyncParam param) {
        Long roleId = param.getRoleId();
        Date now = new Date();
        List<AuthDataPO> list = list(roleId);

        Set<Long> ids = new HashSet<>();
        for (int i = 0; i < list.size(); i++) {
            AuthDataPO dataPO = list.get(i);
            DataTargetTypeEnum dataTargetTypeEnum = DataTargetTypeEnum.parseByValue(dataPO.getTargetType());
            DataLinkEnum dataLinkEnum = DataLinkEnum.parseByValue(dataPO.getLink());
            Set<Long> empResult = dataTargetTypeEnum.getEmpIds(dataPO.getTarget());
            if (i == 0) {
                ids = empResult;
            } else {
                ids = dataLinkEnum.calculation(ids, empResult);
            }
        }

        getAuthRoleDataMapper().deleteByRoleId(roleId);

        List<AuthRoleDataPO> collect = ids.stream().map(empId ->
                        AuthRoleDataPO.builder()
                                .id(IdGenerator.generate())
                                .roleId(roleId)
                                .employeeId(empId)
                                .creator((long) user.getUID())
                                .createTime(now)
                                .updateTime(now)
                                .deleteType(0)
                                .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                                .build())
                .collect(Collectors.toList());

        List<List<AuthRoleDataPO>> partition = Lists.partition(collect, 100);
        partition.forEach(pos -> getAuthRoleDataMapper().batchInsert(pos));
    }

    @Override
    public void deleteByRoleId(Long roleId) {
        getAuthDataMapper().deleteByRoleId(roleId);
        getAuthRoleDataMapper().deleteByRoleId(roleId);
    }

    @Override
    public List<AuthRoleDataDTO> listRoleData( AuthDataQueryParam param) {
        List<AuthRoleDataDTO> authRoleDataDTOS = getAuthRoleDataMapper().listRoleData(param.getRoleId());
        if (StrUtil.isNotEmpty(param.getUsername())){
            authRoleDataDTOS = authRoleDataDTOS.stream().filter(authRoleDataDTO -> authRoleDataDTO.getUsername().contains(param.getUsername())).collect(Collectors.toList());
        }
        return authRoleDataDTOS;
    }
}
