package com.xjrsoft.module.teacher.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.xjrsoft.common.enums.LeaveReasonEnum;
import com.xjrsoft.module.hikvision.entity.HikvisionData;
import com.xjrsoft.module.hikvision.mapper.HikvisionDataMapper;
import com.xjrsoft.module.hikvision.util.ApiUtil;
import com.xjrsoft.module.teacher.entity.WfHeadTeacherLeave;
import com.xjrsoft.module.teacher.entity.WfTeacherleave;
import com.xjrsoft.module.teacher.mapper.WfTeacherleaveMapper;
import com.xjrsoft.module.teacher.service.IWfHeadTeacherLeaveService;
import com.xjrsoft.module.teacher.service.IWfTeacherleaveService;
import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @title: 教职工请假流程
 * @Author szs
 * @Date: 2023-12-20
 * @Version 1.0
 */
@Service
@AllArgsConstructor
public class WfTeacherleaveServiceImpl extends MPJBaseServiceImpl<WfTeacherleaveMapper, WfTeacherleave> implements IWfTeacherleaveService {

    private final IWfHeadTeacherLeaveService wfHeadTeacherLeaveService;
    private final HikvisionDataMapper hikvisionDataMapper;
    private final WfTeacherleaveMapper wfTeacherleaveMapper;
    @Override
    public Boolean dataHandle(Long dataId) {
        WfTeacherleave wfTeacherleave = this.getById(dataId);
        //如果请假老师是班主任，将信息同步到班主任事项请假
        if (ObjectUtil.isNotNull(wfTeacherleave) && wfTeacherleave.getIsItAHomeroomTeacher().equals("是")) {
            /*
             * 如果是周一到周四的上午，自动同步请假类型为“早自习、课间操”的数据到班主任事项请假列表，
             * 如果是周五下午自动同步请假类型为“学生放假”的数据到班主任事项请假列表。
             */

            //将请假时间段按照日分割成几段
            Date leaveStartTime = wfTeacherleave.getLeaveStartTime();//请假开始时间
            Date leaveEndTime = wfTeacherleave.getLeaveEndTime();//请假结束时间
            List<DateRange> dateRangeList = splitDateRangeByDay(LocalDateTime.ofInstant(leaveStartTime.toInstant(), ZoneId.systemDefault()), LocalDateTime.ofInstant(leaveEndTime.toInstant(), ZoneId.systemDefault()));
            List<WfHeadTeacherLeave> wfHeadTeacherLeaveList = new ArrayList<>();
            for (DateRange dateRange : dateRangeList) {
                LocalDateTime startTime = dateRange.getBegin();
                LocalDateTime endTime = dateRange.getEnd();
                //获取星期几
                DayOfWeek dayOfWeek = startTime.getDayOfWeek();
                int dayOfWeekValue = dayOfWeek.getValue();

                //LocalDateTime forenoonStartDateTime = LocalDateTime.of(startTime.toLocalDate(), LocalTime.of(9, 50, 0));
                LocalDateTime forenoonEndDateTime = LocalDateTime.of(startTime.toLocalDate(), LocalTime.of(10, 30, 0));
                //LocalDateTime afternoonStartDateTime = LocalDateTime.of(startTime.toLocalDate(), LocalTime.of(14, 0, 0));
                LocalDateTime afternoonEndDateTime = LocalDateTime.of(startTime.toLocalDate(), LocalTime.of(15, 30, 0));
                /*
                 *当天是在星期一到星期四，
                 * 且开始时间早于当天上午区间的结束时间，
                 * 结束时间晚于当天上午区间的结束时间，
                 * 自动同步一条请假类型为“早自习、课间操”的数据到班主任事项请假列表。
                 */
                if (dayOfWeekValue > 0 && dayOfWeekValue < 5
                        && startTime.compareTo(forenoonEndDateTime) < 0
                        && endTime.compareTo(forenoonEndDateTime) > 0) {

                    wfHeadTeacherLeaveList.add(new WfHeadTeacherLeave(){{
                        setWfTeacherleaveId(wfTeacherleave.getId());
                        setApplicantUserId(Long.valueOf(wfTeacherleave.getUserId()));
                        setLeaveReason(LeaveReasonEnum.LeaveReason2.getCode());
                        Instant startTimeInstant = startTime.atZone(ZoneId.systemDefault()).toInstant();
                        Date startTimeDate = Date.from(startTimeInstant);
                        setStartTime(startTimeDate);
                        setTimePeriod(1);
                        setRemark(wfTeacherleave.getReasonForLeave());
                        setStatus(1);
                        if(wfTeacherleave.getLeaveDays() <= 1){
                            setSubstituteUserId(wfTeacherleave.getReliefHomerooTeacherId());
                        }
                        if(wfTeacherleave.getLeaveDays() > 1){
                            setSubstituteUserId(wfTeacherleave.getReliefTeacherId());
                        }
                        setCreateDate(new Date());
                        //setCreateUserId(StpUtil.getLoginIdAsLong());
                        QueryWrapper<WfHeadTeacherLeave> queryWrapperSortcode = new QueryWrapper<>();
                        queryWrapperSortcode.select("IFNULL(MAX(sort_code),0) as sortCode");
                        WfHeadTeacherLeave w = wfHeadTeacherLeaveService.getOne(queryWrapperSortcode);
                        setSortCode(w.getSortCode() + 1);
                    }});
                }
                /*
                 * 当天是在星期五，
                 * 且开始时间早于下午区间的结束时间，
                 * 结束时间晚于下午区间的结束时间，
                 * 自动同步一条请假类型为“学生放假”的数据到班主任事项请假列表。
                 */
                if (dayOfWeekValue == 5
                        && startTime.compareTo(afternoonEndDateTime) < 0
                        && endTime.compareTo(afternoonEndDateTime) > 0) {
                    WfHeadTeacherLeave wfHeadTeacherLeave = new WfHeadTeacherLeave();

                    wfHeadTeacherLeave.setWfTeacherleaveId(wfTeacherleave.getId());
                    wfHeadTeacherLeave.setApplicantUserId(Long.valueOf(wfTeacherleave.getUserId()));
                    wfHeadTeacherLeave.setLeaveReason(LeaveReasonEnum.LeaveReason1.getCode());
                    Instant startTimeInstant = startTime.atZone(ZoneId.systemDefault()).toInstant();
                    Date startTimeDate = Date.from(startTimeInstant);
                    wfHeadTeacherLeave.setStartTime(startTimeDate);
                    wfHeadTeacherLeave.setTimePeriod(2);
                    wfHeadTeacherLeave.setRemark(wfTeacherleave.getReasonForLeave());
                    wfHeadTeacherLeave.setStatus(1);
                    wfHeadTeacherLeave.setCreateDate(new Date());
                    //wfHeadTeacherLeave.setCreateUserId(StpUtil.getLoginIdAsLong());
                    QueryWrapper<WfHeadTeacherLeave> queryWrapperSortcode = new QueryWrapper<>();
                    queryWrapperSortcode.select("IFNULL(MAX(sort_code),0) as sortCode");
                    WfHeadTeacherLeave w = wfHeadTeacherLeaveService.getOne(queryWrapperSortcode);
                    wfHeadTeacherLeave.setSortCode(w.getSortCode() + 1);
                    wfHeadTeacherLeaveList.add(wfHeadTeacherLeave);
                }
            }
            return wfHeadTeacherLeaveService.saveBatch(wfHeadTeacherLeaveList);
        }
        return true;
    }

