package com.yifu.cloud.plus.v1.business.service.vacation.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import com.alibaba.excel.util.StringUtils;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.yifu.cloud.plus.v1.business.dto.vacation.AddOrUpdateTVacationInfoDTO;
import com.yifu.cloud.plus.v1.business.dto.vacation.ChangeVacationStatusDTO;
import com.yifu.cloud.plus.v1.business.dto.vacation.ImportVacationInfoDTO;
import com.yifu.cloud.plus.v1.business.dto.vacation.UpdateVacationRedundancyDTO;
import com.yifu.cloud.plus.v1.business.entity.system.TBusDept;
import com.yifu.cloud.plus.v1.business.entity.vacation.TVacationInfo;
import com.yifu.cloud.plus.v1.business.entity.vacation.TVacationMonitor;
import com.yifu.cloud.plus.v1.business.mapper.vacation.TVacationInfoMapper;
import com.yifu.cloud.plus.v1.business.query.vacation.TVacationInfoQuery;
import com.yifu.cloud.plus.v1.business.service.system.TBusDeptService;
import com.yifu.cloud.plus.v1.business.service.vacation.TVacationInfoService;
import com.yifu.cloud.plus.v1.business.service.vacation.TVacationMonitorService;
import com.yifu.cloud.plus.v1.business.util.BusinessCommonContants;
import com.yifu.cloud.plus.v1.business.util.BusinessResultErrorMsg;
import com.yifu.cloud.plus.v1.business.vo.vacation.TVacationInfoVO;
import com.yifu.cloud.plus.v1.yifu.archives.entity.TBusinessEmployeeExtendInfo;
import com.yifu.cloud.plus.v1.yifu.archives.vo.TBusinessDataListVo;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CacheConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.exception.CheckedException;
import com.yifu.cloud.plus.v1.yifu.common.core.util.*;
import com.yifu.cloud.plus.v1.yifu.common.core.vo.YifuUser;
import com.yifu.cloud.plus.v1.yifu.common.dapr.util.ArchivesDaprUtil;
import com.yifu.cloud.plus.v1.yifu.common.security.util.SecurityUtils;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @description: 假勤信息表 service实现层
 * @author: huyc
 * @date: 2023/1/13
