package com.engine.salary.service.impl;

import com.engine.common.util.ServiceUtil;
import com.engine.core.impl.Service;
import com.engine.salary.encrypt.EncryptUtil;
import com.engine.salary.entity.datacollection.DataCollectionEmployee;
import com.engine.salary.entity.taxagent.dto.TaxAgentEmployeeDTO;
import com.engine.salary.entity.taxdeclaration.bo.TaxDeclarationBO;
import com.engine.salary.entity.taxdeclaration.bo.TaxDeclarationDetailBO;
import com.engine.salary.entity.taxdeclaration.dto.*;
import com.engine.salary.entity.taxdeclaration.param.TaxDeclarationDetailListQueryParam;
import com.engine.salary.entity.taxdeclaration.po.TaxDeclarationDetailPO;
import com.engine.salary.entity.taxdeclaration.po.TaxDeclarationPO;
import com.engine.salary.enums.salaryaccounting.EmployeeTypeEnum;
import com.engine.salary.exception.SalaryRunTimeException;
import com.engine.salary.mapper.taxdeclaration.TaxDeclarationDetailMapper;
import com.engine.salary.service.SalaryEmployeeService;
import com.engine.salary.service.TaxAgentService;
import com.engine.salary.service.TaxDeclarationDetailService;
import com.engine.salary.service.TaxDeclarationService;
import com.engine.salary.sys.entity.vo.OrderRuleVO;
import com.engine.salary.sys.service.SalarySysConfService;
import com.engine.salary.sys.service.impl.SalarySysConfServiceImpl;
import com.engine.salary.util.SalaryEntityUtil;
import com.engine.salary.util.db.MapperProxyFactory;
import com.engine.salary.util.page.PageInfo;
import com.engine.salary.util.page.SalaryPageUtil;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
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
 **/
public class TaxDeclarationDetailServiceImpl extends Service implements TaxDeclarationDetailService {

    private EncryptUtil encryptUtil = new EncryptUtil();

    private TaxDeclarationDetailMapper getTaxDeclarationDetailMapper() {
        return MapperProxyFactory.getProxy(TaxDeclarationDetailMapper.class);
    }

    private SalaryEmployeeService getSalaryEmployeeService() {
        return ServiceUtil.getService(SalaryEmployeeServiceImpl.class, user);
    }

    private TaxDeclarationService getTaxDeclarationService(User user) {
        return ServiceUtil.getService(TaxDeclarationServiceImpl.class, user);
    }

    private TaxAgentService getTaxAgentService(User user) {
        return ServiceUtil.getService(TaxAgentServiceImpl.class, user);
    }

    private SalaryEmployeeService getSalaryEmployeeService(User user) {
        return (SalaryEmployeeService) ServiceUtil.getService(SalaryEmployeeServiceImpl.class, user);
    }

    private SalarySysConfService getSalarySysConfService(User user) {
        return ServiceUtil.getService(SalarySysConfServiceImpl.class, user);
    }

    @Override
    public List<TaxDeclarationDetailPO> listByTaxDeclarationIdAndEmployeeIds(Long taxDeclarationId, Collection<Long> employeeIds) {
        if (CollectionUtils.isEmpty(employeeIds)) {
            return Collections.emptyList();
        }

        return getTaxDeclarationDetailMapper().listByTaxDeclarationIdAndEmployeeIds(taxDeclarationId, employeeIds);
    }

    @Override
    public PageInfo<TaxDeclarationEmployeeDTO> listPage4EmployeeIdByParam(TaxDeclarationDetailListQueryParam queryParam) {
        //排序配置
        OrderRuleVO orderRule = getSalarySysConfService(user).orderRule();
        queryParam.setOrderRule(orderRule);

//        SalaryPageUtil.start(queryParam.getCurrent(), queryParam.getPageSize());
        List<TaxDeclarationEmployeeDTO> taxDeclarationEmployeeDTOS = getTaxDeclarationDetailMapper().listPage4EmployeeId(queryParam);
        taxDeclarationEmployeeDTOS = taxDeclarationEmployeeDTOS.stream().filter(SalaryEntityUtil.distinctByKey(TaxDeclarationEmployeeDTO::getEmployeeId)).collect(Collectors.toList());

        List<TaxDeclarationEmployeeDTO> list = SalaryPageUtil.subList(queryParam.getCurrent(), queryParam.getPageSize(), taxDeclarationEmployeeDTOS);
        PageInfo<TaxDeclarationEmployeeDTO> pageInfo = new PageInfo<>(list, TaxDeclarationEmployeeDTO.class);
        pageInfo.setPageNum(queryParam.getCurrent());
        pageInfo.setPageSize(queryParam.getPageSize());
        pageInfo.setTotal(taxDeclarationEmployeeDTOS.size());
        return pageInfo;
    }

