package cn.com.ctop.oa.modules.service.impl;

import cn.com.ctop.common.module.utils.Check;
import cn.com.ctop.common.module.utils.HttpUtils;
import cn.com.ctop.oa.modules.constant.QYWxConstant;
import cn.com.ctop.oa.modules.entity.WechatAttendance;
import cn.com.ctop.oa.modules.entity.WechatCheckinData;
import cn.com.ctop.oa.modules.entity.WechatNoList;
import cn.com.ctop.oa.modules.enums.SpNoEnum;
import cn.com.ctop.oa.modules.mapper.WechatCheckinDataMapper;
import cn.com.ctop.oa.modules.mapper.WechatNoListMapper;
import cn.com.ctop.oa.modules.service.IWechatNoListService;
import cn.com.ctop.oa.modules.service.IWechatTokenService;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xxl.job.core.enums.NoEn;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.common.util.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.jeecg.common.constant.GeneralConstant.*;

/**
 * 审批信息
 *
 * @author jeecg-boot
 * @version V1.0
 * @date 2020-09-23
 */
@Service
@Slf4j
public class WechatNoListServiceImpl extends ServiceImpl<WechatNoListMapper, WechatNoList> implements IWechatNoListService {
    @Autowired
    private IWechatTokenService tokenService;
    @Autowired
    private WechatNoListMapper wechatNoListMapper;
    @Autowired
    private WechatCheckinDataMapper wechatCheckinDataMapper;

    /**
     * 获取审批token
     *
     * @return java.lang.String
     * @throws
     * @author ZHAOXA
     * @Param []
     */
    private String getToken(String dataType) throws Exception {
        Map<String, Object> approvaAccessToken = tokenService.getApprovaAccessToken();
        if (NoEn.NO1.valueStr().equals(dataType)) {
            approvaAccessToken = tokenService.getYRApprovaToken();
        }
        if ((Integer) approvaAccessToken.get("code") != 0) {
            log.error("企业微信获取token失败,返回信息：{}", approvaAccessToken.get("message"));
            throw new Exception("企业微信获取token失败");
        }
        return approvaAccessToken.get("accessToken").toString();
    }

    @Override
    public void getNoDateByNo(String starttime, String endtime, String dataType) {
        Map<String, Object> returnMap = new HashMap<>();
        try {
            long start = DateUtils.timeToStamp(starttime);
            long end = DateUtils.timeToStamp(endtime);
            String token = getToken(dataType);
            Integer page = 0;
            JSONArray noList = getAllNoList(page, new JSONArray(), start, end, token);
            boolean sleep = false;
            if (noList.size() > 600) {
                sleep = true;
            }
            if (!Check.isNull(noList)) {
                StringBuffer buf = new StringBuffer();
                //获取审批申请详情 URL;
                buf.append(QYWxConstant.APP_ROVAL_DETAIL).append("?access_token=").append(token);
                String userId = null;
                Map<String, String> parameterMap = null;
                for (Object spNo : noList) {
                    parameterMap = new HashMap<>();
                    //接口频率限制 600次/分钟
                    if (sleep) {
                        Thread.sleep(105);
                    }
                    JSONObject params = new JSONObject();
                    params.put("sp_no", spNo);
                    String resultStr = HttpUtils.httpPostRequestTest(buf.toString(), params.toJSONString(), null);
                    JSONObject resultJson = JSONObject.parseObject(resultStr);
                    Integer errcode = resultJson.getInteger("errcode");
                    if (errcode == 0) {
                        JSONObject info = resultJson.getJSONObject("info");
                        String spStatus = info.getString("sp_status");
                        String spName = info.getString("sp_name");
                        /**申请单状态：1-审批中；2-已通过，只记录这两种状态数据
                         * 而且只记录请假、打卡补卡类型
                         **/
                        boolean statusisOK = "2".equals(spStatus) || "1".equals(spStatus);
                        boolean typeisOK = spName.contains("打卡补卡") || spName.contains("请假") || spName.contains("外出") || spName.contains("出差");
                        if (statusisOK && typeisOK) {
                            JSONObject applyer = info.getJSONObject("applyer");
                            if (!Check.isNull(applyer)) {
                                userId = applyer.getString("userid");
                            }
                            //审批申请数据
                            JSONObject applyData = info.getJSONObject("apply_data");
                            //获取审批状态数据
                            getParameterMap(applyData, parameterMap);
                            WechatNoList noEntity = new WechatNoList();
                            noEntity.setUserId(userId);
                            noEntity.setSpNo(spNo.toString());
                            noEntity.setStatus(spStatus);
                            if (!Check.isNull(parameterMap.get("newBegin"))) {
                                noEntity.setNewBegin(DateUtils.stampToTime(Long.valueOf(parameterMap.get("newBegin"))));
                            }
                            if (!Check.isNull(parameterMap.get("newEnd"))) {
                                noEntity.setNewEnd(DateUtils.stampToTime(Long.valueOf(parameterMap.get("newEnd"))));
                            }
                            noEntity.setType(parameterMap.get(TYPE));
                            noEntity.setNewDuration(parameterMap.get("newDuration"));
                            if (NoEn.NO1.valueStr().equals(dataType)) {
                                noEntity.setDataType(NoEn.NO1.valueInt());
                            }
                            wechatNoListMapper.insert(noEntity);
                        }
                    }
                }
            }
        } catch (Exception e) {
            returnMap.put("code", -1);
            returnMap.put("message", "系统错误");
            log.error("审批异常", e);
        }
    }