    @Override
    public Boolean hikvisionLeave(Long id) {
        WfTeacherleave teacherleave = this.getById(id);
        //查询学生在海康的id
        HikvisionData hikvisionData = hikvisionDataMapper.selectOne(
            new QueryWrapper<HikvisionData>().lambda()
            .eq(HikvisionData::getSourceId, teacherleave.getUserId())
            .eq(HikvisionData::getTableName, "base_teacher")
        );
        ApiUtil apiUtil = new ApiUtil();
        String apiPath = "/api/acps/v1/auth_config/add";

        String outputFormat = "yyyy-MM-dd'T'HH:mm:ss+08:00";
        SimpleDateFormat sdf = new SimpleDateFormat(outputFormat);
        JsonObject paramJson = new JsonObject();

        paramJson.addProperty("startTime", sdf.format(teacherleave.getLeaveStartTime()));
        paramJson.addProperty("endTime", sdf.format(teacherleave.getLeaveEndTime()));

        //组装人员数据
        JsonArray personDatas = new JsonArray();
        JsonObject personData = new JsonObject();
        personData.addProperty("personDataType", "person");

        JsonArray indexCodes = new JsonArray();
        indexCodes.add(hikvisionData.getHikvisionId());
        personData.add("indexCodes", indexCodes);

        personDatas.add(personData);
        paramJson.add("personDatas", personDatas);

        JsonArray resourceInfos = selectResource(apiUtil);
        paramJson.add("resourceInfos", resourceInfos);

        Map<String, String> header = new HashMap<>();
        header.put("tagId", "studentleave");
        //调用接口获取到返回内容，并将其存到数据库中
        String result = apiUtil.doPost(apiPath, paramJson.toString(), null, header);
        teacherleave.setHikvisionResult(result);
        this.updateById(teacherleave);

        return true;
    }