    @Override
    public PageInfo<TaxDeclarationDetailListDTO> listDtoPageByParam(TaxDeclarationDetailListQueryParam queryParam) {
        // 查询个税申报表明细的人员
        List<Long> employeeIdPage = getTaxDeclarationDetailMapper().listEmployeeId(queryParam.getTaxDeclarationId());
        PageInfo<TaxDeclarationDetailListDTO> dtoPage = new PageInfo<TaxDeclarationDetailListDTO>(TaxDeclarationDetailListDTO.class);
        dtoPage.setPageNum(queryParam.getCurrent());
        dtoPage.setPageSize(queryParam.getPageSize());
        if (null == employeeIdPage) {
            return dtoPage;
        }
        if (CollectionUtils.isNotEmpty(employeeIdPage)) {
            // 查询个税申报表明细
            List<TaxDeclarationDetailPO> taxDeclarationDetailPOS = listByTaxDeclarationIdAndEmployeeIds(queryParam.getTaxDeclarationId(), employeeIdPage);
            // 查询人员
            List<DataCollectionEmployee> simpleEmployees = getSalaryEmployeeService().getEmployeeByIdsAll(employeeIdPage);
            // List<SimpleEmployee> simpleEmployees = hrmCommonEmployeeService.getEmployeeByIds(employeeIdPage.getRecords(), tenantKey);
            // 转换成列表dto
            TaxDeclarationBO.buildDetailListDTO(queryParam.getTaxDeclarationId(), dtoPage, taxDeclarationDetailPOS, simpleEmployees);
        }
        return dtoPage;
    }

    @Override
    public PageInfo<TaxDeclarationLaborListDTO> listDtoPageByParam4Labor(TaxDeclarationDetailListQueryParam queryParam) {

        // 查询个税申报主表
        TaxDeclarationPO taxDeclarationPO = getTaxDeclarationService(user).getById(queryParam.getTaxDeclarationId());
        // 判断是否有权限查看
        boolean canSee = getTaxDeclarationService(user).checkByAuthority(taxDeclarationPO, (long) user.getUID());
        if (!canSee) {
            throw new SalaryRunTimeException("对不起，您暂时没有权限查看");
        }
        // 查询个税申报表明细的人员
        PageInfo<TaxDeclarationEmployeeDTO> employeeIdPage = listPage4EmployeeIdByParam(queryParam);
        PageInfo<TaxDeclarationLaborListDTO> dtoPage = new PageInfo<>(TaxDeclarationLaborListDTO.class);
        dtoPage.setPageSize(employeeIdPage.getPageSize());
        dtoPage.setPageNum(employeeIdPage.getPageNum());
        dtoPage.setTotal(employeeIdPage.getTotal());
        List list = employeeIdPage.getList();
        if (CollectionUtils.isNotEmpty(list)) {
            // 转换成列表dto
            List<TaxDeclarationLaborListDTO> taxDeclarationLaborListDTOS = listDto4Labor(queryParam.getTaxDeclarationId(), list);
            dtoPage.setList(taxDeclarationLaborListDTOS);
        }
        return dtoPage;
    }

