package com.bonus.system.holiday.service;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.fastjson2.JSONObject;
import com.bonus.common.core.utils.FastJsonHelper;
import com.bonus.common.core.utils.ImportExcelUtils;
import com.bonus.common.core.utils.UploadCheckUtils;
import com.bonus.common.core.web.domain.AjaxResult;
import com.bonus.common.security.utils.SecurityUtils;
import com.bonus.common.security.utils.ValidatorsUtils;
import com.bonus.system.api.domain.MapVo;
import com.bonus.system.api.domain.SysUser;
import com.bonus.system.att.entity.Holiday;
import com.bonus.system.basic.domain.SysNotice;
import com.bonus.system.basic.service.SysNoticeService;
import com.bonus.system.dept.dao.ProDeptRoleDao;
import com.bonus.system.holiday.dao.HolidayDao;
import com.bonus.system.holiday.entity.HolidayBean;
import com.bonus.system.holiday.entity.HolidayImportBean;
import com.bonus.system.holiday.entity.HolidayKeyBean;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.multipart.MultipartFile;
import springfox.documentation.spring.web.json.Json;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 项目部角色-业务层
 *
 * @author fly
 */
@Service("HolidayService")
@Slf4j
public class HolidayServiceImpl implements HolidayService {

    @Resource(name = "HolidayDao")
    private HolidayDao holidayDao;

    /**
     * 消息推送库表
     */
    @Resource
    private SysNoticeService noticeService;

    @Override
    public List<HolidayBean> getHolidayList(HolidayBean bean) {
        //只能查自己部门的人
        return holidayDao.getHolidayList(bean);
    }

    @Override
    public List<HolidayBean> getHolidayListCheck(HolidayBean bean) {
        return holidayDao.getHolidayList(bean);
    }

