package com.yifu.cloud.plus.v1.permission.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yifu.cloud.plus.v1.permission.config.WxConfig;
import com.yifu.cloud.plus.v1.permission.mapper.EkpQiweiChuchaiMapper;
import com.yifu.cloud.plus.v1.permission.service.EkpQiweiWorkovertimeService;
import com.yifu.cloud.plus.v1.permission.service.EkpQiweiZhaopinService;
import com.yifu.cloud.plus.v1.permission.service.QiWeiService;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.CommonConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.constant.SecurityConstants;
import com.yifu.cloud.plus.v1.yifu.common.core.util.Common;
import com.yifu.cloud.plus.v1.yifu.common.core.util.DateUtil;
import com.yifu.cloud.plus.v1.yifu.common.core.util.LocalDateTimeUtils;
import com.yifu.cloud.plus.v1.yifu.common.core.util.R;
import com.yifu.cloud.plus.v1.yifu.insurances.util.LocalDateUtil;
import com.yifu.cloud.plus.v1.yifu.permission.entity.EkpQiwiChuchai;
import com.yifu.cloud.plus.v1.yifu.permission.entity.EkpQiwiWorkovertime;
import com.yifu.cloud.plus.v1.yifu.permission.entity.EkpQiwiZhaoPin;
import com.yifu.cloud.plus.v1.yifu.permission.vo.QiWeiUserVo;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 获取微信信息
 *
 * @author hgw
 * @date 2024-4-15 17:16:57
 */
@Service
@AllArgsConstructor
@Log4j2
public class QiWeiServiceImpl extends ServiceImpl<EkpQiweiChuchaiMapper, EkpQiwiChuchai> implements QiWeiService {

	private RestTemplate restTemplate = new RestTemplate();

	private static final String VALUESTR = "value";
	private static final String NEW_NEXT_CURSOR = "new_next_cursor";
	private static final String NEW_CURSOR = "new_cursor";
	private static final String TIME_PATTEN = "yyyy-MM-dd HH:mm:ss";
	private static final String START_TIME = " 00:00:00";
	private static final String END_TIME = " 23:59:59";
	private final WxConfig wxConfig;

	private final EkpQiweiZhaopinService ekpQiwiZhaoPinService;

	private final EkpQiweiWorkovertimeService ekpQiweiWorkovertimeService;

	/**
	 * @Description: 获取企业微信审批里的【招聘平台采购/调配】
	 * @Author: hgw
	 * @Date: 2024-8-22 11:19:52
	 **/
	@Override
	public synchronized R<List<EkpQiwiZhaoPin>> getQiWeiZhaoPinAndSave(String startTime, String endTime) {
		try {
			// 起止时间
			DateTimeFormatter df = DateTimeFormatter.ofPattern(TIME_PATTEN);
			LocalDateTime startDate = LocalDateTime.parse(startTime + START_TIME, df);
			LocalDateTime endDate = LocalDateTime.parse(endTime + END_TIME, df);
			Duration duration = Duration.between(startDate, endDate);
			long days = duration.toDays(); //相差的天数
			// 判断时间跨度：
			if (days > 30) {
				return R.failed("时间范围超过30天了：起：" + startTime + "；止：" + endTime);
			}
			// 获取起月份的起止时间
			SimpleDateFormat sdf = new SimpleDateFormat(TIME_PATTEN);
			Date startTimeDate = sdf.parse(startTime + START_TIME);
			Date endTimeDate = sdf.parse(endTime + END_TIME);
			Calendar rightNow = Calendar.getInstance();
			rightNow.setTime(startTimeDate);
			startTime = String.valueOf(rightNow.getTime().getTime() / 1000);
			rightNow.setTime(endTimeDate);
			endTime = String.valueOf(rightNow.getTime().getTime() / 1000);

			// 已被拉取的Map
			Map<String, String> cpMap = ekpQiwiZhaoPinService.getZhaoPinAllMap();
			// 企微姓名Map
			Map<String, String> userMap = this.getUserMap();
			// 一个月的全量编码数据
			List<EkpQiwiChuchai> cpAllList = new ArrayList<>();
			List<EkpQiwiZhaoPin> returnCpList = new ArrayList<>();

			String qwType = "zhaoPin";
			this.getCostPaymentListByMonth(startTime, endTime, cpAllList, qwType);
			log.debug("1拉取企业微信招聘数据cpAllList.size()=" + cpAllList.size());
			if (!cpAllList.isEmpty()) {
				EkpQiwiZhaoPin zhaoPin;
				for (EkpQiwiChuchai cp : cpAllList) {
					if (cpMap.get(cp.getFdSpNo()) == null) {
						zhaoPin = new EkpQiwiZhaoPin();
						zhaoPin.setFdSpNo(cp.getFdSpNo());
						zhaoPin.setFdStatus("未关联");
						returnCpList.add(zhaoPin);
					}
				}
			}
			log.debug("1拉取企业微信招聘数据returnCpList.size()=" + returnCpList.size());
			// 填充详情
			if (!returnCpList.isEmpty()) {
				log.debug("拉取企业微信招聘数据：" + returnCpList.size() + " 条，开始循环拉取明细！");
				this.getTStatisticsProjectReimburseDetailByZhaoPin(returnCpList, userMap);
				log.debug("拉取企业微信招聘数据结束");
			}
			// 填充基础数据并保存：
			if (!returnCpList.isEmpty()) {
				ekpQiwiZhaoPinService.saveBatch(returnCpList);
			}
			cpMap.clear();
			userMap.clear();
			return new R<>(returnCpList);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("拉取企业微信招聘失败：", e);
			return R.failed("时间转化失败，请选择合适的时间，例如：2021-07-29，且范围不超过30天。" + e.getMessage());
		}
	}

