package jnpf.personnels.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jnpf.base.ActionResult;
import jnpf.enums.UserStateEnum;
import jnpf.model.common.PayRollJsonItem;
import jnpf.model.dto.FtbXcLochCheckDto;
import jnpf.model.dto.UserSalaryDto;
import jnpf.model.hr.PersonSalaryHistoryVo;
import jnpf.model.personnels.dto.salary.FtbPersonnelRosterSalaryHistoryDTO;
import jnpf.model.personnels.dto.salary.FtbPersonnelsSalaryInfo;
import jnpf.model.personnels.dto.salary.FtbPersonnelsSalaryTemporaryStorageCreatDto;
import jnpf.model.personnels.po.FtbPersonnelsRegistrationFormFieldOption;
import jnpf.model.personnels.po.FtbPersonnelsRegularManagement;
import jnpf.model.personnels.po.FtbPersonnelsSalaryTemporaryStorage;
import jnpf.model.personnels.po.FtbPersonnelsStaffRoster;
import jnpf.model.personnels.vo.salary.FtbPersonnelRosterSalaryVO;
import jnpf.model.personnels.vo.salary.FtbPersonnelsSalaryTemporaryStorageVo;
import jnpf.model.personnels.vo.salary.UserInfoWithSalary;
import jnpf.model.vo.FtbXcLochCheckVo;
import jnpf.permission.PositionApi;
import jnpf.permission.UserApi;
import jnpf.permission.entity.BasePositionGradesEntity;
import jnpf.permission.model.position.PositionGradesSampleBoundVO;
import jnpf.permission.model.user.UserBoundMoreInfoVO;
import jnpf.personnels.controller.web.salary.FtbPersonnelsSalaryController;
import jnpf.personnels.mapper.FtbPersonnelsRegistrationFormFieldOptionMapper;
import jnpf.personnels.mapper.FtbPersonnelsSalaryTemporaryStorageMapper;
import jnpf.personnels.service.FtbPersonnelsRegularManagementService;
import jnpf.personnels.service.FtbPersonnelsSalaryService;
import jnpf.personnels.service.FtbPersonnelsStaffRosterService;
import jnpf.personnels.service.FtbPersonnelsTransferManageService;
import jnpf.salary.QuerySalaryApi;
import jnpf.util.JsonUtil;
import jnpf.util.UserProvider;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Title: web薪酬
 * @Author: peng.hao
 * @create: 2024/5/22:14:56
 */
@Service
@Slf4j
public class FtbPersonnelsSalaryServiceImpl implements FtbPersonnelsSalaryService {

    @Autowired
    QuerySalaryApi salaryApi;

    @Autowired
    FtbPersonnelsStaffRosterService staffRosterService;

    @Autowired
    PositionApi positionApi;

    @Autowired
    UserApi userApi;

    @Resource
    FtbPersonnelsSalaryTemporaryStorageMapper temporaryStorageMapper;

    @Resource
    private FtbPersonnelsRegistrationFormFieldOptionMapper formFieldOptionMapper;

    @Resource
    FtbPersonnelsRegularManagementService regularManagementService;

    @Resource
    FtbPersonnelsTransferManageService transferManageService;


    @Override
    public void saveTheChangePayInformation(List<FtbPersonnelsSalaryInfo> salaryList,
                                            String userId,
                                            Date date,
                                            UserInfoWithSalary userInfo,
                                            String updateType,
                                            String remark,
                                            String operationType,
                                            Integer isDelete,
                                            Integer salaryType, String payrollSequenceId) {
        saveTheChangePayInformation(salaryList, userId, date, userInfo, updateType, remark, operationType, isDelete, salaryType, payrollSequenceId, null);
    }