*/
@AllArgsConstructor
@Service
public class TVacationInfoServiceImpl extends ServiceImpl<TVacationInfoMapper, TVacationInfo>
implements TVacationInfoService {

    private final ObjectMapper objectMapper;

    private final TVacationMonitorService vacationMonitorService;

    private final Lock lock = new ReentrantLock();

	private final ArchivesDaprUtil archivesDaprUtil;

	private final TBusDeptService busDeptService;

    /**
     * @description: 分页查询: 条件分页查询
     * @param query 查询条件
     * @return: R<IPage<TVacationInfoVO>>
	 * @author: huyc
	 * @date: 2023/1/13
    */
    @Override
    public R<IPage<TVacationInfoVO>> getListByPage(TVacationInfoQuery query) {
        Page<TVacationInfoVO> page = new Page<>(query.getCurrent(), query.getSize());
        page.setOrders(query.getOrders());
        page = this.baseMapper.getListByPage(page, query);
        return R.ok(page,CommonConstants.SEARCH_SUCCESS);
    }

    /**
     * @description: 查询：根据条件出列表
     * @param query 查询条件
     * @return: IPage<com.yifu.cloud.v1.hrobusiness.api.vo.vacation.TVacationInfoVO>>
	 * @author: huyc
	 * @date: 2023/1/13
     */
    @Override
    public R<List<TVacationInfoVO>> getList(TVacationInfoQuery query) {
        List<TVacationInfoVO> list = this.baseMapper.getListByPage(query);
        return R.ok(list,CommonConstants.SEARCH_SUCCESS);
    }

    /**
     * @description: 查询-详情：根据id查询数据
     * @param id
     * @return: R<TVacationInfoVO>
     * @author: wangweiguo
     * @date: 2021-08-24
     */
    @Override
    public R<TVacationInfoVO> getDataById(String id) {
        TVacationInfoVO vo = this.baseMapper.getDataById(id);
        return R.ok(vo,CommonConstants.SEARCH_SUCCESS);
    }

    /**
     * @description: 销假：单条-根据id更新记录
     * @param dto dto
     * @return: R<Boolean>
     * @author: wangweiguo
     * @date: 2021-08-24
     */
    @Override
    public R<Boolean> vacationEnd(ChangeVacationStatusDTO dto) {
        YifuUser user = SecurityUtils.getUser();
        if (user == null) {
            return R.failed(BusinessResultErrorMsg.USER_NOT_LOGIN);
        }
        TVacationInfo entity = this.getById(dto.getId());
        if (null == entity) {
            return R.failed(BusinessResultErrorMsg.VACATION_INFO_NOT_EXIST);
        }
        if (null != dto.getActuralVacationEndTime() && !dto.getActuralVacationEndTime().isBefore(entity.getVacationEndTime()) && !dto.getActuralVacationEndTime().isEqual(entity.getVacationEndTime())) {
            return R.failed(BusinessResultErrorMsg.ACTURAL_START_END_TIME_ERROR);
        }
        entity.setVacationStatus(CommonConstants.THREE_STRING);
        entity.setVacationNote(dto.getVacationNote());
        entity.setActuralVacationEndTime(dto.getActuralVacationEndTime());
        entity.setUpdateUser(user.getNickname());
        entity.setUpdateUserId(user.getId());
        entity.setUpdateTime(LocalDateTime.now());
        boolean isSuccess = this.updateById(entity);
        return R.ok(isSuccess,CommonConstants.RESULT_DATA_SUCESS);
    }

    /**
     * @description: 导入: 通过json串格式导入假勤信息
     * @param jsonStr json字符串数据
     * @return: com.yifu.cloud.v1.common.core.util.R<java.lang.Boolean>
     * @author: wangweiguo
     * @date: 2021/8/24
     */
    @Override
    public R<List<ErrorMessage>> batchImportByJsonStr(String jsonStr) {
        YifuUser user = SecurityUtils.getUser();
        if (null == user) {
            return R.failed(BusinessResultErrorMsg.USER_NOT_LOGIN);
        }
        List<ErrorMessage> errorMessageList = new ArrayList<>();
        List<ImportVacationInfoDTO> list;
        try {
			list = objectMapper.readValue(jsonStr, new TypeReference<List<ImportVacationInfoDTO>>(){});
        } catch (InvalidFormatException e) {
            e.printStackTrace();
            if (e.getCause().toString().contains("DateTimeParseException")) {
                errorMessageList.add(new ErrorMessage(e.getPath().get(0).getIndex() + 2, BusinessResultErrorMsg.JSON_DATE_RESOLVER_ERROR.concat("错误值：" + e.getValue().toString())));
                return R.failed(errorMessageList,CommonConstants.UPDATE_DATA_FAIL);
            }
            errorMessageList.add(new ErrorMessage(e.getPath().get(0).getIndex() + 2, BusinessResultErrorMsg.JSON_RESOLVER_ERROR.concat(e.getCause().toString())));
			return R.failed(errorMessageList,CommonConstants.UPDATE_DATA_FAIL);
        } catch (Exception e) {
            e.printStackTrace();
            errorMessageList.add(new ErrorMessage(null, e.getCause().toString()));
            return R.failed(errorMessageList,CommonConstants.UPDATE_DATA_FAIL);
        }
        if (!CollUtil.isEmpty(list)) {
            errorMessageList.addAll(Common.commonImportErrorMessage(list));
			List<TBusinessEmployeeExtendInfo> employeeExtentList = new ArrayList<>();
			List<TBusDept> busDeptList = busDeptService.list();
            R<TBusinessDataListVo> sdRes = archivesDaprUtil.getAllExtendList();
			if (Common.isNotNull(sdRes) && Common.isNotNull(sdRes.getData())){
				employeeExtentList = sdRes.getData().getExtendInfo();
			}
            if (employeeExtentList.isEmpty()) {
                errorMessageList.add(new ErrorMessage(null, BusinessResultErrorMsg.EMPLOYEE_EXTENT_DATA_NOT_EXIST));
                return R.failed(errorMessageList,BusinessResultErrorMsg.EMPLOYEE_EXTENT_DATA_NOT_EXIST);
            }
            if (Common.isEmpty(busDeptList)) {
                errorMessageList.add(new ErrorMessage(null, BusinessResultErrorMsg.DEPART_DATA_NOT_EXIST));
                return R.failed(errorMessageList,BusinessResultErrorMsg.DEPART_DATA_NOT_EXIST);
            }

            // 初始化人员拓展信息map和假勤类型map
            HashMap<String, TBusinessEmployeeExtendInfo> employeeExtentMap= Common.listToHashMapByKey(employeeExtentList, "businessTelecomNumber");
            HashMap<String, TBusDept> busDeptMap= Common.listToHashMapByKey(busDeptList, "name");
            int size = list.size();
			Map<String,String> sysMap = new HashMap<>();
			Map<String,String> dicObj = (Map<String, String>) RedisUtil.redis.opsForValue().get(
					CacheConstants.DICT_DETAILS + CommonConstants.COLON_STRING + "HROB_VACATION_TYPE");
			if (Common.isNotNull(dicObj)) {
				for (Map.Entry<String, String> entry : dicObj.entrySet()) {
					sysMap.put(entry.getValue(),entry.getKey());
				}
			}
			if (sysMap.isEmpty()) {
				errorMessageList.add(new ErrorMessage(null, BusinessResultErrorMsg.SYS_ITEM_NOT_EXIST));
				return R.failed(errorMessageList,BusinessResultErrorMsg.SYS_ITEM_NOT_EXIST);
			}
			TBusinessEmployeeExtendInfo businessEmployeeExtend;
            for (int i = 0; i < size; i++) {
                int line = i + 2;
                TVacationInfo entity = new TVacationInfo();
                ImportVacationInfoDTO dto = list.get(i);
               	businessEmployeeExtend = employeeExtentMap.get(dto.getBusinessTelecomNumber());
                if (null == businessEmployeeExtend) {
                    errorMessageList.add(new ErrorMessage(line, BusinessResultErrorMsg.BUSINESS_TELECOM_NUMBER_NOT_EXIST, CommonConstants.RED));
                    continue;
                }
                TBusDept busDept = busDeptMap.get(businessEmployeeExtend.getDepartName());
                boolean isSave = true;
                if (!errorMessageList.isEmpty() && errorMessageList.stream().allMatch(e -> e.getLineNum() == line)) {
                    continue;
                }
                if (Common.isEmpty(sysMap.get(dto.getVacationType()))) {
                    errorMessageList.add(new ErrorMessage(line, BusinessResultErrorMsg.VACATION_TYPE_DATA_NOT_EXIST, CommonConstants.RED));
                    isSave = false;
                }
                if (StringUtils.equals(businessEmployeeExtend.getBusinessWorkingStatus(), CommonConstants.ONE_STRING)) {
                    errorMessageList.add(new ErrorMessage(line, BusinessResultErrorMsg.EMPLOYEE_ALREADY_LEAVE, CommonConstants.RED));
                    isSave = false;
                }
                if (null == busDept) {
                    busDept = new TBusDept();
                }
                if (dto.getVacationEndTime().isBefore(dto.getVacationStartTime())) {
                    errorMessageList.add(new ErrorMessage(line, BusinessResultErrorMsg.START_END_TIME_ERROR, CommonConstants.RED));
                    isSave = false;
                }
                if (!isSave) {
                    continue;
                }
                LocalDate vacationEnd = dto.getVacationEndTime();
                LocalDate vacationStart = dto.getVacationStartTime();
                BeanUtil.copyProperties(dto, entity, CopyOptions.create().setIgnoreNullValue(true).setIgnoreProperties("vacationEndTime", "vacationStartTime"));
                entity.setCreateUser(user.getNickname());
                entity.setCreateUserId(user.getId());
                entity.setBusinessPost(businessEmployeeExtend.getBusinessPost());
                entity.setEmpName(businessEmployeeExtend.getEmpName());
                entity.setEmpIdcard(businessEmployeeExtend.getEmpIdcard());
				entity.setVacationType(sysMap.get(dto.getVacationType()));
                entity.setDepartId(busDept.getId());
                entity.setCreateTime(LocalDateTime.now());
                entity.setVacationEndTime(vacationEnd.atStartOfDay());
                entity.setVacationStartTime(vacationStart.atStartOfDay());
                // 对年休假做处理
                if(StringUtils.equals(entity.getVacationType(), BusinessCommonContants.YEAR_VACATION_VALUE)) {
                    String year = String.valueOf(entity.getVacationStartTime().getYear());
                    try {
                        lock.lock();
                        TVacationMonitor monitor = this.vacationMonitorService.getMonitorByEmpIdcardAndYear(entity.getEmpIdcard(), year);
                        if (null == monitor) {
                            errorMessageList.add(new ErrorMessage(line, BusinessResultErrorMsg.VACATION_MONITOR_NOT_EXIST));
                            continue;
                        }
                        if (monitor.getNotUsedVacationDuration().compareTo(entity.getVacationDuration()) < 0) {
                            errorMessageList.add(new ErrorMessage(line, BusinessResultErrorMsg.SURPLUS_VACATION_NOT_ENOUGH));
                            continue;
                        }
                        // 消耗年休假
                        consumeVacationDuration(entity, monitor, year);
                    } finally {
                        lock.unlock();
                    }
                }
                boolean saveSuccess = this.save(entity);
                if (!saveSuccess) {
                    runTimeExceptionDiy(BusinessResultErrorMsg.CONSUME_YEAR_VACATION_DURATION_ERROR);
                } else {
                    errorMessageList.add(new ErrorMessage(line, BusinessResultErrorMsg.IMPORT_SUCCESS, CommonConstants.GREEN));
                }
            }
            errorMessageList.sort(Comparator.comparingInt(ErrorMessage::getLineNum));
            return R.ok(errorMessageList,CommonConstants.RESULT_DATA_SUCESS);
        } else {
            return R.failed(errorMessageList,CommonConstants.NO_DATA_TO_HANDLE);
        }
    }

    /**
     * 消耗年假
     * @param entity 假勤实体
     * @param monitor 监控信息
     * @param vacationYear 假勤年份
     */
    private void consumeVacationDuration(TVacationInfo entity, TVacationMonitor monitor, String vacationYear) {
        BigDecimal notUsedVacationDuration = monitor.getNotUsedVacationDuration();
        boolean consumeSuccess = this.vacationMonitorService.consumeVacationDuration(entity.getEmpIdcard(), entity.getVacationDuration(), vacationYear);
        if (!consumeSuccess) {
            runTimeExceptionDiy(BusinessResultErrorMsg.CONSUME_YEAR_VACATION_DURATION_ERROR);
        }
        entity.setVacationNotUsedDuration(BigDecimalUtils.safeSubtract(notUsedVacationDuration, entity.getVacationDuration()));
    }

    /**
     * @description: 删除-单条：根据id删除记录
     * @param id
     * @return: R<Boolean>
     * @author: wangweiguo
     * @date: 2021-08-24
     */
    @Transactional
    @Override
    public R<Boolean> removeDataById(String id) {
        TVacationInfo entity = this.getById(id);
        if (null == entity) {
            return R.failed(BusinessResultErrorMsg.VACATION_INFO_NOT_EXIST);
        }
        boolean isSuccess = this.removeById(id);
        if (isSuccess && StringUtils.equals(BusinessCommonContants.YEAR_VACATION_VALUE, entity.getVacationType())) {
            // 释放年休假
            String vacationYear = String.valueOf(entity.getVacationStartTime().getYear());
            TVacationMonitor monitor = this.vacationMonitorService.getMonitorByEmpIdcardAndYear(entity.getEmpIdcard(), vacationYear);
            if (null == monitor) {
                return R.failed(BusinessResultErrorMsg.VACATION_MONITOR_NOT_EXIST);
            }
            boolean releaseSuccess = this.vacationMonitorService.releaseVacationDuration(entity.getEmpIdcard(), entity.getVacationDuration(), String.valueOf(entity.getVacationStartTime().getYear()));
            if (!releaseSuccess) {
                runTimeExceptionDiy(BusinessResultErrorMsg.RELEASE_VACATION_DURATION_ERROR);
            }
        }
        return R.ok(isSuccess,CommonConstants.RESULT_DATA_SUCESS);
    }

    /**
     * @description: 添加：新增-单条-添加一条记录
     * @param dto
     * @return: R<TVacationInfo>
     * @author: wangweiguo
     * @date: 2021-08-24
     */
    @Transactional
    @Override
    public R<TVacationInfo> saveData(AddOrUpdateTVacationInfoDTO dto) {
        YifuUser user = SecurityUtils.getUser();
        if (user == null) {
            return R.failed(BusinessResultErrorMsg.USER_NOT_LOGIN);
        }
        R<TBusinessEmployeeExtendInfo> businessEmployeeExtendInfoR = archivesDaprUtil.getExtendByBusinessTelecomNumber(dto.getBusinessTelecomNumber());
        if (!R.haveData(businessEmployeeExtendInfoR)) {
            return R.failed(BusinessResultErrorMsg.EMPLOYEE_EXTENT_DATA_NOT_EXIST);
        }
        if (R.haveData(businessEmployeeExtendInfoR) && StringUtils.equals(businessEmployeeExtendInfoR.getData().getBusinessWorkingStatus(), CommonConstants.ONE_STRING)) {
            return R.failed(BusinessResultErrorMsg.EMPLOYEE_ALREADY_LEAVE);
        }
        TVacationInfo entity = new TVacationInfo();
        BeanUtil.copyProperties(dto, entity);
        entity.setCreateUser(user.getNickname());
        entity.setCreateUserId(user.getId());
        entity.setCreateTime(LocalDateTime.now());
        if (StringUtils.equals(BusinessCommonContants.YEAR_VACATION_VALUE, entity.getVacationType())) {
            String vacationYear = String.valueOf(dto.getVacationStartTime().getYear());
            try {
                lock.lock();
                TVacationMonitor monitor = this.vacationMonitorService.getMonitorByEmpIdcardAndYear(dto.getEmpIdcard(), vacationYear);
                if (null == monitor) {
                    return R.failed(BusinessResultErrorMsg.VACATION_MONITOR_NOT_EXIST);
                }
                // 剩余年假不足本次消耗
                if (monitor.getNotUsedVacationDuration().compareTo(dto.getVacationDuration()) < 0) {
                    return R.failed(BusinessResultErrorMsg.SURPLUS_VACATION_NOT_ENOUGH);
                }
                // 消耗年休假
                consumeVacationDuration(entity, monitor, vacationYear);
            } finally {
                lock.unlock();
            }
        }
        boolean isSuccess = this.save(entity);
        if (!isSuccess) {
            runTimeExceptionDiy(BusinessResultErrorMsg.CONSUME_VACATION_DURATION_ERROR);
        }
        return R.ok(entity,CommonConstants.RESULT_DATA_SUCESS);
    }

    /**
     * @author wangweiguo
     * @description 更新假勤信息中的冗余信息
     * @date 20:32 2021/8/24
     * @param dtoList 更新冗余字段dto集合
     * @return com.yifu.cloud.v1.common.core.util.R<java.lang.Boolean>
     **/
    @Override
    public R<Boolean> updateRedundancyEmployeeFields(List<UpdateVacationRedundancyDTO> dtoList) {
        if (!CollUtil.isEmpty(dtoList)) {
            dtoList.forEach(v ->
                this.lambdaUpdate().eq(TVacationInfo::getEmpIdcard, v.getEmpIdcard())
                        .set(TVacationInfo::getEmpName, v.getEmpName())
                        .set(TVacationInfo::getBusinessTelecomNumber, v.getBusinessTelecomNumber())
                        .set(TVacationInfo::getBusinessPost, v.getBusinessPost())
                        .set(TVacationInfo::getDepartId, v.getDepartId())
                        .update()
            );
        }
        return R.ok(null,CommonConstants.RESULT_DATA_SUCESS);
    }

	/**
	 * 抛个异常先
	 * @Author fxj
	 * @Date 2020-09-09
	 * @param errorInfo
	 * @return
	 **/
	public static void runTimeExceptionDiy(String errorInfo) {
		throw new CheckedException(errorInfo);
	}
}