	/**
	 * @param startTime
	 * @param endTime
	 * @param type      1：企业微信；2：HCM的E人事
	 * @Description: 获取所有的出差
	 * @Author: hgw
	 * @Date: 2021/3/24 15:41
	 * @return: com.yifu.cloud.v1.common.core.util.R<java.util.List < com.yifu.cloud.v1.hrms.api.entity.TStatisticsProjectReimburse>>
	 **/
	@Override
	public synchronized R<List<EkpQiwiChuchai>> getQiWeiChuChaiAndSave(String startTime, String endTime, int type) {
		try {
			// 起止时间
			DateTimeFormatter df = DateTimeFormatter.ofPattern(TIME_PATTEN);
			LocalDateTime startDate = LocalDateTime.parse(startTime + START_TIME, df);
			LocalDateTime endDate = LocalDateTime.parse(endTime + END_TIME, df);
			Duration duration = Duration.between(startDate, endDate);
			long days = duration.toDays(); //相差的天数
			// 判断时间跨度：
			if (days > 30) {
				return R.failed("时间范围超过30天了：起：" + startTime + "；止：" + endTime);
			}
			String startTimes = startTime + START_TIME;
			String endTimes = endTime + END_TIME;
			// 获取起月份的起止时间
			SimpleDateFormat sdf = new SimpleDateFormat(TIME_PATTEN);
			Date startTimeDate = sdf.parse(startTime + START_TIME);
			Date endTimeDate = sdf.parse(endTime + END_TIME);
			Calendar rightNow = Calendar.getInstance();
			rightNow.setTime(startTimeDate);
			startTime = String.valueOf(rightNow.getTime().getTime() / 1000);
			rightNow.setTime(endTimeDate);
			endTime = String.valueOf(rightNow.getTime().getTime() / 1000);

			// 已被拉取的Map
			Map<String, String> cpMap = new HashMap<>();
			// 企微姓名Map
			Map<String, String> userMap = new HashMap<>();
			// 一个月的全量数据
			List<EkpQiwiChuchai> cpAllList = new ArrayList<>();
			List<EkpQiwiChuchai> returnCpList = new ArrayList<>();

			// 1.9.6计划改造：只查找：已被拉取的90天内的数据Map
			String queryStartDay = DateUtil.addDay(-90);
			String queryStartTimes = queryStartDay + " 00:00:00";

			// type 1：企业微信；2：HCM的E人事
			if (type == 1) {
				// 已被拉取的Map
				// 1.9.6计划改造：只查找：已被拉取的90天内的数据Map（定时任务最多拉取30天内的，手动执行是当天的。所以比对90天内的查重足够了。查全部数据对IO是浪费的）
				cpMap = this.getAllMap(queryStartTimes,endTimes);
				// 企微姓名Map
				userMap = this.getUserMap();
				String qwType = "chuChai";
				this.getCostPaymentListByMonth(startTime, endTime, cpAllList, qwType);
				log.debug("1拉取企业微信出差数据cpAllList.size()=" + cpAllList.size());
				if (!cpAllList.isEmpty()) {
					for (EkpQiwiChuchai cp : cpAllList) {
						if (cpMap.get(cp.getFdSpNo()) == null) {
							returnCpList.add(cp);
						}
					}
				}
				log.debug("1拉取企业微信出差数据returnCpList.size()=" + returnCpList.size());
				// 填充详情
				if (!returnCpList.isEmpty()) {
					log.debug("拉取企业微信出差数据：" + returnCpList.size() + " 条，开始循环拉取明细！");
					this.getTStatisticsProjectReimburseDetail(returnCpList, userMap);
					log.debug("拉取企业微信出差数据结束");
				}
			} else {
				// type 2：HCM的E人事
				// 已被拉取的Map
				// 1.9.6计划改造：只查找：已被拉取的90天内的数据Map（定时任务最多拉取30天内的，手动执行是当天的。所以比对90天内的查重足够了。查全部数据对IO是浪费的）
				cpMap = this.getAllMap(queryStartTimes,endTimes);
				this.getChuChaiListByHcm(startTimes, endTimes, cpAllList);
				log.debug("2拉取HCM的E人事出差数据cpAllList.size()=" + cpAllList.size());
				if (!cpAllList.isEmpty()) {
					for (EkpQiwiChuchai cp : cpAllList) {
						if (cpMap.get(cp.getFdSpNo()) == null) {
							returnCpList.add(cp);
						}
					}
				}
				log.debug("2拉取HCM的E人事出差数据returnCpList.size()=" + returnCpList.size());
			}
			// 填充基础数据并保存：
			if (!returnCpList.isEmpty()) {
				this.saveBatch(returnCpList);
			}
			cpMap.clear();
			userMap.clear();
			return new R<>(returnCpList);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("拉取企业微信出差失败：", e);
			return R.failed("时间转化失败，请选择合适的时间，例如：2021-07-29，且范围不超过30天。" + e.getMessage());
		}
	}

	/**
	 * @param startTime
	 * @param endTime
	 * @param cpAllList
	 * @Description: 获取当月的list
	 * @Author: hgw
	 * @Date: 2021/3/24 17:50
	 * @return: void
	 **/
	private void getCostPaymentListByMonth(String startTime, String endTime, List<EkpQiwiChuchai> cpAllList, String qwType) {
		// 当月的全量数据
		R<List<EkpQiwiChuchai>> listR = this.getTStatisticsProjectReimburseListByWx(startTime, endTime, qwType);
		if (listR.getCode() == CommonConstants.SUCCESS) {
			cpAllList.addAll(listR.getData());
		}
	}