    @Override
    public String saveTheChangePayInformation(List<FtbPersonnelsSalaryInfo> salaryList,
                                            String userId, Date date, UserInfoWithSalary userInfo,
                                            String updateType, String remark, String operationType, Integer isDelete,
                                            Integer salaryType, String payrollSequenceId, String tenantId) {
        log.error("人事调用[薪酬信息变更]: "
                + "userid[" + userId + "]    " +
                "userInfo[" + userInfo + "]    " +
                "updateType[" + updateType + "]    " +
                "operationType[" + operationType + "]    "
        );
        if (CollUtil.isEmpty(salaryList)){
            throw new RuntimeException("目标岗位暂无薪资结构，无法进行薪酬调整；建议选择是否调整薪酬为“否”！");
        }
        // 根据用户信息构建基础信息
        LambdaQueryWrapper<FtbPersonnelsStaffRoster> query = Wrappers.lambdaQuery();
        query.eq(FtbPersonnelsStaffRoster::getUserId, userId);
        FtbPersonnelsStaffRoster one = staffRosterService.getOne(query);

        UserSalaryDto userSalaryDto = new UserSalaryDto();
        if (StringUtils.isNotEmpty(one.getPhone())) {
            userSalaryDto.setFCardId(one.getPhone());
            userSalaryDto.setUserName(one.getName());
            userSalaryDto.setOperatorWorkNo(one.getSystemWokerId());
        } else {
            throw new RuntimeException("该用户没有手机号，无法使用薪酬功能；建议前往设置-账号与安全页面绑定手机号。");
        }
        userSalaryDto.setRankId(userInfo.getRankId());
        userSalaryDto.setRankName(userInfo.getRankName());
        userSalaryDto.setPostId(userInfo.getPostId());
        userSalaryDto.setPostName(userInfo.getPostName());
        userSalaryDto.setFOrgName(userInfo.getFOrgName());
        userSalaryDto.setFOrgId(userInfo.getFOrgId());
        // 更改为手机号
        userSalaryDto.setUserId(userId);
        userSalaryDto.setOperationType(operationType);
        // 更改类型
        userSalaryDto.setUpdateType(updateType);
        // 生效时间
        if (ObjectUtil.isEmpty(date)) {
            throw new RuntimeException("薪资生效时间不能为空!");
        }
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        String format = sdf.format(date);
        userSalaryDto.setChangeDate(format);
        // 加薪原因
//        if (StringUtils.isEmpty(remark)) userSalaryDto.setRemark("调整薪酬");
        if (StringUtils.isNotEmpty(remark)) userSalaryDto.setRemark(remark);
        userSalaryDto.setUpdateUserName(UserProvider.getUser().getUserName());
        userSalaryDto.setUpdateUserId(UserProvider.getUser().getUserId());
        // 移除过滤信息
        // 正则表达式匹配中文
        String regex = "^\\d+(\\.\\d+)?$";
        BigDecimal fTotalMoney = salaryList.stream().filter(item -> item.getFSetValue().matches(regex)).map(item -> BigDecimal.valueOf(Double.parseDouble(item.getFSetValue()))).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
        userSalaryDto.setFTotalMoney(fTotalMoney);
        List<PayRollJsonItem> collect = salaryList.stream().map(this::covert).collect(Collectors.toList());
        // 修改的薪资详情
        String jsonString = JSONObject.toJSONString(collect);
        userSalaryDto.setAfterSalaryJson(jsonString);
        userSalaryDto.setIsDelete(isDelete.toString());
        userSalaryDto.setSalaryType(salaryType);
        userSalaryDto.setSequenceId(payrollSequenceId);
        userSalaryDto.setTenantId(tenantId);
        userSalaryDto.setOperatorWorkNo(userInfo.getOperatorWorkNo());
        userSalaryDto.setTaskId(userInfo.getTaskId());
        userSalaryDto.setUserTypeId(userInfo.getUserTypeId());
        if (StringUtils.isNotEmpty(userInfo.getUserTypeId())){
            LambdaQueryWrapper<FtbPersonnelsRegistrationFormFieldOption> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(FtbPersonnelsRegistrationFormFieldOption::getId, userInfo.getUserTypeId());
            FtbPersonnelsRegistrationFormFieldOption formFieldOption = formFieldOptionMapper.selectOne(queryWrapper);
            userSalaryDto.setUserTypeName(formFieldOption == null ? "" : formFieldOption.getName());
        }
        userSalaryDto.setEntryDate(userInfo.getEntryDate());
        userSalaryDto.setBeComeDate(userInfo.getBeComeDate());
        ActionResult<String> actionResult = salaryApi.updateSalaryJson(userSalaryDto);
        if (actionResult == null) {
            log.error("updateSalaryJson={}",userSalaryDto);
            throw new RuntimeException("薪资修改调整失败!");
        }
        if (actionResult.getCode() == 400) {
            throw new RuntimeException(actionResult.getMsg());
        }
        return actionResult.getData();
    }


