package com.engine.salary.service.impl;

import com.alibaba.fastjson.JSON;
import com.api.formmode.mybatis.util.SqlProxyHandle;
import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.biz.EmployBiz;
import com.engine.salary.constant.SalaryDefaultTenantConstant;
import com.engine.salary.entity.SalarySobExtRangePO;
import com.engine.salary.entity.datacollection.DataCollectionEmployee;
import com.engine.salary.entity.hrm.DeptInfo;
import com.engine.salary.entity.hrm.PositionInfo;
import com.engine.salary.entity.hrm.SubCompanyInfo;
import com.engine.salary.entity.hrm.dto.EmployeeInfoExpandDTO;
import com.engine.salary.entity.hrm.dto.FieldSetting;
import com.engine.salary.entity.hrm.po.ExpandFieldSettingsPO;
import com.engine.salary.entity.salarysob.bo.SalarySobRangeBO;
import com.engine.salary.entity.salarysob.param.SalarySobRangeEmpQueryParam;
import com.engine.salary.entity.salarysob.po.SalarySobRangePO;
import com.engine.salary.enums.UserStatusEnum;
import com.engine.salary.enums.datacollection.UseEmployeeTypeEnum;
import com.engine.salary.enums.salarysob.TargetTypeEnum;
import com.engine.salary.mapper.datacollection.EmployMapper;
import com.engine.salary.mapper.hrm.ExpandFieldSettingsMapper;
import com.engine.salary.mapper.sys.SalarySysConfMapper;
import com.engine.salary.service.ExtEmpService;
import com.engine.salary.service.SalaryEmployeeService;
import com.engine.salary.service.SalarySobExtRangeService;
import com.engine.salary.service.SalarySobRangeService;
import com.engine.salary.sys.entity.po.SalarySysConfPO;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.SalaryI18nUtil;
import com.engine.salary.util.db.IdGenerator;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import weaver.conn.RecordSet;
import weaver.hrm.User;

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

/**
 * 人员信息
 * <p>Copyright: Copyright (c) 2022</p>
 * <p>Company: 泛微软件</p>
 *
 * @author qiantao
 * @version 1.0
 **/
@Slf4j
public class SalaryEmployeeServiceImpl extends Service implements SalaryEmployeeService {

    private EmployBiz employBiz = new EmployBiz();

    private EmployMapper getEmployMapper() {
        return SqlProxyHandle.getProxy(EmployMapper.class);
    }

    private SalarySobRangeService getSalarySobRangeService(User user) {
        return ServiceUtil.getService(SalarySobRangeServiceImpl.class, user);
    }

    private SalarySysConfMapper getSalarySysConfMapper() {
        return SqlProxyHandle.getProxy(SalarySysConfMapper.class);
    }


    private ExpandFieldSettingsMapper getExpandFieldSettingsMapper() {
        return SqlProxyHandle.getProxy(ExpandFieldSettingsMapper.class);
    }


    private ExtEmpService getExtEmpService(User user) {
        return ServiceUtil.getService(ExtEmpServiceImpl.class, user);
    }


    private SalarySobExtRangeService getSalarySobExtRangeService(User user) {
        return ServiceUtil.getService(SalarySobExtRangeServiceImpl.class, user);
    }

    boolean openExtEmp = true;

    @Override
    public List<DataCollectionEmployee> listAll(UseEmployeeTypeEnum empType) {
        List<DataCollectionEmployee> result = new ArrayList<>();
        if (empType == UseEmployeeTypeEnum.ORG) {
            result = employBiz.listAll();
        }
        if (empType == UseEmployeeTypeEnum.EXT) {
            result = getExtEmpService(user).listEmployee();
        }
        if (empType == UseEmployeeTypeEnum.ALL) {
            result.addAll(employBiz.listAll());
            result.addAll(getExtEmpService(user).listEmployee());
        }
        SalaryI18nUtil.i18nList(result);
        return result;
    }

    @Override
    public List<DataCollectionEmployee> listAllForReport() {
        List<DataCollectionEmployee> result = employBiz.listAllForReport();
        if (openExtEmp) {
            result.addAll(getExtEmpService(user).listAllForReport());
        }
        SalaryI18nUtil.i18nList(result);
        return result;
    }