	/**
	 * @Description: 从微信-获取所有的支出项
	 * @Author: hgw
	 * @Date: 2021/3/18 14:58
	 * @return: java.util.List<com.yifu.cloud.v1.hrms.api.entity.TStatisticsProjectReimburse>
	 **/
	private R<List<EkpQiwiChuchai>> getTStatisticsProjectReimburseListByWx(String startTime, String endTime, String qwType) {
		String accessToken = wxConfig.getReimbursementToken(restTemplate);
		log.debug("1拉取企业微信出差数据accessToken=" + accessToken);
		JSONObject json = new JSONObject();
		List<Map<String, String>> paramList = new ArrayList<>();
		Map<String, String> paramMap = new HashMap<>();

		if (Common.isEmpty(qwType) || "chuChai".equals(qwType)) {
			// record_type - 审批单类型属性，1-请假；2-打卡补卡；3-出差；4-外出；5-加班； 6- 调班；7-会议室预定；8-退款审批；9-红包报销审批
			paramMap.put("key", "record_type");
			paramMap.put("value", "3");
		} else if ("zhaoPin".equals(qwType)) {
			paramMap.put("key", "template_id");
			// 模板id，从功能的编辑的url里找
			// https://work.weixin.qq.com/wework_admin/frame#approval_v2/app/264/3WLuP5gXZf3UFAJJa3WSouuP56UFJsQGgCWdo3zs
			paramMap.put("value", "3WLuP5gXZf3UFAJJa3WSouuP56UFJsQGgCWdo3zs");
		}

		paramList.add(paramMap);
		paramMap = new HashMap<>();
		// sp_status-审批单状态（1-审批中；2-已通过；3-已驳回；4-已撤销；6-通过后撤销；7-已删除；10-已支付
		paramMap.put("key", "sp_status");
		paramMap.put("value", "2");
		paramList.add(paramMap);
		json.put("starttime", startTime);
		json.put("endtime", endTime);
		json.put("filters", paramList);
		HttpHeaders headers = new HttpHeaders();
		MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
		headers.setContentType(type);
		headers.add("Accept", MediaType.APPLICATION_JSON.toString());
		HttpEntity<String> formEntity = new HttpEntity<>(json.toString(), headers);
		String dataResultList = restTemplate.postForEntity(SecurityConstants.WX_GET_APPROVAL_LIST, formEntity, String.class, accessToken).getBody();
		log.debug("1拉取企业微信出差数据dataResultList=" + dataResultList);
		if (Common.isEmpty(dataResultList)) {
			throw new AuthenticationServiceException("获取企业微信审批数据失败");
		}
		JSONObject jsonObject = JSON.parseObject(dataResultList);
		String errcode = jsonObject.getString("errcode");
		String errmsg = jsonObject.getString("errmsg");
		if (!"0".equals(errcode)) {
			return R.failed(errmsg);
		}

		// 时间段内的总审批单个数
		String nextCode = jsonObject.getString(NEW_NEXT_CURSOR);
		List<EkpQiwiChuchai> cpList = new ArrayList<>();
		this.setTStatisticsProjectReimburseInfo(jsonObject, cpList);

		// 如果一次没取全，循环取
		while (Common.isNotNull(nextCode)) {
			json.put(NEW_CURSOR, nextCode);
			formEntity = new HttpEntity<>(json.toString(), headers);
			dataResultList = restTemplate.postForEntity(SecurityConstants.WX_GET_APPROVAL_LIST, formEntity, String.class, accessToken).getBody();
			if (Common.isEmpty(dataResultList)) {
				throw new AuthenticationServiceException("获取企业微信审批数据失败");
			}
			jsonObject = JSON.parseObject(dataResultList);
			this.setTStatisticsProjectReimburseInfo(jsonObject, cpList);
			nextCode = jsonObject.getString(NEW_NEXT_CURSOR);
		}
		return new R<>(cpList);
	}