    public void removeUserAllSalary(String userId){
        ActionResult actionResult = salaryApi.removeUserAllSalary(userId);
        log.error("重复入职，没有选择薪资项，清除薪资项，userId={},res={}",userId, JSONUtil.toJsonStr(actionResult));
    }

    @SneakyThrows
    @Override
    public void voidSalary(String userId, String date, String salaryRecordId) {
        salaryApi.voidSalary(userId, date, salaryRecordId);
    }

    @Override
    public String lochCheck(String userId, Date lochStartTime, Date lochEndTime) {
        FtbXcLochCheckDto lochCheckDto = new FtbXcLochCheckDto();
        lochCheckDto.setUserId(userId);
        lochCheckDto.setLochStartTime(lochStartTime);
        lochCheckDto.setLochEndTime(lochEndTime);
        List<FtbXcLochCheckVo> ftbXcLochCheckVos = salaryApi.lochCheck(lochCheckDto);
        if (CollUtil.isEmpty(ftbXcLochCheckVos)) {
            return null;
         }
        return ftbXcLochCheckVos.stream().map(v->String.valueOf(v.getChangeDate())).collect(Collectors.joining(","));
    }

    @Override
    public List<Map<String, Object>> querySalaryIntersectionWithOtherBusiness(String userId, Date startData, Date endData) {
        startData = DateUtil.beginOfDay(startData);
        endData = DateUtil.endOfDay(endData);
        FtbXcLochCheckDto lochCheckDto = new FtbXcLochCheckDto();
        lochCheckDto.setUserId(userId);
        lochCheckDto.setLochStartTime(startData);
        lochCheckDto.setLochEndTime(endData);
        List<FtbXcLochCheckVo> ftbXcLochCheckVos = salaryApi.lochCheckAllSalary(lochCheckDto);
        List<Map<String, Object>> hashMaps = new ArrayList<>();
        if (CollUtil.isEmpty(ftbXcLochCheckVos)) {
            LambdaQueryWrapper<FtbPersonnelsRegularManagement> queryWrapper = Wrappers.lambdaQuery();
            queryWrapper.eq(FtbPersonnelsRegularManagement::getUserId, userId);
            queryWrapper.between(FtbPersonnelsRegularManagement::getActualConverDate, startData,endData );
            queryWrapper.in(FtbPersonnelsRegularManagement::getTransferStatus,2,6);
            queryWrapper.eq(FtbPersonnelsRegularManagement::getEnableMark,0);
            List<FtbPersonnelsRegularManagement> managements = regularManagementService.list(queryWrapper);
            if (CollUtil.isNotEmpty(managements)){
                List<Map<String, Object>> regularMaps = managements.stream().map(v -> {
                    Map<String, Object> map = new HashMap<>();
                    map.put("time", v.getActualConverDate());
                    map.put("type", "转正");
                    return map;
                }).collect(Collectors.toList());
                hashMaps.addAll(regularMaps);
            }
            List<Date> dates = transferManageService.transferCheckTimeCrossing(userId, startData, endData);
            if (CollUtil.isNotEmpty(dates)){
                List<Map<String, Object>> transferMaps = dates.stream().map(v -> {
                    Map<String, Object> map = new HashMap<>();
                    map.put("time", v);
                    map.put("type", "调动");
                    return map;
                }).collect(Collectors.toList());
                hashMaps.addAll(transferMaps);
            }
            FtbXcLochCheckDto lochCheckDto1 = new FtbXcLochCheckDto();
            lochCheckDto1.setUserId(userId);
            lochCheckDto1.setLochStartTime(startData);
            lochCheckDto1.setLochEndTime(endData);
            List<FtbXcLochCheckVo> ftbXcLochCheckVos1 = salaryApi.lochCheck(lochCheckDto1);
            if (CollUtil.isNotEmpty(ftbXcLochCheckVos1)){
                List<Map<String, Object>> hashMaps1 = ftbXcLochCheckVos1.stream().map(v -> {
                    Map<String, Object> map = new HashMap<>();
                    UserStateEnum userState = v.getUserState();
                    map.put("time", v.getChangeDate());
                    map.put("type", userState.getDesc());
                    return map;
                }).collect(Collectors.toList());
                hashMaps.addAll(hashMaps1);
            }
        }else{
            hashMaps = ftbXcLochCheckVos.stream().map(v -> {
                Map<String, Object> map = new HashMap<>();
                UserStateEnum userState = v.getUserState();
                map.put("time", v.getChangeDate());
                map.put("type", userState.getDesc());
                return map;
            }).collect(Collectors.toList());
        }
        return hashMaps;
    }