    @Override
    public int insertHoliday(HolidayBean o) {
        Long userId = SecurityUtils.getLoginUser().getSysUser().getUserId();
        o.setCreateUserId(userId);
        o.setSource("1");
        o.setExamineStatus("0");
        o.setType(o.getLeaveType());
        int i = holidayDao.insertHoliday(o);
        if (i > 0) {
            //获取部门负责人
            List<Long> userList = noticeService.getUserIdByOrgId(o.getOrgId());
            // 将 List 转换为数组
            if(!userList.isEmpty()){
                if (userList.size() > 1) { // 检查是否有多个元素
                    // 如果有多个元素，检查并移除值为1的元素
                    while (userList.contains(userId)) {
                        userList.remove(Long.valueOf(userId));
                    }
                }
                Long[] userIds = userList.toArray(new Long[0]);
                //发送审批消息
                SysNotice bean = new SysNotice();
                bean.setUserIds(userIds);
                bean.setUserId(userId);
                /*if("轮休".equals(o.getLeaveType())){
                    bean.setTitle("轮休申请");
                    bean.setContent("轮休申请");
                    bean.setType("65");
                }else{
                    bean.setTitle("临时外出申请");
                    bean.setContent("临时外出申请");
                    bean.setType("66");
                }*/
                if("轮休".equals(o.getLeaveType())){
                    bean.setTitle("轮休审批提醒");
                    bean.setContent("轮休审批提醒");
                    bean.setType("67");
                }else{
                    bean.setTitle("临时外出审批提醒");
                    bean.setContent("临时外出审批提醒");
                    bean.setType("68");
                }

                bean.setValue("");
                bean.setLeaveApplyId(o.getId());
                //推送消息
                noticeService.insertNotice(bean);
            }
        }
        return i;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult batchCheckStatus(HolidayBean o) {
        try {
            if(CollectionUtils.isEmpty(o.getIds())){
                return AjaxResult.error("未选择审批数据");
            }
            if(StringUtils.isEmpty(o.getExamineStatus())){
                return AjaxResult.error("未选择审批状态");
            }
            Long updateUserId = SecurityUtils.getLoginUser().getSysUser().getUserId();
            o.setUpdateUserId(updateUserId);
            o.setExamineUserId(updateUserId);
            SysUser sysUser = SecurityUtils.getLoginUser().getSysUser();
            String userName =sysUser.getUserName();
            // 当前登录人存在多个组织机构时，只取第一个组织机构的名称
            String orgName = CollectionUtils.isEmpty(sysUser.getOrgList()) ? "" : sysUser.getOrgList().get(0).getName();
            String now = DateUtil.now();
            if(Objects.equals(o.getExamineStatus(),"1")){
                o.setExamineOpinion("同意 " + orgName + " "+userName+" "+ now);
            }else if(Objects.equals(o.getExamineStatus(),"2")){
                o.setExamineOpinion("不同意 " + orgName + " "+userName+" "+ now);
            }
            o.setExamineTime(DateUtil.date());
            holidayDao.batchCheckStatus(o);
        } catch (Exception e) {
            log.error(e.toString(),e);
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return AjaxResult.error();
        }
        return AjaxResult.success();
    }

    @Override
    public HolidayBean selectHolidayById(Long id) {
        return holidayDao.selectHolidayById(id);
    }

    @Override
    public int updateHoliday(HolidayBean o) {
        o.setUpdateUserId(SecurityUtils.getLoginUser().getSysUser().getUserId());
        o.setExamineStatus("0");
        int i = holidayDao.updateHoliday(o);
        Long userId = SecurityUtils.getLoginUser().getSysUser().getUserId();
        if (i > 0) {
            //获取部门负责人
            List<Long> userList = noticeService.getUserIdByOrgId(o.getOrgId());
            // 将 List 转换为数组
            if(!userList.isEmpty()){
                if (userList.size() > 1) { // 检查是否有多个元素
                    // 如果有多个元素，检查并移除值为1的元素
                    while (userList.contains(userId)) {
                        userList.remove(Long.valueOf(userId));
                    }
                }
                Long[] userIds = userList.toArray(new Long[0]);
                //发送审批消息
                SysNotice bean = new SysNotice();
                bean.setUserIds(userIds);
                bean.setUserId(userId);
                if("轮休".equals(o.getLeaveType())){
                    bean.setTitle("轮休审批提醒");
                    bean.setContent("轮休审批提醒");
                    bean.setType("67");
                }else{
                    bean.setTitle("临时外出审批提醒");
                    bean.setContent("临时外出审批提醒");
                    bean.setType("68");
                }
                bean.setValue("");
                bean.setLeaveApplyId(o.getId());
                //先删除之前的推送消息
                noticeService.delNotice(bean);
                //推送消息
                noticeService.insertNotice(bean);
            }
        }
        return i;
    }

    @Override
    public int deleteHolidayById(Long id) {
        int i = holidayDao.deleteHolidayById(id);
        if(i>0){
            SysNotice bean = new SysNotice();
            bean.setLeaveApplyId(id);
            //先删除之前的推送消息
            noticeService.delNotice(bean);
        }
        return i ;
    }

    /**
     * 修改请假状态
     *
     * @param o
     * @return
     */
    @Override
    public int changeStatus(HolidayBean o) {
        Long updateUserId = SecurityUtils.getLoginUser().getSysUser().getUserId();
        o.setUpdateUserId(updateUserId);
        int i = 0;
        if (StringUtils.isNotEmpty(o.getExamineStatus())) {
            // 1,2 是审核人审核 0,3 是自己修改
            String examineStatus = "1,2";
            String ownStatus = "0,3";
            if (examineStatus.contains(o.getExamineStatus())) {
                o.setExamineUserId(updateUserId);
                SysUser sysUser = SecurityUtils.getLoginUser().getSysUser();
                String userName =sysUser.getUserName();
                String orgName = sysUser.getOrgName();
                if("1".equals(o.getExamineStatus())){
                    o.setExamineOpinion("同意 " + o.getOrgName() + " "+userName+" "+ DateUtil.now());
                }else{
                    o.setExamineOpinion("不同意 " + o.getOrgName() + " "+userName+" "+ DateUtil.now());
                }
                o.setExamineTime(DateUtil.date());
            } else if (ownStatus.contains(o.getExamineStatus())) {
                o.setUpdateUserId(updateUserId);
            }
             i = holidayDao.changeHolidayStatus(o);
             if (i > 0 && Objects.equals("0", o.getExamineStatus())) {
                //获取提交请假的人
                List<Long> userList =holidayDao.getUserIdById(o.getId());
                // 将 List 转换为数组
                if(!userList.isEmpty()){
                      if (userList.size() > 1) { // 检查是否有多个元素
                        // 如果有多个元素，检查并移除值为1的元素
                        while (userList.contains(updateUserId)) {
                            userList.remove(Long.valueOf(updateUserId));
                        }
                    }
                    Long[] userIds = userList.toArray(new Long[0]);
                    //发送审批消息
                    SysNotice bean = new SysNotice();
                    bean.setUserIds(userIds);
                    bean.setUserId(updateUserId);
                    if("轮休".equals(o.getLeaveType())){
                        bean.setTitle("轮休审批提醒");
                        bean.setContent("轮休审批提醒");
                        bean.setType("67");
                    }else{
                        bean.setTitle("临时外出审批提醒");
                        bean.setContent("临时外出审批提醒");
                        bean.setType("68");
                    }
                    bean.setValue("");
                    //推送消息
                    noticeService.insertNotice(bean);
                }
            }
        }

        return i;
    }

    @Resource(name = "ValidatorsUtils")
    private ValidatorsUtils validatorsUtils;
    public AjaxResult excelUpload(MultipartFile file, HttpServletRequest request, HttpServletResponse response) {
        try {
            List<JSONObject> listObj = ImportExcelUtils.readExcel(file, HolidayImportBean.class, "");
            List<HolidayImportBean> list = new ArrayList<>();
            if (CollectionUtils.isEmpty(listObj)) {
                return AjaxResult.error("请勿导入空数据");
            }
            // 获取人员岗位
            for (JSONObject obj : listObj) {
                HolidayImportBean vo = FastJsonHelper.jsonObjToBean(obj, HolidayImportBean.class);
                String validResult = validatorsUtils.valid(vo, HolidayImportBean.Query.class);
                if (org.apache.commons.lang3.StringUtils.isNotBlank(validResult)) {
                    return AjaxResult.error("第" + obj.getString("rowNo") + "行" + validResult);
                }
                list.add(vo);
            }
            //先检验excel数据是否有重叠
            String s = hasOverlappingHolidays(list);
            if (!s.isEmpty()) {
                return AjaxResult.error(s);
            }
            // 校验库中数据的是否存在
            List<HolidayKeyBean> orgList = holidayDao.getOrgList();
            List<HolidayKeyBean> personList = holidayDao.getPersonList();
            List<HolidayKeyBean> leaveTypeList = holidayDao.getLeaveTypeList();
            //查前一个月的请假数据，对比导入的数据，判断是否有重复
            // 获取当前日期的 LocalDate
            LocalDate currentDate = LocalDate.now();
            // 将 LocalDate 转换为 Date
            Date currentDateAsDate = Date.from(currentDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
            // 使用 Hutool 的 DateUtil.offsetMonth 方法
            Date previousMonthDateAsDate = DateUtil.offsetMonth(currentDateAsDate, -2);
            // 如果需要转换回 LocalDate
            LocalDate previousMonthDate = previousMonthDateAsDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
            List<HolidayImportBean> listHoliday = holidayDao.getHolidayData(previousMonthDate);
            Map<String, List<HolidayImportBean>> groupedByUserName = listHoliday.stream()
                    .collect(Collectors.groupingBy(HolidayImportBean::getUserName));
            int i = 0;
            for (HolidayImportBean vo : list) {
                i++;
                if (!codeIsExist(orgList, vo, 1)) {
                    return AjaxResult.error("第" + i + "行部门不存在");
                }
                if (!codeIsExist(personList, vo, 2)) {
                    return AjaxResult.error("第" + i + "行考勤库没有这个人员");
                }
                if (!codeIsExist(leaveTypeList, vo, 3)) {
                    return AjaxResult.error("第" + i + "行请假类型不存在");
                }
                // 检查请假是否有重叠
                String userName = vo.getUserName();
                List<HolidayImportBean> holidays = groupedByUserName.get(userName);
                if (holidays != null) {
                    for (HolidayImportBean other : holidays) {
                        if (vo != other && vo.isOverlapping(other)) {
                            return AjaxResult.error("第" + i + "行请假与历史请假存在重叠");
                        }
                    }
                }
            }

            for (HolidayImportBean vo : list) {
                HolidayBean bean = new HolidayBean();
                bean.setOrgId(vo.getOrgId());
                bean.setUserId(vo.getUserId());
                bean.setOrgName(vo.getOrgName());
                bean.setUserName(vo.getUserName());
                bean.setLeaveDate(vo.getLeaveDate().replaceAll("\"", "" ));
                String leaveStartDate = vo.getLeaveStartDate().replaceAll("\"", "").substring(0,10);
                String leaveEndDate = vo.getLeaveEndDate().replaceAll("\"", "").substring(0,10);
                // 定义日期时间格式
                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
                // 解析字符串
                LocalDate date1 = LocalDate.parse(leaveStartDate, formatter);
                LocalDate date2 = LocalDate.parse(leaveEndDate, formatter);
                bean.setLeaveStartDate(date1);
                bean.setLeaveStartInterval("1");
                bean.setLeaveEndDate(date2);
                bean.setLeaveEndInterval("2");
                bean.setLeaveDuration(Double.parseDouble(vo.getLeaveDuration()));
                bean.setLeaveReason(vo.getLeaveReason());
                bean.setLeaveType(vo.getLeaveType());
                bean.setType("请假");
                bean.setSource("2");
                bean.setExamineStatus("1");
                bean.setCreateUserId(SecurityUtils.getLoginUser().getSysUser().getUserId());
                holidayDao.insertHoliday(bean);
            }
            return AjaxResult.success();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    // 验证是否存在重叠的请假时间
    public String hasOverlappingHolidays(List<HolidayImportBean> list) {
        // 按 userName 分组
        Map<String, List<HolidayImportBean>> groupedByUser = list.stream()
                .collect(Collectors.groupingBy(HolidayImportBean::getUserName));

        // 遍历每个用户的请假记录，检查是否有时间段重叠
        for (Map.Entry<String, List<HolidayImportBean>> entry : groupedByUser.entrySet()) {
            List<HolidayImportBean> holidays = entry.getValue();

            // 检查组内所有的假期记录是否有交集
            for (int i = 0; i < holidays.size(); i++) {
                HolidayImportBean current = holidays.get(i);
                for (int j = i + 1; j < holidays.size(); j++) {
                    HolidayImportBean other = holidays.get(j);
                    if (isOverlapping(current, other)) {
                        return "excel中用户 " + current.getUserName() + " 的请假时间有重叠："
                                + current.getLeaveStartDate() + " - " + current.getLeaveEndDate()
                                + " 和 " + other.getLeaveStartDate() + " - " + other.getLeaveEndDate(); // 存在重叠
                    }
                }
            }
        }
        return ""; // 无重叠
    }

    // 判断两个请假记录是否重叠
    public boolean isOverlapping(HolidayImportBean h1, HolidayImportBean h2) {
        return (h1.getLeaveStartDate().compareTo(h2.getLeaveEndDate()) <= 0) &&
                (h1.getLeaveEndDate().compareTo(h2.getLeaveStartDate()) >= 0);
    }


    /**
     * 判断导入部门、请假类型 是否存在
     * @param list
     * @param value
     * @return boolean
     * @author fly
     * @date 2024/10/15 18:09
     */
    public boolean codeIsExist(List<HolidayKeyBean> list, HolidayImportBean value, int type) {
        if (value == null) {
            throw new IllegalArgumentException("HolidayImportBean cannot be null.");
        }
        if (CollectionUtils.isEmpty(list)) {
            return false;
        }
        for (HolidayKeyBean map : list) {
            String name = map.getName();
            if (isMatch(type, name, value)) {
                Long idStr = map.getId();
                if (handleId(idStr, type, value)) {
                    return true;
                }
            }
        }
        return false;
    }

    // 提取公共方法处理 id 设置
    private boolean handleId(Long id, int type, HolidayImportBean value) {
        if (id == null) {
            return false;
        }
        try {
            switch (type) {
                case 1:
                    value.setOrgId(id);
                    break;
                case 2:
                    value.setUserId(id);
                    break;
                default:
                    // 不需要设置 id
                    break;
            }
            return true;
        } catch (NumberFormatException e) {
            // 记录错误信息
            System.err.println("Failed to parse ID: " + id);
            return false;
        }
    }

    // 判断是否匹配
    private boolean isMatch(int type, String name, HolidayImportBean value) {
        switch (type) {
            case 1:
                return Objects.equals(name, value.getOrgName());
            case 2:
                return Objects.equals(name, value.getUserName());
            default:
                return Objects.equals(name, value.getLeaveType());
        }
    }




}