	/**
	 * @Description: 从HCM-获取所有的出差信息
	 * @Author: hgw
	 * @Date: 2024-4-28 17:02:01
	 * @return: java.util.List<com.yifu.cloud.v1.hrms.api.entity.TStatisticsProjectReimburse>
	 **/
	private R<String> getChuChaiListByHcm(String startTime, String endTime, List<EkpQiwiChuchai> cpList) {
		//测试环境：
		// String appId = "627673F79C6BAB92"
		//String appSecret = "EA2641EF627673F79C6BAB9280137F00"
		//线上环境：
		// String appId = "627673F79C6BAB92"
		//String appSecret = "EA2641EF627673F79C6BAB9280137F00"
		// HCM的签名 0501be43d7249b4b82a916be67ee88b08f721b02dd590812deec0ba03361afda

		String sign = wxConfig.getHcmSign();
		if (Common.isEmpty(sign)) {
			return R.failed("获取HCM的sign失败！");
		}

		String appUrl = wxConfig.getHcmAppUrl();
		if (Common.isEmpty(appUrl)) {
			return R.failed("获取HCM的appUrl失败！");
		}
		log.debug("1拉取HCM出差数据sign=" + sign);
		HttpHeaders headers = new HttpHeaders();
		MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
		headers.setContentType(type);
		headers.add("Accept", MediaType.APPLICATION_JSON.toString());
		headers.add("sign", sign);
		HttpEntity<String> formEntity = new HttpEntity<>(headers);
		// 线上地址 appUrl = "http://119.96.166.49:28950/api/v1/instance/business/list?startTime={startTime}&endTime={endTime}"
		// 测试地址 appUrl = "https://qas-hcm.yfzxtech.com:28950/api/v1/instance/business/list?startTime={startTime}&endTime={endTime}"
		String dataResultList = restTemplate.postForEntity(appUrl, formEntity, String.class, startTime, endTime).getBody();
		log.debug("1拉取HCM出差数据dataResultList=" + dataResultList);
		if (Common.isEmpty(dataResultList)) {
			throw new AuthenticationServiceException("获取HCM出差数据失败");
		}
		JSONObject jsonObject = JSON.parseObject(dataResultList);
		String code = jsonObject.getString("code");
		String msg = jsonObject.getString("msg");
		if (!"200".equals(code)) {
			return R.failed(msg);
		}
		// 时间段内的总审批单个数
		EkpQiwiChuchai reimburse;
		String data = jsonObject.getString("data");
		if (Common.isNotNull(data)) {
			List<JSONObject> dataList = JSON.parseArray(data, JSONObject.class);
			String formatterTime = LocalDateTimeUtils.DATE_TIME_PATTERN;
			JSONObject formData;
			String person;
			int renShu;
			int renShu1;
			int renShu2;
			String tools;
			String dataSource = "HCM";
			DateTimeFormatter df = DateTimeFormatter.ofPattern(TIME_PATTEN);
			List<JSONObject> toolList;
			Map<String, String> toolMap = new HashMap<>();
			toolMap.put("1", "飞机");
			toolMap.put("2", "自驾");
			toolMap.put("3", "汽车");
			toolMap.put("4", "高铁火车");
			for (JSONObject datas : dataList) {
				person = null;
				renShu = 1;
				tools = null;
				reimburse = new EkpQiwiChuchai();
				reimburse.setFdDataSource(dataSource);
				if (Common.isNotNull(datas.getString("applyTimeFormat"))) {
					reimburse.setFdApplyDate(LocalDateTime.parse(datas.getString("applyTimeFormat"), df));
				}
				reimburse.setFdApplyUserName(datas.getString("applyName"));
				reimburse.setFdSpNo(datas.getString("flowId"));
				// cyx-mvp1.7.0: 关联状态默认为"未关联"
				reimburse.setFdStatus("未关联");
				reimburse.setCreateTime(LocalDateTime.now());
				reimburse.setFdApplyUserDept(datas.getString("applyDeptName"));
				if (Common.isNotNull(datas.getString("startTimeFormat"))) {
					reimburse.setFdNewBegin(LocalDateUtil.parseLocalDate(datas.getString("startTimeFormat")));
				}
				if (Common.isNotNull(datas.getString("endTimeFormat"))) {
					reimburse.setFdNewEnd(LocalDateUtil.parseLocalDate(datas.getString("endTimeFormat")));
				}
				reimburse.setFdReason(datas.getString("initiationReason"));

				if (Common.isNotNull(datas.getString("formData"))) {
					formData = JSON.parseObject(datas.getString("formData"));

					try {
						int i = 0;
						try {
							toolList = JSON.parseArray(formData.getString("随行人员"), JSONObject.class);
							if (toolList != null && !toolList.isEmpty()) {
								for (JSONObject tool : toolList) {
									if (i++ == 0) {
										person = tool.getString("name");
									} else {
										person += "," + tool.getString("name");
									}
									renShu++;
								}
							}
						} catch (Exception e) {
							person = formData.getString("随行人员");
							renShu = 1;
							if (Common.isNotNull(person)) {
								renShu1 = person.split(",").length;
								renShu2 = person.split("，").length;
								if (renShu1 > renShu2) {
									renShu += renShu1;
								} else {
									renShu += renShu2;
								}
							}
						}
						i = 0;
						try {
							toolList = JSON.parseArray(formData.getString("出行工具"), JSONObject.class);
							if (toolList != null && !toolList.isEmpty()) {
								for (JSONObject tool : toolList) {
									if (i++ == 0) {
										tools = tool.getString("label");
									} else {
										tools += ";" + tool.getString("label");
									}
								}
							}
						} catch (Exception e) {
							tools = formData.getString("出行工具");
							String[] toolArr = tools.split(",");
							i = 0;
							for (String tool : toolArr) {
								if (toolMap.get(tool) != null) {
									if (i++ == 0) {
										tools = toolMap.get(tool);
									} else {
										tools += ";" + toolMap.get(tool);
									}
								}
							}
						}
					} catch (Exception e) {
						person = "-";
						renShu = 1;
						tools = null;
					}
					reimburse.setFdRenShu(renShu);
					reimburse.setFdPerson(person);
					reimburse.setFdAddress(formData.getString("出差地点"));
					reimburse.setFdOldAddress(formData.getString("出发地点"));
					reimburse.setFdTools(tools);
					reimburse.setFdAddressLevel(formData.getString("出差地点级别"));
					reimburse.setFdJiaoTong(formData.getString("交通补助"));
					reimburse.setFdCanYin(formData.getString("餐饮补助"));
					// cyx-mvp1.7.0 新增字段：岗位级别、业务条线归属、代为发起随行人员出差流程
					reimburse.setFdPositionLevel(formData.getString("岗位级别"));
					reimburse.setFdBusinessLine(formData.getString("业务条线归属"));
					// 代为发起随行人员出差流程，标识含义：1：是；2：否
					if(CommonConstants.ONE_STRING.equals(formData.getString("代为发起随行人员出差流程"))){
						reimburse.setFdPersonTravelProcess("是");
					}
					if(CommonConstants.TWO_STRING.equals(formData.getString("代为发起随行人员出差流程"))){
						reimburse.setFdPersonTravelProcess("否");
					}

				}
				cpList.add(reimburse);
			}
		}
		return R.ok();
	}