    @Override
    public List<FtbPersonnelRosterSalaryVO> getSalaryHistoryByUserId(FtbPersonnelRosterSalaryHistoryDTO dto) {
        if (StrUtil.isBlank(dto.getUserId())) {
            return new ArrayList<>();
        }
        List<PersonSalaryHistoryVo> salaryHistoryVos = salaryApi.getSalaryHistoryByUserId(dto.getUserId()).getData();
        if (CollUtil.isEmpty(salaryHistoryVos)) {
            return new ArrayList<>();
        }
        FtbPersonnelsStaffRoster personnelStaffRosters = staffRosterService.queryRosterInfoByUserId(dto.getUserId());
        List<FtbPersonnelRosterSalaryVO> vos = JsonUtil.getJsonToList(salaryHistoryVos, FtbPersonnelRosterSalaryVO.class);
        if (personnelStaffRosters != null) {
            vos.forEach(vo -> {
                if(null!=vo) {
                    vo.setSystemWokerId(personnelStaffRosters.getSystemWokerId());
                }
            });
        }

        return vos;
    }

    @Override
    public List<FtbPersonnelsSalaryInfo> getTheCurrentPersonSSalary(String userId, String rankId, String postId) {
        // 根据用户信息构建基础信息
        LambdaQueryWrapper<FtbPersonnelsStaffRoster> query = Wrappers.lambdaQuery();
        query.eq(FtbPersonnelsStaffRoster::getUserId, userId);
        FtbPersonnelsStaffRoster one = staffRosterService.getOne(query);
        String userName = "";
        String phone = "";
        if (ObjectUtil.isNotEmpty(one)) {
            phone = one.getPhone();
            userName = one.getName();
        }
        List<BasePositionGradesEntity> gradesEntityList = positionApi.getGradesEntityList(List.of(rankId));
        String rankName = "";
        if (CollUtil.isNotEmpty(gradesEntityList)) {
            rankName = gradesEntityList.stream().findFirst().get().getFullName();
        }
        ActionResult<List<PayRollJsonItem>> salaryJsonByUserId = salaryApi.getSalaryJsonByUserId(userId, userName, phone, rankId, rankName, postId);
        return getListActionResult(salaryJsonByUserId);
    }

    @Override
    public List<FtbPersonnelsSalaryInfo> innerGetTheCurrentPersonSSalary(FtbPersonnelsStaffRoster one, String rankId, String postId) {
        String userId = one.getUserId();
        String userName = "";
        String phone = "";
        if (ObjectUtil.isNotEmpty(one)) {
            phone = one.getPhone();
            userName = one.getName();
        }
//        List<BasePositionGradesEntity> gradesEntityList = positionApi.getGradesEntityList(List.of(rankId));
        String rankName = "";
//        if (CollUtil.isNotEmpty(gradesEntityList)) {
//            rankName = gradesEntityList.stream().findFirst().get().getFullName();
//        }
        ActionResult<List<PayRollJsonItem>> salaryJsonByUserId = salaryApi.getSalaryJsonByUserId(userId, userName, phone, rankId, rankName, postId);
        return getListActionResult(salaryJsonByUserId);
    }