    //递归获取审批数据
    private JSONArray getAllNoList(Integer page, JSONArray spNoList, Long starttime, Long endtime, String token) {
        JSONObject data = getNoList(page, starttime, endtime, token);
        spNoList.addAll(data.getJSONArray("sp_no_list"));
        Integer nextCursor = data.getInteger("next_cursor");
        if (!Check.isNull(nextCursor)) {
            return getAllNoList(nextCursor, spNoList, starttime, endtime, token);
        }
        return spNoList;
    }

    /**
     * 批量获取审批单号，单号！
     *
     * @param page      查询起始数，分页查询游标，默认为0
     * @param starttime 审批单提交的时间范围，开始时间，UNix时间戳
     * @param endtime   批单提交的时间范围，结束时间，Unix时间戳
     * @return com.alibaba.fastjson.JSONObject
     * @throws
     * @author ZHAOXA
     */
    private JSONObject getNoList(Integer page, Long starttime, Long endtime, String token) {
        try {
            JSONObject params = new JSONObject();
            params.put("starttime", starttime);
            params.put("endtime", endtime);
            params.put("cursor", page);
            params.put("size", 100);
            StringBuffer buf = new StringBuffer();
            //批量获取审批单号 URL
            buf.append(QYWxConstant.APP_ROVAL_INFO).append("?access_token=").append(token);
            String resultStr = HttpUtils.httpPostRequestTest(buf.toString(), params.toJSONString(), null);
            JSONObject resultJson = JSONObject.parseObject(resultStr);
            Integer errcode = resultJson.getInteger("errcode");
            if (errcode == 0) {
                return resultJson;
            } else {
                throw new Exception("批量获取审批单号");
            }
        } catch (Exception e) {
            log.error("批量获取审批单号异常", e);
        }
        return new JSONObject();
    }