    @Override
    public PageInfo<TaxDeclarationAnnualListDTO> listDtoPageByParam4Annual(TaxDeclarationDetailListQueryParam queryParam) {
        // 查询个税申报主表
        TaxDeclarationPO taxDeclarationPO = getTaxDeclarationService(user).getById(queryParam.getTaxDeclarationId());
        // 判断是否有权限查看
        boolean canSee = getTaxDeclarationService(user).checkByAuthority(taxDeclarationPO, (long) user.getUID());
        if (!canSee) {
            throw new SalaryRunTimeException("对不起，您暂时没有权限查看");
        }
        // 查询个税申报表明细的人员
        PageInfo<TaxDeclarationEmployeeDTO> employeeIdPage = listPage4EmployeeIdByParam(queryParam);
        PageInfo<TaxDeclarationAnnualListDTO> dtoPage = new PageInfo<>(TaxDeclarationAnnualListDTO.class);
        dtoPage.setPageSize(employeeIdPage.getPageSize());
        dtoPage.setPageNum(employeeIdPage.getPageNum());
        dtoPage.setTotal(employeeIdPage.getTotal());
        List list = employeeIdPage.getList();
        if (CollectionUtils.isNotEmpty(list)) {
            // 转换成列表dto
            List<TaxDeclarationAnnualListDTO> taxDeclarationLaborListDTOS = listDto4Annual(queryParam.getTaxDeclarationId(), list);
            dtoPage.setList(taxDeclarationLaborListDTOS);
        }
        return dtoPage;
    }

    @Override
    public List<TaxDeclarationLaborListDTO> listDto4Labor(Long taxDeclarationId, List<TaxDeclarationEmployeeDTO> taxDeclarationEmployees) {
        long employeeId = (long) user.getUID();
        // 查询个税申报主表
        TaxDeclarationPO taxDeclarationPO = getTaxDeclarationService(user).getById(taxDeclarationId);
        // 判断是否有权限查看
        boolean canSee = getTaxDeclarationService(user).checkByAuthority(taxDeclarationPO, employeeId);
        if (!canSee) {
            throw new SalaryRunTimeException("对不起，您暂时没有权限查看");
        }
        // 查询个税申报表明细
        List<Long> employeeIds = taxDeclarationEmployees.stream().map(TaxDeclarationEmployeeDTO::getEmployeeId).collect(Collectors.toList());
        List<TaxDeclarationDetailPO> taxDeclarationDetailPOS = listByTaxDeclarationIdAndEmployeeIds(taxDeclarationId, employeeIds);
        // 查询人员信息
        List<DataCollectionEmployee> simpleEmployees = getSalaryEmployeeService().getEmployeeByIdsAll(employeeIds);
        // 转换成列表dto
        return TaxDeclarationDetailBO.convert2ListDTO4Labor(taxDeclarationDetailPOS, taxDeclarationEmployees, simpleEmployees);
    }

    public List<TaxDeclarationAnnualListDTO> listDto4Annual(Long taxDeclarationId, List<TaxDeclarationEmployeeDTO> taxDeclarationEmployees) {
        long employeeId = (long) user.getUID();
        // 查询个税申报主表
        TaxDeclarationPO taxDeclarationPO = getTaxDeclarationService(user).getById(taxDeclarationId);
        // 判断是否有权限查看
        boolean canSee = getTaxDeclarationService(user).checkByAuthority(taxDeclarationPO, employeeId);
        if (!canSee) {
            throw new SalaryRunTimeException("对不起，您暂时没有权限查看");
        }
        // 查询个税申报表明细
        List<Long> employeeIds = taxDeclarationEmployees.stream().map(TaxDeclarationEmployeeDTO::getEmployeeId).collect(Collectors.toList());
        List<TaxDeclarationDetailPO> taxDeclarationDetailPOS = listByTaxDeclarationIdAndEmployeeIds(taxDeclarationId, employeeIds);
        // 查询人员信息
        List<DataCollectionEmployee> simpleEmployees = getSalaryEmployeeService().getEmployeeByIdsAll(employeeIds);
        // 转换成列表dto
        return TaxDeclarationDetailBO.convert2ListDTO4Annual(taxDeclarationDetailPOS, taxDeclarationEmployees, simpleEmployees);
    }