    @Override
    public void regularizationRevoked(String userId) {
        ActionResult actionResult = salaryApi.revokeUserConfirmation(userId);
        if (actionResult == null) {
            throw new RuntimeException("转正薪资撤销失败!");
        }
        if (actionResult.getCode() == 400) {
            throw new RuntimeException(actionResult.getMsg());
        }
    }

    @Override
    public String whetherToVoidWages(String userId, List<PayRollJsonItem> beforeItem, String flag, Date changeDate) {
        UserSalaryDto userSalaryDto = new UserSalaryDto();
        BigDecimal fTotalMoney = beforeItem.stream().filter(item ->
                StringUtils.isNotEmpty(item.getfSetValue())
                        && "1".equals(item.getfValueType())
        ).map(item -> BigDecimal.valueOf(Double.parseDouble(item.getfSetValue()))).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
        userSalaryDto.setFTotalMoney(fTotalMoney);
        userSalaryDto.setIsDelete(flag);
        userSalaryDto.setChangeDate(DateUtil.format(changeDate, DatePattern.NORM_DATE_PATTERN));
        userSalaryDto.setUpdateUserId(UserProvider.getUser().getUserId());
        userSalaryDto.setUpdateUserName(UserProvider.getUser().getUserName());
        userSalaryDto.setAfterSalaryJson(JSONObject.toJSONString(beforeItem));
        userSalaryDto.setUserId(userId);
        userSalaryDto.setUpdateType("1");
        userSalaryDto.setOperationType("1");
        // 根据用户信息构建基础信息
        LambdaQueryWrapper<FtbPersonnelsStaffRoster> query = Wrappers.lambdaQuery();
        query.eq(FtbPersonnelsStaffRoster::getUserId, userId);
        FtbPersonnelsStaffRoster one = staffRosterService.getOne(query);
        if (StringUtils.isNotEmpty(one.getPhone())) {
            userSalaryDto.setFCardId(one.getPhone());
            userSalaryDto.setUserName(one.getName());
        } else {
            throw new RuntimeException("该用户没有手机号，无法使用薪酬功能；建议前往设置-账号与安全页面绑定手机号。");
        }
        List<UserBoundMoreInfoVO> workerGroupDataDtos = userApi.getUserBoundMoreInfosByUserId(userId);
        if (CollUtil.isNotEmpty(workerGroupDataDtos)) {
            UserBoundMoreInfoVO boundMoreInfoVO = workerGroupDataDtos.stream().filter(PositionGradesSampleBoundVO::getIsDefaultOrganize).findFirst().orElse(new UserBoundMoreInfoVO());
            userSalaryDto.setRankId(boundMoreInfoVO.getPositionGradesId());
            userSalaryDto.setRankName(boundMoreInfoVO.getPositionGradesName());
            userSalaryDto.setPostId(boundMoreInfoVO.getPositionId());
            userSalaryDto.setPostName(boundMoreInfoVO.getPositionName());
            userSalaryDto.setFOrgName(boundMoreInfoVO.getOrganizeName());
            userSalaryDto.setFOrgId(boundMoreInfoVO.getOrganizeId());
        }
        userSalaryDto.setRemark("作废薪资");
        ActionResult<String> actionResult = salaryApi.updateSalaryJson(userSalaryDto);
        if (actionResult == null) {
            throw new RuntimeException("薪资修改调整失败!");
        }
        if (actionResult.getCode() == 400) {
            throw new RuntimeException(actionResult.getMsg());
        }
        return actionResult.getData();
    }