    @Override
    public List<DataCollectionEmployee> listBySalarySobId(Long salarySobId) {

        List<DataCollectionEmployee> includeSalaryEmployees = new ArrayList<>();

        // 查询薪资账套的人员范围
        List<SalarySobRangePO> includeSalarySobRangePOS = getSalarySobRangeService(user).listBySalarySobIdAndIncludeType(salarySobId, NumberUtils.INTEGER_ONE);
        if (CollectionUtils.isNotEmpty(includeSalarySobRangePOS)) {
            // 将薪资账套的人员范围转换成人员查询参数
            List<SalarySobRangeEmpQueryParam> includeQueryParams = SalarySobRangeBO.convert2EmployeeQueryParam(includeSalarySobRangePOS);
            // 根据上一步的查询参数查询人员
            includeSalaryEmployees = listByParams(includeQueryParams);
            if (CollectionUtils.isEmpty(includeSalaryEmployees)) {
                return Collections.emptyList();
            }
            //去重
            includeSalaryEmployees = includeSalaryEmployees.stream().distinct().collect(Collectors.toList());
            // 查询薪资账套的人员范围（从范围中排除）
            List<SalarySobRangePO> excludeSalarySobRangePOS = getSalarySobRangeService(user).listBySalarySobIdAndIncludeType(salarySobId, NumberUtils.INTEGER_ZERO);
            if (CollectionUtils.isNotEmpty(excludeSalarySobRangePOS)) {
                // 将薪资账套的人员范围转换成人员查询参数
                List<SalarySobRangeEmpQueryParam> excludeQueryParams = SalarySobRangeBO.convert2EmployeeQueryParam(excludeSalarySobRangePOS);
                // 根据上一步的查询参数查询人员
                List<DataCollectionEmployee> excludeSalaryEmployees = listByParams(excludeQueryParams);
                // 需要排除的人员范围
                Set<Long> excludeEmployeeIds = SalaryEntityUtil.properties(excludeSalaryEmployees, DataCollectionEmployee::getEmployeeId);
                // 过滤人员
                includeSalaryEmployees = includeSalaryEmployees.stream()
                        .filter(salaryEmployee -> !excludeEmployeeIds.contains(salaryEmployee.getEmployeeId()))
                        .collect(Collectors.toList());
            }
        }

        //外部人员
        List<SalarySobExtRangePO> salarySobExtRangePOS = getSalarySobExtRangeService(user).listBySalarySobId(salarySobId);
        if (CollectionUtils.isNotEmpty(salarySobExtRangePOS)) {
            List<Long> ids = SalaryEntityUtil.properties(salarySobExtRangePOS, SalarySobExtRangePO::getTargetId, Collectors.toList());
            List<DataCollectionEmployee> extEmps = getExtEmpService(user).getEmployeeByIds(ids);
            extEmps = extEmps.stream().distinct().collect(Collectors.toList());

            includeSalaryEmployees.addAll(extEmps);
        }
        SalaryI18nUtil.i18nList(includeSalaryEmployees);
        return includeSalaryEmployees;
    }