    /**
     * 根据权限范围过滤
     *
     * @param taxDeclarationPO
     * @param taxDeclarationEmployeeDTOS
     * @return
     */
    private List<TaxDeclarationEmployeeDTO> filterByAuthority(TaxDeclarationPO taxDeclarationPO, List<TaxDeclarationEmployeeDTO> taxDeclarationEmployeeDTOS) {
        long employeeId = user.getUID();
        if (CollectionUtils.isEmpty(taxDeclarationEmployeeDTOS)) {
            return Collections.emptyList();
        }
        // 判断是否开启了分权
        Boolean openDevolution = getTaxAgentService(user).isOpenDevolution();
        // 是否是总管理员
        Boolean isChief = getTaxAgentService(user).isChief(employeeId);
        if (BooleanUtils.isFalse(openDevolution) || isChief) {
            return taxDeclarationEmployeeDTOS;
        }
        // 查询权限范围内的人员
        List<TaxAgentEmployeeDTO> taxAgentEmployeeDTOS = getTaxAgentService(user).listTaxAgentAndEmployee(employeeId);
        Set<String> simpleEmployeeKeySet = SalaryEntityUtil.properties(taxAgentEmployeeDTOS, taxAgentEmployeeDTO -> taxAgentEmployeeDTO.getEmployeeId() + "-" + taxAgentEmployeeDTO.getTaxAgentId());
        // 查询权限范围内的外部人员
//        List<ExtEmployeePO> extEmployeePOS = extEmployeeService.listCanUseByEmployeeId(employeeId, tenantKey);
//        Set<String> extEmployeeKeySet = SalaryEntityUtil.properties(extEmployeePOS, extEmployeePO -> extEmployeePO.getId() + "-" + extEmployeePO.getTaxAgentId());
        // 根据权限范围过滤
        return taxDeclarationEmployeeDTOS.stream().filter(taxDeclarationEmployeeDTO -> {
            if (taxDeclarationEmployeeDTO.getEmployeeType() == null || Objects.equals(taxDeclarationEmployeeDTO.getEmployeeType(), EmployeeTypeEnum.ORGANIZATION.getValue())
                    && simpleEmployeeKeySet.contains(taxDeclarationEmployeeDTO.getEmployeeId() + "-" + taxDeclarationPO.getTaxAgentId())) {
                return true;
            }
//            if (Objects.equals(taxDeclarationEmployeeDTO.getEmployeeType(), EmployeeTypeEnum.EXT_EMPLOYEE.getValue())
//                    && extEmployeeKeySet.contains(taxDeclarationEmployeeDTO.getEmployeeId() + "-" + taxDeclarationPO.getTaxAgentId())) {
//                return true;
//            }
            return false;
        }).collect(Collectors.toList());
    }