    @Override
    public void creatSalaryTemporaryStorage(FtbPersonnelsSalaryTemporaryStorageCreatDto creatDto) {
        FtbPersonnelsSalaryTemporaryStorage covert = FtbPersonnelsSalaryTemporaryStorageCreatDto.covert(creatDto);
        List<FtbPersonnelsSalaryInfo> structureList = creatDto.getSalaryStructureList();
        if (CollUtil.isNotEmpty(structureList)){
            String string = JSONObject.toJSONString(structureList);
            covert.setSalaryStructureList(string);
        }
        temporaryStorageMapper.insert(covert);
    }

    @Override
    public void updateSalaryTemporaryStorage(FtbPersonnelsSalaryTemporaryStorageCreatDto creatDto) {

    }

    @Override
    public FtbPersonnelsSalaryTemporaryStorageVo querySalaryTemporaryStorage(String uerId, String configType) {
        LambdaQueryWrapper<FtbPersonnelsSalaryTemporaryStorage> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(FtbPersonnelsSalaryTemporaryStorage::getUserId,uerId);
        wrapper.eq(FtbPersonnelsSalaryTemporaryStorage::getConfigType,configType);
        FtbPersonnelsSalaryTemporaryStorage temporaryStorage = temporaryStorageMapper.selectOne(wrapper);
        FtbPersonnelsSalaryTemporaryStorageVo coverted = FtbPersonnelsSalaryTemporaryStorageVo.covert(temporaryStorage);
        if (StringUtils.isNotEmpty(temporaryStorage.getSalaryStructureList())){
            coverted.setSalaryStructureList(JSONObject.parseArray(temporaryStorage.getSalaryStructureList(), FtbPersonnelsSalaryInfo.class));
        }
        return coverted;
    }

    private List<FtbPersonnelsSalaryInfo> getListActionResult(ActionResult<List<PayRollJsonItem>> result) {
        if (result != null && result.getCode() == 200) {
            if (ObjectUtils.isEmpty(result.getData())) {
                return null;
            }
            return result.getData().stream().map(FtbPersonnelsSalaryController::covert).collect(Collectors.toList());
        }
        if (result != null && result.getCode() == 400) {
            // 薪酬报错不做处理返回空数据
            return null;
        }
        return null;
    }

    public PayRollJsonItem covert(FtbPersonnelsSalaryInfo salaryInfo) {
        if (salaryInfo == null) {
            return null;
        }
        PayRollJsonItem payRollJsonItem = new PayRollJsonItem();
        payRollJsonItem.setId(salaryInfo.getId());
        payRollJsonItem.setfIsForce(salaryInfo.getFIsForce());
        payRollJsonItem.setfCarryRule(salaryInfo.getFCarryRule());
        payRollJsonItem.setfName(salaryInfo.getFName());
        payRollJsonItem.setfSetType(salaryInfo.getFSetType());
        payRollJsonItem.setfSetValue(salaryInfo.getFSetValue());
        payRollJsonItem.setfValueType(salaryInfo.getFValueType());
        payRollJsonItem.setfReservedBits(salaryInfo.getDecimalPlaces());
        payRollJsonItem.setfRemark(salaryInfo.getFRemark());
        payRollJsonItem.setfItem(salaryInfo.getFItem());
        payRollJsonItem.setfTaxType(salaryInfo.getFTaxType());
        payRollJsonItem.setfSort(salaryInfo.getSort());
        payRollJsonItem.setfDesc(salaryInfo.getFDesc());
        payRollJsonItem.setSequenceType(salaryInfo.getSequenceType());
        payRollJsonItem.setfTypeSort(salaryInfo.getFTypeSort());
        payRollJsonItem.setfSort(salaryInfo.getFSort());
        payRollJsonItem.setGroupId(salaryInfo.getGroupId());
        payRollJsonItem.setGroupName(salaryInfo.getGroupName());
        if (StrUtil.isNotBlank(salaryInfo.getGroupSort())) {
            payRollJsonItem.setGroupSort(Integer.parseInt(salaryInfo.getGroupSort()));
        }
        return payRollJsonItem;
    }
}