    @Override
    public List<DataCollectionEmployee> getEmployeeByIdsAll(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return new ArrayList<>();
        }
        List<DataCollectionEmployee> employeeList = employBiz.getEmployeeByIdsAll(ids);
        if (openExtEmp) {
            employeeList.addAll(getExtEmpService(user).getEmployeeByIds(ids));
        }
        SalaryI18nUtil.i18nList(employeeList);
        return employeeList;
    }

    @Override
    public List<DataCollectionEmployee> listByIds(List<Long> ids) {
        if (CollectionUtils.isEmpty(ids)) {
            return Collections.emptyList();
        }
        List<DataCollectionEmployee> result = new ArrayList<>();
        if (openExtEmp) {
            result.addAll(getExtEmpService(user).getEmployeeByIds(ids));
        }
        result.addAll(employBiz.getEmployeeByIdsAll(ids));
        SalaryI18nUtil.i18nList(result);
        return result;
    }

    @Override
    public DataCollectionEmployee getEmployeeById(Long employeeId) {
        if (openExtEmp) {
            DataCollectionEmployee employee = getExtEmpService(user).getEmployeeById(employeeId);
            if (Objects.nonNull(employee)) {
                return SalaryI18nUtil.i18n(employee);
            }
        }
        DataCollectionEmployee employee = employBiz.getEmployeeById(employeeId);
        return SalaryI18nUtil.i18n(employee);
    }

    @Override
    public List<DataCollectionEmployee> getEmployeeByIds(List<Long> simpleEmployeeIds) {
        if (CollectionUtils.isEmpty(simpleEmployeeIds)) {
            return new ArrayList<>();
        }
        List<DataCollectionEmployee> employeeList = new ArrayList<>();
        List<List<Long>> partition = Lists.partition(simpleEmployeeIds, 1000);
        for (List<Long> longs : partition) {
            employeeList.addAll(employBiz.getEmployeeByIds(longs));
            if (openExtEmp) {
                employeeList.addAll(getExtEmpService(user).getEmployeeByIds(longs));
            }
        }
        return SalaryI18nUtil.i18nList(employeeList);

    }


    public List<DataCollectionEmployee> filterEmployees(List<DataCollectionEmployee> employees, String userName, String deparmentName, String mobile) {
        List<DataCollectionEmployee> employeeSameIds = employees.stream().filter(e -> (StringUtils.isBlank(userName) || Objects.equals(e.getUsername(), userName))
                        && (StringUtils.isBlank(deparmentName) || Objects.equals(e.getDepartmentName(), deparmentName))
                        && (StringUtils.isBlank(mobile) || Objects.equals(e.getMobile(), mobile)))
                .collect(Collectors.toList());
        //存在离职和在职状态取在职状态
        employeeSameIds = employeeSameIds.stream()
                .filter(e -> UserStatusEnum.getNormalStatus().contains(e.getStatus()))
                .collect(Collectors.toList());

        return SalaryI18nUtil.i18nList(employeeSameIds);
    }

    @Override
    public List<DataCollectionEmployee> matchImportEmployee(String confValue, List<DataCollectionEmployee> employeeList, String userName, String deparmentName, String mobile, String workcode, String idNo, Long uid) {
        if (uid != null) {
            return employeeList.stream()
                    .filter(e -> Objects.equals(e.getEmployeeId(), uid))
                    .collect(Collectors.toList());
        }

        List<DataCollectionEmployee> employees = new ArrayList<>();
        //“0”代表姓名+部门+手机号的匹配原则，“1”代表工号为唯一匹配原则
        if ("0".equals(confValue)) {
            employees = employeeList.stream().filter(e -> (StringUtils.isBlank(userName) || Objects.equals(e.getUsername(), userName))
                            && (StringUtils.isBlank(deparmentName) || Objects.equals(e.getDepartmentName(), deparmentName))
                            && (StringUtils.isBlank(mobile) || Objects.equals(e.getMobile(), mobile)))
                    .collect(Collectors.toList());
        } else if ("1".equals(confValue)) {
            employees = employeeList.stream().filter(e -> (StringUtils.isBlank(workcode) || Objects.equals(e.getWorkcode(), workcode)))
                    .collect(Collectors.toList());
        } else if ("2".equals(confValue)) {
            employees = employeeList.stream().filter(e -> (StringUtils.isBlank(idNo) || Objects.equals(e.getIdNo(), idNo)))
                    .collect(Collectors.toList());
        }

        return SalaryI18nUtil.i18nList(employees);

    }

    /**
     * 人员定位方式
     * “0”代表姓名+部门+手机号的匹配原则，“1”代表工号为唯一匹配原则
     *
     * @return
     */
    @Override
    public String empValidType() {
        SalarySysConfPO salarySysConfPO = getSalarySysConfMapper().getOneByCode("matchEmployeeMode");
        return (salarySysConfPO != null && salarySysConfPO.getConfValue() != null && !"".equals(salarySysConfPO.getConfValue())) ? salarySysConfPO.getConfValue() : "0";
    }

    @Override
    public List<DeptInfo> getDeptInfoList(List<Long> departmentIds) {
        return SalaryI18nUtil.i18nList(employBiz.getDeptInfoList(departmentIds));
    }

    @Override
    public List<DeptInfo> getVirtualDeptInfoList(List<Long> virtualDepartmentIds) {
        if (CollectionUtils.isEmpty(virtualDepartmentIds)) {
            return Collections.emptyList();
        }
        return SalaryI18nUtil.i18nList(getEmployMapper().getVirtualDeptInfoList(virtualDepartmentIds));
    }


    @Override
    public List<SubCompanyInfo> getSubCompanyInfoList(List<Long> subDepartmentIds) {
        return SalaryI18nUtil.i18nList(employBiz.getSubCompanyInfoList(subDepartmentIds));
    }

    @Override
    public List<SubCompanyInfo> getVirtualSubCompanyInfoList(List<Long> virtualSubDepartmentIds) {
        if (CollectionUtils.isEmpty(virtualSubDepartmentIds)) {
            return Collections.emptyList();
        }
        return SalaryI18nUtil.i18nList(getEmployMapper().getVirtualSubCompanyInfoList(virtualSubDepartmentIds));
    }


    @Override
    public List<PositionInfo> listPositionInfo(List<Long> positionIds) {
        return SalaryI18nUtil.i18nList(employBiz.listPositionInfo(positionIds));
    }

    @Override
    public List<DataCollectionEmployee> listEmployee() {
        List<DataCollectionEmployee> result = employBiz.listEmployee();
        if (openExtEmp) {
            result.addAll(getExtEmpService(user).listEmployee());
        }
        return SalaryI18nUtil.i18nList(result);
    }

    @Override
    public List<DataCollectionEmployee> listByParams(List<SalarySobRangeEmpQueryParam> includeQueryParams) {
        if (CollectionUtils.isEmpty(includeQueryParams)) {
            return Collections.emptyList();
        }

        List<DataCollectionEmployee> result = employBiz.listByParams(includeQueryParams);
        if (openExtEmp) {
            result.addAll(getExtEmpService(user).listByParams(includeQueryParams));
        }
        // 查询虚拟部门、分部人员信息
        List<SalarySobRangeEmpQueryParam> virtualParams = includeQueryParams.stream().filter(param ->
                (param.getTargetType().equals(TargetTypeEnum.SUBCOMPANY.name()) || param.getTargetType().equals(TargetTypeEnum.DEPT.name())) && ((List<Long>) param.getTargetIds()).get(0).compareTo(0L) < 0
        ).collect(Collectors.toList());

        result.addAll(employBiz.listByVirtualParams(virtualParams));

        // 从hrmresource和hrmresourcevirtual可能获取到重复人员数据，需要根据人员id去重
        result = result.stream().collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparingLong(DataCollectionEmployee::getEmployeeId))), ArrayList::new));

        return SalaryI18nUtil.i18nList(result);
    }

    /**
     * 根据离职日期获取离职信息
     *
     * @param dismissDate
     * @return
     */
    @Override
    public Map<Long, String> getResignationMapByDate(String dismissDate) {
        if (StringUtils.isBlank(dismissDate)) {
            return Collections.emptyMap();
        }
        List<DataCollectionEmployee> employeeList = employBiz.listByDismissDate(dismissDate);
        return SalaryEntityUtil.convert2Map(employeeList, DataCollectionEmployee::getEmployeeId, DataCollectionEmployee::getDismissdate);
    }

    @Override
    public List<DataCollectionEmployee> expandEmployeeInfo(List<Long> ids, EmployeeInfoExpandDTO param) {

        List<DataCollectionEmployee> employees = getEmployeeByIdsAll(ids);

        if (param != null) {
            RecordSet rs = new RecordSet();
            String sql = param.getExpandSql().replace("=$人员id$", "in (" + StringUtils.join(ids, ",") + ")")
                    .replace("in($人员id$)", "in (" + StringUtils.join(ids, ",") + ")");
            String primaryKey = param.getPk();
            rs.executeQuery(sql);
            while (rs.next()) {
                Map<String, String> extendData = new HashMap<>();
                param.getFieldSettings().forEach(setting -> {
                    String field = setting.getField();
                    String value = rs.getString(field);
                    setting.setValue(value);
                    extendData.put(field, value);
                });

                String id = rs.getString(primaryKey);
                employees.stream()
                        .filter(e -> id.equals(e.getEmployeeId().toString()))
                        .forEach(e -> e.setExtendData(extendData));
            }
        }
        return SalaryI18nUtil.i18nList(employees);
    }

    @Override
    public Map<Long, Map<String, String>> expandEmployeeMap(List<Long> ids, EmployeeInfoExpandDTO param) {
        if (CollectionUtils.isNotEmpty(ids) && param != null) {
            Map<Long, Map<String, String>> map = new HashMap<>();

            List<List<Long>> partition = Lists.partition(ids, 5);
            for (int i = 0; i < partition.size(); i++) {
                List<Long> idList = partition.get(i);
                RecordSet rs = new RecordSet();
                String sql = param.getExpandSql().replace("=$人员id$", " in (" + StringUtils.join(idList, ",") + ")")
                        .replace("in($人员id$)", " in (" + StringUtils.join(idList, ",") + ")");
                String primaryKey = param.getPk();
                rs.executeQuery(sql);

                log.info("扩展属性sql" + sql);

                while (rs.next()) {
                    Map<String, String> extendData = new HashMap<>();
                    param.getFieldSettings().forEach(setting -> {
                        String field = setting.getField();
                        String value = rs.getString(field);
                        setting.setValue(value);
                        extendData.put(field, value);
                    });

                    String id = rs.getString(primaryKey);
                    map.put(Long.valueOf(id), extendData);
                }
            }

            return map;
        }
        return new HashMap<>();
    }

    @Override
    public void saveEmployeeExpandFieldSettings(EmployeeInfoExpandDTO param) {
        String settings = JSON.toJSONString(param.getFieldSettings());

        Date now = new Date();

        if (Objects.nonNull(param.getId())) {
            ExpandFieldSettingsPO po = getExpandFieldSettingsMapper().getById(param.getId());
            if (po == null) {
                throw new RuntimeException("配置不存在！");
            }

            po.setPk(param.getPk());
            po.setExpandSql(param.getExpandSql());
            po.setFieldSetting(settings);
            po.setCreator((long) user.getUID());
            po.setUpdateTime(now);
            getExpandFieldSettingsMapper().update(po);

        } else {
            ExpandFieldSettingsPO po = ExpandFieldSettingsPO.builder()
                    .id(IdGenerator.generate())
                    .module(param.getModule())
                    .moduleInfo(param.getModuleInfo())
                    .pk(param.getPk())
                    .fieldSetting(settings)
                    .expandSql(param.getExpandSql())
                    .deleteType(0)
                    .creator((long) user.getUID())
                    .createTime(now)
                    .updateTime(now)
                    .tenantKey(SalaryDefaultTenantConstant.DEFAULT_TENANT_KEY)
                    .build();
            getExpandFieldSettingsMapper().insertIgnoreNull(po);
        }

    }


    @Override
    public EmployeeInfoExpandDTO getExpandFieldSettings(String module) {

        ExpandFieldSettingsPO po = getExpandFieldSettingsMapper().getByModule(module);

        if (po != null) {
            List<FieldSetting> list = JSON.parseArray(po.getFieldSetting(), FieldSetting.class);
            return EmployeeInfoExpandDTO.builder()
                    .id(po.getId())
                    .module(po.getModule())
                    .moduleInfo(po.getModuleInfo())
                    .pk(po.getPk())
                    .expandSql(po.getExpandSql())
                    .fieldSettings(list)
                    .build();

        }

        return null;
    }

    @Override
    public List<DataCollectionEmployee> getVirtualEmpByVirtualDepIds(List<Long> virtualDepartmentIds) {
        if (CollectionUtils.isEmpty(virtualDepartmentIds)) {
            return Collections.emptyList();
        }
        return getEmployMapper().listVirtualEmpByVirtualDepIds(virtualDepartmentIds);
    }

    @Override
    public List<DataCollectionEmployee> getVirtualEmpByVirtualSubCompanyIds(List<Long> virtualSubCompanyIds) {
        if (CollectionUtils.isEmpty(virtualSubCompanyIds)) {
            return Collections.emptyList();
        }
        return getEmployMapper().listVirtualEmpByVirtualSubCompanyIds(virtualSubCompanyIds);
    }

    @Override
    public List<DataCollectionEmployee> listBySubCompanyOrDepartment(List<Long> subCompanyIds, List<Long> departmentIds) {
        List<DataCollectionEmployee> employeeList = new ArrayList<>();
        employeeList.addAll(getEmployMapper().listBySubCompanyOrDepartment(subCompanyIds, departmentIds));
        if (openExtEmp) {
            employeeList.addAll(getExtEmpService(user).listBySubCompanyOrDepartment(subCompanyIds, departmentIds));
        }
        return SalaryI18nUtil.i18nList(employeeList);
    }
}