    @Override
    public PageInfo<TaxDeclarationWageListDTO> listDtoPageByParam4Wage(TaxDeclarationDetailListQueryParam queryParam) {

        // 查询个税申报主表
        TaxDeclarationPO taxDeclarationPO = getTaxDeclarationService(user).getById(queryParam.getTaxDeclarationId());
        // 查询个税申报表明细的人员
        PageInfo<TaxDeclarationEmployeeDTO> employeeIdPage = SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize());
        // 判断是否开启了分权
        Boolean openDevolution = getTaxAgentService(user).isOpenDevolution();
        // 是否是总管理员
        Boolean isChief = getTaxAgentService(user).isChief((long) user.getUID());
//        if (BooleanUtils.isTrue(openDevolution) && !isChief) {
//            List<TaxDeclarationEmployeeDTO> taxDeclarationEmployeeDTOS = getTaxDeclarationDetailMapper().list4EmployeeId(queryParam.getTaxDeclarationId());
//            // 根据权限过滤
//            taxDeclarationEmployeeDTOS = filterByAuthority(taxDeclarationPO, taxDeclarationEmployeeDTOS);
//            employeeIdPage.setTotal(taxDeclarationEmployeeDTOS.size());
//            employeeIdPage.setList(SalaryPageUtil.subList((int) employeeIdPage.getPageNum(), (int) employeeIdPage.getPageSize(), taxDeclarationEmployeeDTOS));
//        } else {
        employeeIdPage = listPage4EmployeeIdByParam(queryParam);
//        }
        PageInfo<TaxDeclarationWageListDTO> dtoPage = SalaryPageUtil.buildPage(queryParam.getCurrent(), queryParam.getPageSize(), TaxDeclarationWageListDTO.class);
        dtoPage.setTotal(employeeIdPage.getTotal());
        if (CollectionUtils.isNotEmpty(employeeIdPage.getList())) {
            List<TaxDeclarationEmployeeDTO> list = employeeIdPage.getList();
            // 查询个税申报表明细
            Set<Long> employeeIds = SalaryEntityUtil.properties(list, TaxDeclarationEmployeeDTO::getEmployeeId);
            List<TaxDeclarationDetailPO> taxDeclarationDetailPOS = listByTaxDeclarationIdAndEmployeeIds(queryParam.getTaxDeclarationId(),
                    employeeIds);
            encryptUtil.decryptList(taxDeclarationDetailPOS, TaxDeclarationDetailPO.class);
            // 查询人员信息
            List<Long> simpleEmployeeIds = list.stream()
                    .filter(taxDeclarationEmployeeDTO -> Objects.equals(taxDeclarationEmployeeDTO.getEmployeeType(), EmployeeTypeEnum.ORGANIZATION.getValue()))
                    .map(TaxDeclarationEmployeeDTO::getEmployeeId)
                    .collect(Collectors.toList());
            List<DataCollectionEmployee> simpleEmployees = getSalaryEmployeeService(user).getEmployeeByIds(simpleEmployeeIds);
            // 查询人员薪资（身份证号码等）
//            List<SimpleUserInfo> simpleUserInfos = salaryEmployeeService.listByEmployeeIds(simpleEmployeeIds, tenantKey);
            // 查询外部人员
//            Set<Long> extEmployeeIds = employeeIdPage.getRecords().stream()
//                    .filter(taxDeclarationEmployeeDTO -> Objects.equals(taxDeclarationEmployeeDTO.getEmployeeType(), EmployeeTypeEnum.EXT_EMPLOYEE.getValue()))
//                    .map(TaxDeclarationEmployeeDTO::getEmployeeId)
//                    .collect(Collectors.toSet());
//            List<ExtEmployeePO> extEmployees = extEmployeeService.listByIds(extEmployeeIds, tenantKey);
            // 转换成列表dto
            List<TaxDeclarationWageListDTO> taxDeclarationWageListDTOS = TaxDeclarationDetailBO.convert2ListDTO4Wage(taxDeclarationDetailPOS,
                    employeeIdPage.getList(), simpleEmployees);
            dtoPage.setList(taxDeclarationWageListDTOS);
        }
        return dtoPage;

    }

    @Override
    public void batchSave(Collection<TaxDeclarationDetailPO> taxDeclarationDetailPOS) {
        if (CollectionUtils.isNotEmpty(taxDeclarationDetailPOS)) {
            taxDeclarationDetailPOS = encryptUtil.encryptList(new ArrayList<>(taxDeclarationDetailPOS), TaxDeclarationDetailPO.class);
            List<List<TaxDeclarationDetailPO>> partition = Lists.partition((List) taxDeclarationDetailPOS, 100);
            partition.forEach(getTaxDeclarationDetailMapper()::batchInsert);
        }
    }

    public List<TaxDeclarationDetailPO> listByTaxDeclarationIdAndEmployeeIds(Long taxDeclarationId, List<Long> employeeIds) {
        if (CollectionUtils.isEmpty(employeeIds)) {
            return Collections.emptyList();
        }

        List<TaxDeclarationDetailPO> taxDeclarationDetailPOS = getTaxDeclarationDetailMapper().listByTaxDeclarationIdAndEmployeeIds(taxDeclarationId, employeeIds);
        return encryptUtil.decryptList(taxDeclarationDetailPOS, TaxDeclarationDetailPO.class);
    }

    @Override
    public void deleteByTaxDeclarationIds(Collection<Long> taxDeclarationIds) {
        getTaxDeclarationDetailMapper().deleteByTaxDeclarationIds(taxDeclarationIds);
    }
}