    @Override
    public Long getLeaveCount(LocalDateTime startTime, LocalDateTime endTime) {
        return wfTeacherleaveMapper.getLeaveCount(startTime, endTime);
    }

    @Override
    public Map<Long, WfTeacherleave> getLeaveList(LocalDateTime startTime, LocalDateTime endTime) {
        List<WfTeacherleave> leaveList = wfTeacherleaveMapper.getLeaveList(startTime, endTime);
        Map<Long, WfTeacherleave> result = new HashMap<>();
        for (WfTeacherleave teacherleave : leaveList) {
            String[] teacherIds = teacherleave.getUserId().split(",");
            for (String teacherId : teacherIds) {
                result.put(Long.valueOf(teacherId), teacherleave);
            }
        }
        return result;
    }

    JsonArray selectResource(ApiUtil apiUtil){
        String apiPath = "/api/irds/v2/resource/resourcesByParams";
        JsonObject jsonObject = new JsonObject();
        jsonObject.addProperty("pageNo", 1);
        jsonObject.addProperty("pageSize", 500);
        jsonObject.addProperty("resourceType", "door");

        String result = apiUtil.doPost(apiPath, jsonObject.toString(), null, null);
        JsonParser parser = new JsonParser();
        JsonObject resultJson = parser.parse(result).getAsJsonObject();
        JsonArray resourceInfos = new JsonArray();

        if("0".equals(resultJson.get("code").getAsString()) && "success".equals(resultJson.get("msg").getAsString())){
            JsonArray list = resultJson.get("data").getAsJsonObject().get("list").getAsJsonArray();
            for (JsonElement jsonElement : list) {
                JsonObject listOne = jsonElement.getAsJsonObject();
                JsonObject resourceInfo = new JsonObject();
                resourceInfo.add("resourceIndexCode", listOne.get("indexCode"));
                resourceInfo.add("resourceType", listOne.get("resourceType"));
                JsonArray channelNos = new JsonArray();
                channelNos.add(listOne.get("channelNo"));
                resourceInfo.add("channelNos", channelNos);
                resourceInfos.add(resourceInfo);
            }
        }

        return resourceInfos;
    }

    /**
     * 按日分割
     *
     * @param startTime 开始时间
     * @param endTime   结束时间
     * @return 分割后的时间段集合
     */
    private List<DateRange> splitDateRangeByDay(LocalDateTime startTime, LocalDateTime endTime) {
        long seconds = startTime.until(endTime, ChronoUnit.SECONDS);
        if (seconds < 0) {
            return new ArrayList<>();
        }
        //轮数
        long turnNum = 0;
        //分割的时间段集合，使用累加算法
        List<DateRange> dateList = new ArrayList<>();
        DateRange range = new DateRange();
        range.setBegin(startTime);
        while (true) {
            turnNum++;
            startTime = startTime.plusDays(1);
            //大于截止日期时，不再累加
            if (startTime.isAfter(endTime)) {
                range.setEnd(endTime);
                range.setTurnNum(turnNum);
                dateList.add(range);
                break;
            }
            //将时间调整为该天的 0时 0分 0秒
            startTime = LocalDateTime.of(startTime.getYear(), startTime.getMonth(), startTime.getDayOfMonth(), 0, 0, 0);
            LocalDateTime tmpBegin = startTime;
            //计算出上一天的最后一秒
            LocalDateTime endDate = tmpBegin.minusSeconds(1);
            range.setEnd(endDate);
            range.setTurnNum(turnNum);
            dateList.add(range);
            //创建新的时间段
            range = new DateRange();
            range.setBegin(tmpBegin);
        }
        return dateList;
    }

    @Data
    static class DateRange {

        /**
         * 开始时间
         */
        private LocalDateTime begin;

        /**
         * 结束时间
         */
        private LocalDateTime end;

        /**
         * 当前时间的第几轮（段）
         */
        private Long turnNum;
    }
}