	/**
	 * @Description: 从企业微信-获取详情
	 * @Author: hgw
	 * @Date: 2024-4-12 16:55:00
	 * @return: java.util.List<com.yifu.cloud.v1.hrms.api.entity.TStatisticsProjectReimburse>
	 **/
	private R<List<EkpQiwiZhaoPin>> getTStatisticsProjectReimburseDetailByZhaoPin(List<EkpQiwiZhaoPin> list, Map<String, String> userMap) {
		String accessToken = wxConfig.getReimbursementToken(restTemplate);
		int i = 1;
		JSONObject jsonDetail;
		HttpHeaders headers = new HttpHeaders();
		MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
		headers.setContentType(type);
		headers.add("Accept", MediaType.APPLICATION_JSON.toString());
		HttpEntity<String> formEntityDetail;
		String dataResultDetail;
		JSONObject jsonObject;
		String errcode;
		String errmsg;
		String info;
		for (EkpQiwiZhaoPin r : list) {
			log.debug("企业微信招聘【" + i + "/" + "" + list.size() + "】条");
			jsonDetail = new JSONObject();
			jsonDetail.put("sp_no", r.getFdSpNo());
			formEntityDetail = new HttpEntity<>(jsonDetail.toString(), headers);
			dataResultDetail = restTemplate.postForEntity(SecurityConstants.WX_GET_APPROVAL_DETAIL, formEntityDetail, String.class, accessToken).getBody();
			if (Common.isEmpty(dataResultDetail)) {
				throw new AuthenticationServiceException("获取企业微信招聘审批详情失败！");
			}
			jsonObject = JSON.parseObject(dataResultDetail);
			errcode = jsonObject.getString("errcode");
			errmsg = jsonObject.getString("errmsg");
			if (!"0".equals(errcode)) {
				return R.failed(errmsg);
			}
			// 详细信息
			info = jsonObject.getString("info");
			this.setTStatisticsProjectReimburseDetailByZhaoPin(info, r, userMap);
			if (i++ >= 600) {
				// 企业微信频率限制：接口频率限制 600次/分钟
				try {
					Thread.sleep(60000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		return new R<>(list);
	}

	/**
	 * @Description: 从企业微信-获取详情
	 * @Author: hgw
	 * @Date: 2024-4-12 16:55:00
	 * @return: java.util.List<com.yifu.cloud.v1.hrms.api.entity.TStatisticsProjectReimburse>
	 **/
	private R<List<EkpQiwiChuchai>> getTStatisticsProjectReimburseDetail(List<EkpQiwiChuchai> list, Map<String, String> userMap) {
		String accessToken = wxConfig.getReimbursementToken(restTemplate);
		int i = 1;
		JSONObject jsonDetail;
		HttpHeaders headers = new HttpHeaders();
		MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
		headers.setContentType(type);
		headers.add("Accept", MediaType.APPLICATION_JSON.toString());
		HttpEntity<String> formEntityDetail;
		String dataResultDetail;
		JSONObject jsonObject;
		String errcode;
		String errmsg;
		String info;
		for (EkpQiwiChuchai r : list) {
			log.info("企业微信出差【" + i + "/" + "" + list.size() + "】条");
			jsonDetail = new JSONObject();
			jsonDetail.put("sp_no", r.getFdSpNo());
			formEntityDetail = new HttpEntity<>(jsonDetail.toString(), headers);
			dataResultDetail = restTemplate.postForEntity(SecurityConstants.WX_GET_APPROVAL_DETAIL, formEntityDetail, String.class, accessToken).getBody();
			if (Common.isEmpty(dataResultDetail)) {
				throw new AuthenticationServiceException("获取企业微信审批详情失败！");
			}
			jsonObject = JSON.parseObject(dataResultDetail);
			errcode = jsonObject.getString("errcode");
			errmsg = jsonObject.getString("errmsg");
			if (!"0".equals(errcode)) {
				return R.failed(errmsg);
			}
			// 详细信息
			info = jsonObject.getString("info");
			this.setTStatisticsProjectReimburseDetail(info, r, userMap);
			if (i++ >= 600) {
				// 企业微信频率限制：接口频率限制 600次/分钟
				try {
					Thread.sleep(60000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
		return new R<>(list);
	}

	/**
	 * @Description: 获取全部的列表，用来： 拉取企业微信时，不覆盖数据
	 * 1.9.6版本优化：只查找：已被拉取的90天内的数据Map（定时任务最多拉取30天内的，手动执行是当天的。所以比对90天内的查重足够了。查全部数据对IO是浪费的）
	 * 用来： 拉取企E人事出差数据时，不覆盖数据
	 * @Author: hgw
	 * @Date: 2021-7-28 18:14:59
	 * @return: java.util.Map<java.lang.String, java.lang.String>
	 **/
	private Map<String, String> getAllMap(String queryStartTime,String queryEndTime) {
		List<EkpQiwiChuchai> cpHistoryList = baseMapper.getAllInfo(null,queryStartTime,queryEndTime);
		Map<String, String> cpMap = new HashMap<>();
		for (EkpQiwiChuchai cpHis : cpHistoryList) {
			cpMap.put(cpHis.getFdSpNo(), "0");
		}
		return cpMap;
	}

	private Map<String, String> getUserMap() {
		List<QiWeiUserVo> userList = baseMapper.getQiYeWeiXinUserList();
		Map<String, String> userMap = new HashMap<>();
		for (QiWeiUserVo cpHis : userList) {
			userMap.put(cpHis.getUserId(), cpHis.getUserName());
		}
		return userMap;
	}

	/**
	 * @param jsonObject
	 * @param cpList
	 * @Description: 向支出list里塞值
	 * @Author: hgw
	 * @Date: 2021/3/18 14:58
	 * @return: void
	 **/
	private void setTStatisticsProjectReimburseInfo(JSONObject jsonObject, List<EkpQiwiChuchai> cpList) {
		EkpQiwiChuchai cp;
		String data = jsonObject.getString("sp_no_list");
		if (Common.isNotNull(data)) {
			List<String> dataList = JSON.parseArray(data, String.class);
			for (String datas : dataList) {
				cp = new EkpQiwiChuchai();
				cp.setFdApplyDate(LocalDateTime.now());
				cp.setFdApplyUserName("张三");
				cp.setFdSpNo(datas);
				cp.setFdStatus(CommonConstants.ZERO_STRING);
				cpList.add(cp);
			}
		}
	}

	/**
	 * @param reimburse
	 * @Description: 向详情里塞值
	 * @Author: hgw
	 * @Date: 2024-4-12 17:01:35
	 * @return: void
	 **/
	private void setTStatisticsProjectReimburseDetail(String info, EkpQiwiChuchai reimburse, Map<String, String> userMap) {
		JSONObject jsonObject = JSON.parseObject(info);
		if (Common.isNotNull(info)) {
			reimburse.setFdDataSource("企微");
			reimburse.setCreateTime(LocalDateTime.now());
			String userId = ((JSONObject) jsonObject.get("applyer")).getString("userid");
			if (Common.isNotNull(userId) && userMap.get(userId) != null) {
				reimburse.setFdApplyUserName(userMap.get(userId));
			} else {
				reimburse.setFdApplyUserName(userId);
			}
			reimburse.setFdApplyUserDept(((JSONObject) jsonObject.get("applyer")).getString("partyid"));
			reimburse.setFdSpNo(jsonObject.getString("sp_no"));
			reimburse.setFdApplyDate(LocalDateTime.ofInstant(Instant.ofEpochSecond(Long.parseLong(String.valueOf(jsonObject.get("apply_time")))), ZoneId.systemDefault()));
			// 核心数据
			JSONObject applyData = (JSONObject) jsonObject.get("apply_data");
			String contents = applyData.getString("contents");
			List<HashMap> contentList = JSON.parseArray(contents, HashMap.class);
			JSONArray title;
			JSONObject value;
			JSONObject attendance;
			JSONObject dateRange;
			JSONObject selector;
			JSONArray options;
			JSONObject options0;
			JSONArray options0value;
			JSONObject options0value0;
			// 开始时间
			LocalDate newBegin = null;
			// 结束时间
			LocalDate newEnd = null;
			// 出差时长
			//String newDuration;
			// 出差地点级别
			String addressLevel = null;
			// 交通补助
			String jiaoTong = null;
			// 餐饮补助
			String canYin = null;
			// 业务条线归属
			//String lineType;
			// 出差事由
			String reason = null;
			// 随行人员
			String person = null;
			// 出差地点
			String address = null;
			// 出发地点
			String oldAddress = null;
			// 出行工具
			String tools = "";
			for (HashMap content : contentList) {
				title = (JSONArray) content.get("title");
				if ("出差".equals(((JSONObject) title.get(0)).get("text"))) {
					value = (JSONObject) content.get(VALUESTR);
					attendance = (JSONObject) value.get("attendance");
					dateRange = (JSONObject) attendance.get("date_range");
					// 28801 是时区+8小时1秒
					newBegin = LocalDate.ofEpochDay((Long.parseLong(dateRange.getString("new_begin")) + 28801) / 86400);
					newEnd = LocalDate.ofEpochDay((Long.parseLong(dateRange.getString("new_end")) + 28801) / 86400);
					//newEnd = LocalDateTime.ofInstant(Instant.ofEpochSecond(Long.valueOf(dateRange.getString("new_end"))), ZoneId.systemDefault());
					//newDuration = dateRange.getString("new_duration");
				}
				/*else if ("岗位级别".equals(((JSONObject)title.get(0)).get("text"))) {
					value = (JSONObject) content.get(VALUESTR);
					selector = (JSONObject) value.get("selector");
					options = (JSONArray) selector.get("options");
					post = ((JSONObject) ((JSONArray) ((JSONArray) ((JSONObject) options.get(0)).get(VALUESTR)).get(0)).get(0)).getString("text");
				} else if ("业务条线归属".equals(((JSONObject)title.get(0)).get("text"))) {
					value = (JSONObject) content.get(VALUESTR);
					selector = (JSONObject) value.get("selector");
					options = (JSONArray) selector.get("options");
					lineType = ((JSONObject) ((JSONArray) ((JSONArray) ((JSONObject) options.get(0)).get(VALUESTR)).get(0)).get(0)).getString("text");
				}*/
				else if ("出差事由".equals(((JSONObject) title.get(0)).get("text"))) {
					value = (JSONObject) content.get(VALUESTR);
					if (Common.isNotNull(value)) {
						reason = value.getString("text");
					}
				} else if ("随行人员".equals(((JSONObject) title.get(0)).get("text"))) {
					value = (JSONObject) content.get(VALUESTR);
					if (Common.isNotNull(value)) {
						person = value.getString("text");
					}
				} else if ("出差地点".equals(((JSONObject) title.get(0)).get("text"))) {
					value = (JSONObject) content.get(VALUESTR);
					if (Common.isNotNull(value)) {
						address = value.getString("text");
					}
				} else if ("出发地点".equals(((JSONObject) title.get(0)).get("text"))) {
					value = (JSONObject) content.get(VALUESTR);
					if (Common.isNotNull(value)) {
						oldAddress = value.getString("text");
					}
				} else if ("出差地点级别".equals(((JSONObject) title.get(0)).get("text"))) {
					value = (JSONObject) content.get(VALUESTR);
					if (Common.isNotNull(value)) {
						selector = (JSONObject) value.get("selector");
						if (Common.isNotNull(selector)) {
							options = (JSONArray) selector.get("options");
							if (Common.isNotNull(options)) {
								options0 = (JSONObject) options.get(0);
								if (Common.isNotNull(options0)) {
									options0value = (JSONArray) options0.get(VALUESTR);
									if (Common.isNotNull(options0value)) {
										options0value0 = (JSONObject) options0value.get(0);
										if (Common.isNotNull(options0value0)) {
											addressLevel = options0value0.getString("text");
										}
									}
								}
							}
						}
					}
				} else if (((JSONObject) title.get(0)).getString("text").contains("交通补助")) {
					value = (JSONObject) content.get(VALUESTR);
					if (value != null && Common.isNotNull(value.getString("text"))) {
						jiaoTong = value.getString("text");
					}
				} else if (((JSONObject) title.get(0)).getString("text").contains("餐饮补助")) {
					value = (JSONObject) content.get(VALUESTR);
					if (value != null && Common.isNotNull(value.getString("text"))) {
						canYin = value.getString("text");
					}
				} else if ("出行工具".equals(((JSONObject) title.get(0)).get("text"))) {
					value = (JSONObject) content.get(VALUESTR);
					if (Common.isNotNull(value)) {
						selector = (JSONObject) value.get("selector");
						if (Common.isNotNull(selector)) {
							options = (JSONArray) selector.get("options");
							if (Common.isNotNull(options)) {
								for (int j = 0; j < options.size(); j++) {
									options0 = (JSONObject) options.get(j);
									options0value = (JSONArray) options0.get(VALUESTR);
									options0value0 = (JSONObject) options0value.get(0);
									tools += options0value0.getString("text") + ";";
								}
							}
						}
					}
				}
			}
			reimburse.setFdNewBegin(newBegin);
			reimburse.setFdNewEnd(newEnd);
			reimburse.setFdReason(reason);
			int renShu = 1;
			if (Common.isNotNull(person)) {
				int renShu1 = person.split(",").length;
				int renShu2 = person.split("，").length;
				if (renShu1 > renShu2) {
					renShu += renShu1;
				} else {
					renShu += renShu2;
				}
			}
			reimburse.setFdRenShu(renShu);
			reimburse.setFdPerson(person);
			reimburse.setFdAddress(address);
			reimburse.setFdOldAddress(oldAddress);
			reimburse.setFdTools(tools);
			reimburse.setFdAddressLevel(addressLevel);
			reimburse.setFdJiaoTong(jiaoTong);
			reimburse.setFdCanYin(canYin);
		}
	}


	/**
	 * @param reimburse
	 * @Description: 向详情里塞值
	 * @Author: hgw
	 * @Date: 2024-4-12 17:01:35
	 * @return: void
	 **/
	private void setTStatisticsProjectReimburseDetailByZhaoPin(String info, EkpQiwiZhaoPin reimburse, Map<String, String> userMap) {
		JSONObject jsonObject = JSON.parseObject(info);
		if (Common.isNotNull(info)) {
			reimburse.setFdDataSource("企微");
			reimburse.setCreateDataTime(LocalDateTime.now());
			// 为了EKP范围查询而存的申请时间
			reimburse.setCreateTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(Long.parseLong(String.valueOf(jsonObject.get("apply_time")))), ZoneId.systemDefault()));
			String userId = ((JSONObject) jsonObject.get("applyer")).getString("userid");
			if (Common.isNotNull(userId) && userMap.get(userId) != null) {
				reimburse.setFdApplyUserName(userMap.get(userId));
			} else {
				reimburse.setFdApplyUserName(userId);
			}
			reimburse.setFdApplyUserDept(((JSONObject) jsonObject.get("applyer")).getString("partyid"));
			reimburse.setFdSpNo(jsonObject.getString("sp_no"));
			reimburse.setFdApplyDate(LocalDateTime.ofInstant(Instant.ofEpochSecond(Long.parseLong(String.valueOf(jsonObject.get("apply_time")))), ZoneId.systemDefault()));
			// 核心数据
			JSONObject applyData = (JSONObject) jsonObject.get("apply_data");
			String contents = applyData.getString("contents");
			List<HashMap> contentList = JSON.parseArray(contents, HashMap.class);
			JSONArray title;
			String titleStr;
			JSONObject value;
			JSONObject attendance;
			// 开始时间
			LocalDate newBegin = null;
			// 结束时间
			LocalDate newEnd = null;
			// 申请子 (分) 公司或部门名称
			String fdUserDeptName = null;
			// "购买方式"
			String fdBuyStyle = null;
			// "平台名称"
			String fdPingTaiName = null;
			// "平台产品名称"
			String fdPingTaiChanPin = null;
			// "数量"
			String fdNum = null;
			// "单价"
			String fdMoney = null;
			// "总计金额"
			String fdMoneySum = null;
			// "使用项目名称"
			String fdDeptName = null;
			// "使用岗位名称"
			String fdPostName = null;
			// "成本归属"
			String fdCostName = null;
			// 招聘运营部填写
			// "购买/调配方式是否合理")
			String fdTwoIsHeLi = null;
			// "平台名称"
			String fdTwoPingTaiName = null;
			// "产品名称"
			String fdTwoPingTaiChanPin = null;
			// "数量"
			String fdTwoNum = null;
			// "金额"
			String fdTwoMoneySum = null;
			// "被调配的业务单元名称"
			String fdTwoYeWu = null;
			// "备注"
			String fdTwoRemark = null;

			String keyText = "text";
			String keyMoney = "new_money";
			String keyNumber = "new_number";
			String valueStr;
			for (HashMap content : contentList) {
				try {
					title = (JSONArray) content.get("title");
					titleStr = String.valueOf(((JSONObject) title.get(0)).get("text"));
					value = (JSONObject) content.get(VALUESTR);
					if (Common.isNotNull(value)) {
						valueStr = value.getString(keyText);
						switch (titleStr) {
							case "申请子 (分) 公司或部门名称":
								fdUserDeptName = this.getDeptName(value);
								break;
							case "购买方式":
								fdBuyStyle = this.getSelectValue(value);
								break;
							case "开始时间":
								attendance = (JSONObject) value.get("date");
								newBegin = LocalDate.ofEpochDay((Long.parseLong(attendance.getString("s_timestamp")) + 28801) / 86400);
								break;
							case "结束时间":
								attendance = (JSONObject) value.get("date");
								newEnd = LocalDate.ofEpochDay((Long.parseLong(attendance.getString("s_timestamp")) + 28801) / 86400);
								break;
							case "平台名称":
								fdPingTaiName = valueStr;
								break;
							case "平台产品名称":
								fdPingTaiChanPin = valueStr;
								break;
							case "数量":
								fdNum = value.getString(keyNumber);
								break;
							case "单价":
								fdMoney = value.getString(keyMoney);
								break;
							case "总计金额":
								fdMoneySum = value.getString(keyMoney);
								break;
							case "使用项目名称":
								fdDeptName = valueStr;
								break;
							case "使用岗位名称":
								fdPostName = valueStr;
								break;
							case "成本归属":
								fdCostName = this.getDeptName(value);
								break;
							case "招聘运营部填写":
								JSONArray childrenArray = (JSONArray) value.get("children");
								if (Common.isNotNull(childrenArray) && !childrenArray.isEmpty()) {
									List<HashMap> childrenList = JSON.parseArray(((JSONObject) childrenArray.get(0)).getString("list"), HashMap.class);
									for (HashMap childrenContent : childrenList) {
										title = (JSONArray) childrenContent.get("title");
										titleStr = String.valueOf(((JSONObject) title.get(0)).get("text"));
										value = (JSONObject) childrenContent.get(VALUESTR);
										if (Common.isNotNull(value)) {
											valueStr = value.getString(keyText);
											switch (titleStr) {
												case "购买/调配方式是否合理":
													fdTwoIsHeLi = this.getSelectValue(value);
													if (Common.isEmpty(fdTwoIsHeLi)) {
														fdTwoIsHeLi = "无";
													}
													break;
												case "平台名称":
													fdTwoPingTaiName = valueStr;
													break;
												case "产品名称":
													fdTwoPingTaiChanPin = valueStr;
													break;
												case "数量":
													fdTwoNum = value.getString(keyText);
													break;
												case "金额":
													fdTwoMoneySum = value.getString(keyMoney);
													break;
												case "被调配的业务单元名称":
													fdTwoYeWu = valueStr;
													break;
												case "备注":
													fdTwoRemark = valueStr;
													break;
												default:
													break;
											}
										}
									}
								}
								break;
							default:
								break;
						}
					}
				} catch (Exception e) {
					log.error("获取企微招聘平台信息出错：" + e.getMessage());
				}
			}
			reimburse.setFdNewBegin(newBegin);
			reimburse.setFdNewEnd(newEnd);
			reimburse.setFdUserDeptName(fdUserDeptName);
			reimburse.setFdBuyStyle(fdBuyStyle);
			reimburse.setFdPingTaiName(fdPingTaiName);
			reimburse.setFdPingTaiChanPin(fdPingTaiChanPin);
			reimburse.setFdNum(fdNum);
			reimburse.setFdMoney(fdMoney);
			reimburse.setFdMoneySum(fdMoneySum);
			reimburse.setFdDeptName(fdDeptName);
			reimburse.setFdPostName(fdPostName);
			reimburse.setFdCostName(fdCostName);
			reimburse.setFdTwoIsHeLi(fdTwoIsHeLi);
			reimburse.setFdTwoPingTaiName(fdTwoPingTaiName);
			reimburse.setFdTwoPingTaiChanPin(fdTwoPingTaiChanPin);
			reimburse.setFdTwoNum(fdTwoNum);
			reimburse.setFdTwoMoneySum(fdTwoMoneySum);
			reimburse.setFdTwoYeWu(fdTwoYeWu);
			reimburse.setFdTwoRemark(fdTwoRemark);
		}
	}

	/**
	 * @Description: 获取选择框的值
	 * @Author: hgw
	 * @Date: 2024/8/27 14:57
	 * @return: java.lang.String
	 **/
	private String getSelectValue(JSONObject value) {
		JSONObject options0value0;
		JSONArray options;
		JSONObject options0;
		JSONArray options0value;
		JSONObject selector;
		if (Common.isNotNull(value)) {
			selector = (JSONObject) value.get("selector");
			if (Common.isNotNull(selector)) {
				options = (JSONArray) selector.get("options");
				if (Common.isNotNull(options)) {
					options0 = (JSONObject) options.get(0);
					if (Common.isNotNull(options0)) {
						options0value = (JSONArray) options0.get(VALUESTR);
						if (Common.isNotNull(options0value)) {
							options0value0 = (JSONObject) options0value.get(0);
							if (Common.isNotNull(options0value0)) {
								return options0value0.getString("text");
							}
						}
					}
				}
			}
		}
		return null;
	}

	/**
	 * @Description: 获取部门名称
	 * @Author: hgw
	 * @Date: 2024/8/27 14:54
	 * @return: java.lang.String
	 **/
	private String getDeptName(JSONObject value) {
		JSONObject options0;
		JSONArray options;
		if (Common.isNotNull(value)) {
			options = (JSONArray) value.get("departments");
			StringBuilder deptName = new StringBuilder();
			if (Common.isNotNull(options)) {
				for (int i = 0; i < options.size(); i++) {
					options0 = (JSONObject) options.get(i);
					if (Common.isNotNull(options0)) {
						if (i > 0) {
							deptName.append("；");
						}
						deptName.append(options0.getString("name"));
					}
				}
				if (Common.isNotNull(deptName)) {
					if (deptName.length() > 200) {
						return deptName.substring(0, 200);
					} else {
						return deptName.toString();
					}
				}
			}
		}
		return null;
	}


	/**
	 * 获取HCM审批通过的加班数据并存储到EKP
	 * @param startDay 开始日期
	 * @param endDay 结束日期
	 * @author chenyuxi
	 * @since  1.9.6
	 * @date   2025-02-06
	 * @return R<List<EkpQiwiChuchai>>
	 **/
	@Override
	public synchronized R<List<EkpQiwiWorkovertime>> getHcmWorkOvertimeAndSave(String startDay, String endDay) {
		try {
			String startTime = startDay + START_TIME;
			String endTime = endDay + END_TIME;

			// 可存储的数据
			List<EkpQiwiWorkovertime> saveCpList = ekpQiweiWorkovertimeService.saveWorkovertimeList(startTime, endTime);

			return new R<>(saveCpList);
		} catch (Exception e) {
			e.printStackTrace();
			log.error("拉取HCM审批通过的加班数据失败：", e);
			return R.failed("拉取失败" + e.getMessage());
		}
	}


}