    /**
     * 获取审批状态数据
     *
     * @return void
     * @throws
     * @author ZHAOXA
     * @Param [applyData, parameterMap]
     */
    private void getParameterMap(JSONObject applyData, Map<String, String> parameterMap) {
        String control = null;
        if (!Check.isNull(applyData)) {
            //审批申请详情，由多个表单控件及其内容组成
            JSONArray contents = applyData.getJSONArray("contents");
            if (!Check.isNull(contents)) {
                for (int i = 0; i < contents.size(); i++) {
                    //获取content 对象数据
                    JSONObject contentEntity = contents.getJSONObject(i);
                    if (!Check.isNull(contentEntity)) {
                        control = contentEntity.getString("control");
                        //如果补卡组件为PunchCorrection，直接判断为补卡
                        if (SpNoEnum.control3.getCode().equals(control)) {
                            JSONObject value = contentEntity.getJSONObject(VALUE);
                            if (!Check.isNull(value)) {
                                JSONObject punch = value.getJSONObject("punch_correction");
                                if (!Check.isNull(punch)) {
                                    parameterMap.put(TYPE, SpNoEnum.type2.getName());
                                    parameterMap.put("newBegin", punch.getString("time"));
                                    parameterMap.put("newEnd", punch.getString("time"));
                                }
                            }
                            //假勤组件-请假组件 Vacation
                        } else if (SpNoEnum.control2.getCode().equals(control)) {
                            JSONObject value = contentEntity.getJSONObject(VALUE);
                            if (!Check.isNull(value)) {
                                JSONObject vacation = value.getJSONObject("vacation");
                                if (!Check.isNull(vacation)) {
                                    JSONObject selector = vacation.getJSONObject("selector");
                                    if (!Check.isNull(selector)) {
                                        getVacation(selector, parameterMap);
                                    }
                                    JSONObject attendance = vacation.getJSONObject("attendance");
                                    if (!Check.isNull(attendance)) {
                                        getTimeData(attendance, parameterMap);
                                    }
                                }
                            }
                            //假勤组件-出差/外出/加班组件Attendance
                        } else if (SpNoEnum.control1.getCode().equals(control)) {
                            JSONObject value = contentEntity.getJSONObject(VALUE);
                            if (!Check.isNull(value)) {
                                JSONObject attendance = value.getJSONObject("attendance");
                                if (!Check.isNull(attendance)) {
                                    getTimeData(attendance, parameterMap);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 获取组件中的假勤类型，假勤开始、结束时间以及时长。
     *
     * @return void
     * @throws
     * @author ZHAOXA
     * @Param [attendance, parameterMap]
     */
    private void getTimeData(JSONObject attendance, Map<String, String> parameterMap) {
        String type = attendance.getString(TYPE);
        //假勤类型，排除类型为1的请假，因为有具体的请假类型，例如：年假，事假等具体类型
        if (!NoEn.NO1.valueStr().equals(type)) {
            parameterMap.put(TYPE, SpNoEnum.getSpNoEnum(type).getName());
        }
        JSONObject dateRange = attendance.getJSONObject("date_range");
        if (!Check.isNull(dateRange)) {
            parameterMap.put("newBegin", dateRange.getString("new_begin"));
            parameterMap.put("newEnd", dateRange.getString("new_end"));
            BigDecimal duration = dateRange.getBigDecimal("new_duration");
            if (!Check.isNull(duration)) {
                //除以3600，取小时数
                BigDecimal second = new BigDecimal(3600);
                parameterMap.put("newDuration", String.valueOf(duration.divide(second, 1, 4)));
            }
        }
    }

    /**
     * 获取假期类型
     *
     * @param
     * @return void
     * @throws
     * @author ZHAOXA
     */
    private void getVacation(JSONObject selector, Map<String, String> parameterMap) {
        JSONArray options = selector.getJSONArray("options");
        if (!Check.isNull(options)) {
            for (int j = 0; j < options.size(); j++) {
                JSONObject option = options.getJSONObject(j);
                JSONArray values = option.getJSONArray(VALUE);
                if (!Check.isNull(values)) {
                    for (int k = 0; k < values.size(); k++) {
                        JSONObject val = values.getJSONObject(k);
                        parameterMap.put(TYPE, val.getString("text"));
                    }
                }
            }
        }
    }

    @Override
    public List<WechatAttendance> queryAttendanceData(Map<String, Object> paramsMap) {
        finishingTime(paramsMap);
        List<WechatAttendance> list = wechatNoListMapper.queryAttendanceData(paramsMap);
        if (!Check.isNull(list)) {
            checkOverTimeData(list);
        }
        return list;
    }

    @Override
    public List<WechatAttendance> queryYRAttendanceData(Map<String, Object> paramsMap) {
        finishingTime(paramsMap);
        List<WechatAttendance> list = wechatNoListMapper.queryYRAttendanceData(paramsMap);
        if (!Check.isNull(list)) {
            checkOverTimeData(list);
        }
        return list;
    }

    /**
     * 整理时间
     *
     * @param
     * @return void
     * @throws
     * @author ZHAOXA
     */
    private void finishingTime(Map<String, Object> paramsMap) {
        String startTime = (String) paramsMap.get(START_TIME);
        if (!Check.isNull(startTime)) {
            startTime += DAY_BEGIN;
            paramsMap.put(START_TIME, startTime);
        }
        String stopTime = (String) paramsMap.get(STOP_TIME);
        if (!Check.isNull(stopTime)) {
            stopTime += DAY_END;
            paramsMap.put(STOP_TIME, stopTime);
        }
    }

    @Override
    public List<WechatAttendance> queryOverTimeData(Map<String, Object> paramsMap) {
        finishingTime(paramsMap);
        return wechatNoListMapper.queryOverTimeData(paramsMap);
    }

    @Override
    public List<WechatAttendance> queryYROverTimeData(Map<String, Object> paramsMap) {
        finishingTime(paramsMap);
        return wechatNoListMapper.queryYROverTimeData(paramsMap);
    }

    @Override
    public PageInfo<WechatAttendance> selectNoListPage(Map<String, Object> paramsMap) {
        finishingTime(paramsMap);
        Integer pageNo = (Integer) paramsMap.get(PAGE_NO);
        if (null == pageNo || pageNo == 0) {
            pageNo = NoEn.NO1.valueInt();
        }
        Integer pageSize = (Integer) paramsMap.get(PAGE_SIZE);
        if (null == pageSize || pageSize == 0) {
            pageSize = NoEn.NO10.valueInt();
        }
        PageHelper.startPage(pageNo, pageSize);
        List<WechatAttendance> list = wechatNoListMapper.queryAttendanceData(paramsMap);
        if (!Check.isNull(list)) {
            checkOverTimeData(list);
        }
        return new PageInfo<>(list);
    }

    /**
     * 筛选10:30以后打卡的迟到数据，判断前一天是否加班，更新迟到时长
     *
     * @param
     * @return void
     * @throws
     * @author ZHAOXA
     */
    private void checkOverTimeData(List<WechatAttendance> list) {
        for (WechatAttendance attendance : list) {
            if ("迟到".equals(attendance.getType())) {
                Integer dur = Integer.valueOf(attendance.getStateDuration().replace(" min", ""));
                if (dur - 60 >= 0) {
                    String checkinDate = attendance.getCheckinDate();
                    String lastDay = DateUtils.getLastDay(checkinDate, NoEn.NO1.valueInt());
                    Map<String, Object> map = new HashMap<>();
                    map.put("userId", attendance.getUserId());
                    map.put("checkinDate", lastDay);
                    map.put("checkinType", "下班打卡");
                    WechatCheckinData data = wechatCheckinDataMapper.queryEntityByMap(map);
                    if (!Check.isNull(data) && 1 == data.getOvertimeOrNot()) {
                        attendance.setStateDuration((dur - 60) + " min");
                    }
                }
            }
        }
    }

    @Override
    public PageInfo<WechatAttendance> selectOverTimePage(Map<String, Object> paramsMap) {
        finishingTime(paramsMap);
        Integer pageNo = (Integer) paramsMap.get("pageNo");
        if (null == pageNo || pageNo == 0) {
            pageNo = 1;
        }
        Integer pageSize = (Integer) paramsMap.get("pageSize");
        if (null == pageSize || pageSize == 0) {
            pageSize = 10;
        }
        PageHelper.startPage(pageNo, pageSize);
        List<WechatAttendance> list = wechatNoListMapper.queryOverTimeData(paramsMap);
        return new PageInfo<>(list);
    }
}
