package com.ruoyi.zhushi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.domain.dto.RoleDTO;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.zhushi.entity.*;
import com.ruoyi.zhushi.mapper.DkAttendanceGroupAndUserMapper;
import com.ruoyi.zhushi.mapper.DkAttendanceGroupMapper;
import com.ruoyi.zhushi.mapper.DkRecordMapper;
import com.ruoyi.zhushi.mapper.NjBalanceManageDetailMapper;
import com.ruoyi.zhushi.service.DkRecordService;
import com.ruoyi.zhushi.util.CalendarGenerator;
import com.ruoyi.zhushi.util.Constans;
import com.ruoyi.zhushi.util.TimeUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.util.*;
@SuppressWarnings("all")
@Service
public class DkRecordServiceImpl implements DkRecordService {
    @Autowired
    private DkRecordMapper dkMapper;

    @Autowired
    private NjBalanceManageDetailMapper njBalanceManageDetailMapper;

    @Autowired
    private DkAttendanceGroupAndUserMapper dkAttendanceGroupAndUserMapper;

    @Autowired
    private DkAttendanceGroupMapper dkAttendanceGroupMapper;

    public String getTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date currentDate = new Date();
        return sdf.format(currentDate);
    }

    @Override
    public TableDataInfo<DkCheckInRecordDTO> queryPageList(DkCheckInRecordDTO dkCheckInRecordDTO, PageQuery pageQuery) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        LambdaQueryWrapper<DkCheckInRecord> queryWrapper = buildQueryWrapper(dkCheckInRecordDTO);
        if (dkCheckInRecordDTO.getFlag().equals("my")){
            if (loginUser == null) {
                return TableDataInfo.build();
            }else {
                // 获取用户角色
                List<RoleDTO> roles = loginUser.getRoles();
                if (roles != null && roles.size() > 0) {
                    for (RoleDTO role : roles) {
                        if (role.getRoleKey().equals(Constans.ROLEKEY)) {
                            queryWrapper.eq(DkCheckInRecord::getSysUserId, loginUser.getUserId());
                        }
                    }
                }
            }
        }

        Page<DkCheckInRecordDTO> result = dkMapper.selectVoPage(pageQuery.build(), queryWrapper);
        return TableDataInfo.build(result);
    }

    private LambdaQueryWrapper<DkCheckInRecord> buildQueryWrapper(DkCheckInRecordDTO dkCheckInRecordDTO) {
        LambdaQueryWrapper<DkCheckInRecord> queryWrapper = Wrappers.lambdaQuery();

        queryWrapper.eq(null != dkCheckInRecordDTO.getSysUserId() ,DkCheckInRecord::getSysUserId, dkCheckInRecordDTO.getSysUserId());
        queryWrapper.eq(null != dkCheckInRecordDTO.getSysUserName() ,DkCheckInRecord::getSysUserName, dkCheckInRecordDTO.getSysUserName());
        queryWrapper.eq(null != dkCheckInRecordDTO.getCheckInTime(), DkCheckInRecord::getCheckInTime, dkCheckInRecordDTO.getCheckInTime());
        if (null != dkCheckInRecordDTO.getCheckInStatus()) {
            //未打卡
            if ("0".equals(dkCheckInRecordDTO.getCheckInStatus())) {
                queryWrapper.eq( DkCheckInRecord::getClockInStatus,dkCheckInRecordDTO.getCheckInStatus());
                queryWrapper.eq( DkCheckInRecord::getClockOutStatus,dkCheckInRecordDTO.getCheckInStatus());
            }
            //上班打卡 迟到
            if ("1".equals(dkCheckInRecordDTO.getCheckInStatus())||"3".equals(dkCheckInRecordDTO.getCheckInStatus())) {
                queryWrapper.eq( DkCheckInRecord::getClockInStatus,dkCheckInRecordDTO.getCheckInStatus());
            }
            //下班打卡 早退
            if ("2".equals(dkCheckInRecordDTO.getCheckInStatus())||"4".equals(dkCheckInRecordDTO.getCheckInStatus())) {
                queryWrapper.eq( DkCheckInRecord::getClockOutStatus,dkCheckInRecordDTO.getCheckInStatus());
            }
            //更新打卡
            if ("5".equals(dkCheckInRecordDTO.getCheckInStatus())) {

            }
        }
        //考勤日期 查询
        if(StringUtils.isNotBlank(dkCheckInRecordDTO.getStrDay())){
            queryWrapper.between(DkCheckInRecord::getCheckInTime, TimeUtils.getStartTime(dkCheckInRecordDTO.getStrDay()),
                TimeUtils.getEndTime(dkCheckInRecordDTO.getStrDay()));
        }
        //导出excel 考勤月
        if(StringUtils.isNotBlank(dkCheckInRecordDTO.getStrMonth())){
            queryWrapper.between(DkCheckInRecord::getCheckInTime, TimeUtils.getFirstDayOfMonth(dkCheckInRecordDTO.getStrMonth()),
                TimeUtils.getLastDayOfMonth(dkCheckInRecordDTO.getStrMonth()));
        }
        //考勤组查询
        if (dkCheckInRecordDTO.getAttendanceGroupIds()!=null&&dkCheckInRecordDTO.getAttendanceGroupIds().size()>0) {
            queryWrapper.in(DkCheckInRecord::getAttendanceGroupId,dkCheckInRecordDTO.getAttendanceGroupIds());
        }
        queryWrapper.orderByDesc(DkCheckInRecord::getSysUserName).orderByDesc(DkCheckInRecord::getCheckInTime);

        return queryWrapper;
    }

    /**
     * 导出考勤 excel
     * @param dkCheckInRecordDTO
     * @param response
     */
    @Override
    public void exportNew(DkCheckInRecordDTO dkCheckInRecordDTO, HttpServletResponse response) {
        // 当前日期
        LocalDate now = LocalDate.now();

        // 校验月份
        YearMonth inputMonth = YearMonth.parse(dkCheckInRecordDTO.getStrMonth()); // e.g. "2025-08"
        YearMonth currentMonth = YearMonth.from(now);

        if (inputMonth.isAfter(currentMonth)) {
            return ;
        }
        // 查询出选择的考勤组下面的所有人员
        QueryWrapper<DkAttendanceGroupAndUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.in("attendance_team_id",dkCheckInRecordDTO.getAttendanceGroupIds());
        List<DkAttendanceGroupAndUser> users = dkAttendanceGroupAndUserMapper.selectList(queryWrapper);
        if (users==null||users.size()==0) {
            return;
        }

        try {
            InputStream inputStream = null;
            // 加载模板文件
            if(Constans.GUONEI.equals(dkCheckInRecordDTO.getModelType())){
                ClassPathResource resource = new ClassPathResource("template/template-guonei.xlsx");
                inputStream = resource.getInputStream();
            }
            if(Constans.RIBEN.equals(dkCheckInRecordDTO.getModelType())){
                ClassPathResource resource = new ClassPathResource("template/template-riben.xlsx");
                inputStream = resource.getInputStream();
            }


            //汇总表参数   记录每个用户的 迟到总数和年假总数
            Map<String, Map<String,Integer>> summary = new HashMap<>();

            Workbook workbook = WorkbookFactory.create(inputStream);
            // 遍历所有人员
            for (int i = 0; i <= users.size(); i++){
                int newSheetIndex = workbook.getNumberOfSheets();
                if(i == users.size()){
                    //国内有汇总
                    if (Constans.GUONEI.equals(dkCheckInRecordDTO.getModelType())) {
                        workbook.createSheet("汇总");
                        workbook.setSheetName(newSheetIndex, "汇总");
                        // 获取新创建的Sheet
                        Sheet newSheet = workbook.getSheetAt(newSheetIndex);
                        fillTemplateHuiZong(newSheet, summary);
                    }
                }else{
                    DkAttendanceGroupAndUser user = users.get(i);
                    // 准备数据
                    dkCheckInRecordDTO.setSysUserId(user.getUserId());
                    dkCheckInRecordDTO.setSysUserName(user.getUserName());
                    dkCheckInRecordDTO.setNickName(user.getNickName());

                    workbook.cloneSheet(0);
                    workbook.setSheetName(newSheetIndex, user.getNickName() != null ? user.getNickName() : user.getUserName());

                    // 获取新创建的Sheet
                    Sheet newSheet = workbook.getSheetAt(newSheetIndex);

                    // 国内模版
                    if(Constans.GUONEI.equals(dkCheckInRecordDTO.getModelType())){
                        // 构造导出数据
                        EmployeeAttendance attendanceData = prepareSampleData(dkCheckInRecordDTO);
                        //记录每个人的迟到次数
                        if(attendanceData.getChidaocishu() > 0){
                            if (summary.containsKey(user.getNickName())) {
                                Map map = summary.get(user.getNickName());
                                map.put("lateCount",attendanceData.getChidaocishu());
                            } else {
                                Map map = new HashMap();
                                map.put("lateCount",attendanceData.getChidaocishu());
                                summary.put(user.getNickName(),map);
                            }
                        }

                        //excel内容构建
                        fillTemplate(newSheet, attendanceData,dkCheckInRecordDTO.getStrMonth(),user,summary);
                    }
                    // 日本模版
                    if(Constans.RIBEN.equals(dkCheckInRecordDTO.getModelType())){
                        // 构造导出数据
                        EmployeeAttendance attendanceData = prepareSampleDataRiBen(dkCheckInRecordDTO);
                        fillTemplateRiBen(newSheet, attendanceData,dkCheckInRecordDTO.getStrMonth(),user);
                    }
                }
            }

            workbook.removeSheetAt(0);
            workbook.write(response.getOutputStream());
            workbook.close();
            inputStream.close();
            System.out.println("Excel 导出成功！");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public int updateDkRecord(DkCheckInRecordDTO dkCheckInRecordDTO) {
        AppDTO appDTO = dkAttendanceGroupMapper.queryAttendanceGroupBYUserId(dkCheckInRecordDTO.getSysUserId());












        UpdateWrapper<DkCheckInRecord> updateWrapper =new UpdateWrapper();
        updateWrapper.eq("id",dkCheckInRecordDTO.getId());
        updateWrapper.eq("sys_user_id",dkCheckInRecordDTO.getSysUserId());
        //备注
        updateWrapper.set("description",dkCheckInRecordDTO.getDescription());
        updateWrapper.set("update_time",LocalDateTime.now(ZoneId.of("Asia/Shanghai")));
        updateWrapper.set("update_by",LoginHelper.getUsername());

        //上班时间
        if (dkCheckInRecordDTO.getClockIn()!=null) {
            //规定上班时间
            String workStartTime = appDTO.getWorkStartTime();
            if (isLate(workStartTime,dkCheckInRecordDTO.getClockIn())) {
                updateWrapper.set("clock_in_status","3");
                updateWrapper.set("check_in_status","3");

            } else {
                updateWrapper.set("clock_in_status","1");
                updateWrapper.set("check_in_status","1");

            }

            updateWrapper.set("clock_in",dkCheckInRecordDTO.getClockIn());
            //考勤时间跟随变化
            updateWrapper.set("check_in_time",dkCheckInRecordDTO.getClockIn());

        }
        //下班时间
        if (dkCheckInRecordDTO.getClockOut()!=null) {
            //规定下班时间
            String workEndTime = appDTO.getWorkEndTime();
            if (isEarlyLeave(workEndTime,dkCheckInRecordDTO.getClockOut())) {
                updateWrapper.set("clock_out_status","4");
                updateWrapper.set("check_in_status","4");
            } else {
                updateWrapper.set("clock_out_status","2");
                updateWrapper.set("check_in_status","2");
            }

            updateWrapper.set("clock_out",dkCheckInRecordDTO.getClockOut());
            //考勤时间跟随变化
            updateWrapper.set("check_in_time",dkCheckInRecordDTO.getClockOut());
        }
        return dkMapper.update(null,updateWrapper);
    }
    /**
     * 判断是否迟到
     *
     * @param ruleStartTime 规定上班时间（格式：HH:mm，例如 "08:30"）
     * @param clockIn       实际上班打卡时间
     * @return true = 迟到，false = 正常
     */
    public static boolean isLate(String ruleStartTime, LocalDateTime clockIn) {
        // 解析成 LocalTime
        LocalTime startTime = LocalTime.parse(ruleStartTime);
        // 获取当天规定的上班时间点
        LocalDateTime startDateTime = LocalDateTime.of(clockIn.toLocalDate(), startTime);
        // 如果打卡时间在规定上班时间之后，就迟到
        return clockIn.isAfter(startDateTime);
    }

    /**
     * 判断是否早退
     *
     * @param ruleEndTime 规定下班时间（格式：HH:mm，例如 "17:30"）
     * @param clockOut    实际下班打卡时间
     * @return true = 早退，false = 正常
     */
    public static boolean isEarlyLeave(String ruleEndTime, LocalDateTime clockOut) {
        // 解析成 LocalTime
        LocalTime endTime = LocalTime.parse(ruleEndTime);
        // 获取当天规定的下班时间点
        LocalDateTime endDateTime = LocalDateTime.of(clockOut.toLocalDate(), endTime);
        // 如果打卡时间在规定下班时间之前，就早退
        return clockOut.isBefore(endDateTime);
    }
    /*--------------------------------------------------国内汇总信息 --------------------------*/
    private void fillTemplateHuiZong(Sheet sheet, Map<String, Map<String,Integer>> summary) {

        setCellValue(sheet, 0, 0, "姓名");
        setCellValue(sheet, 0, 1, "年假合计");
        setCellValue(sheet, 0, 2, "迟到合计");
        int i =1;
        for (String key : summary.keySet()) {
            Map<String,Integer> value = summary.get(key);
            setCellValue(sheet, i, 0, key);
            setCellValue(sheet, i, 1, value.get("njCount"));
            setCellValue(sheet, i, 2, value.get("lateCount"));
            i++;
        }

    }

    /*---------------------------------------------------国内 --------------------------*/
    private EmployeeAttendance prepareSampleData(DkCheckInRecordDTO dkCheckInRecordDTO) {

        // 定义员工类对象
        EmployeeAttendance data = new EmployeeAttendance();
        // 设置员工的昵称
        data.setEmployeeName(dkCheckInRecordDTO.getNickName());
        // 设置员工的用户名
        data.setUserName(dkCheckInRecordDTO.getSysUserName());

        // 判断月日是否为空
        if(dkCheckInRecordDTO.getStrMonth() != null){
            data.setDateTime(formatDate(dkCheckInRecordDTO.getStrMonth()));
        }
        if(dkCheckInRecordDTO.getStrDay() != null){
            data.setDateTime(convertToChineseFormat(dkCheckInRecordDTO.getStrDay()));
        }

        //根据userId获取打卡配置信息
        DkAttendanceGroup dkAttendanceGroup = dkMapper.queryConfigByUserId(dkCheckInRecordDTO.getSysUserId());

        // 定义集合，用于存储每天打卡记录
        List<DayRecord> dayRecords = new ArrayList<>();
        // 根据用户的ID 和月份查询该用户所有的打卡记录
        LambdaQueryWrapper<DkCheckInRecord> queryWrapper = buildQueryWrapper(dkCheckInRecordDTO);
        List<DkCheckInRecordDTO> dkCheckInRecordDTOS = dkMapper.selectVoList(queryWrapper);
        if (dkCheckInRecordDTOS == null && dkCheckInRecordDTOS.isEmpty()){
            return data;
        }

        // 构造excel数据
        // 定义迟到次数
        int lateCount = 0;
        // 定义早退次数
        int earlyCount = 0;
        // 工作日加班时间
        BigDecimal workOverTime = new BigDecimal(0);
        // 休息日加班时间
        BigDecimal restOverTime = new BigDecimal(0);
        // 异常数量
        BigDecimal exceptionCount = new BigDecimal(0);

        for(DkCheckInRecordDTO dk : dkCheckInRecordDTOS){
            // 根据打卡时间获取日期
            LocalDate localDate = dk.getCheckInTime() != null ? dk.getCheckInTime().toLocalDate() : LocalDate.now();
            // 获取所属考勤组的上班打卡时间
            String workStartTime = dkAttendanceGroup.getWorkStartTime();
            LocalDateTime workStartTime1 = LocalDateTime.of(localDate, LocalTime.parse(workStartTime));
            // 获取所属考勤组的下班打卡时间
            String workEndTime = dkAttendanceGroup.getWorkEndTime();
            LocalDateTime workEndTime1 = LocalDateTime.of(localDate, LocalTime.parse(workEndTime));

            // 获取所属考勤组的午休开始时间
            String lunchStartTime = dkAttendanceGroup.getLunchStartTime();
            LocalDateTime lunchStartTime1 = LocalDateTime.of(localDate, LocalTime.parse(lunchStartTime));
            // 获取所属考勤组的午休结束时间
            String lunchEndTime = dkAttendanceGroup.getLunchEndTime();
            LocalDateTime lunchEndTime1 = LocalDateTime.of(localDate, LocalTime.parse(lunchEndTime));
            // 获取所属考勤组的午休时间
            String lunchTime = dkAttendanceGroup.getLunchTime();

            // 构造DayRecord
            DayRecord dayRecord = new DayRecord();
            dayRecord.setDay(localDate.getDayOfMonth());
            // 获取星期几（返回 DayOfWeek 枚举）
            DayOfWeek dayOfWeek = localDate.getDayOfWeek();
            int week = dayOfWeek.getValue();
            String chineseWeek = dayOfWeek.getDisplayName(TextStyle.FULL, Locale.CHINESE);
            //System.out.println("中文星期：" + chineseWeek); // 输出：星期三
            dayRecord.setWeekday(chineseWeek);
            dayRecord.setStartTime(null != dk.getClockIn() ? dk.getClockIn().format(DateTimeFormatter.ofPattern("HH:mm:ss")) : "");
            dayRecord.setEndTime(null != dk.getClockOut() ? dk.getClockOut().format(DateTimeFormatter.ofPattern("HH:mm:ss")) : "");
            // 迟到早退判断
            if(dk.getClockIn() != null && dk.getClockOut() != null){
                if(dk.getClockIn().isAfter(workStartTime1.plusMinutes(1))){
                    dayRecord.setChidao("●");
                    dayRecord.setRemark("迟到1次");
                    lateCount ++;
                }

                if(dk.getClockOut().isBefore(workEndTime1)){
                    earlyCount ++;
                }
            }
            // 异常打卡 只有上班 没有下班
            if(dk.getClockIn() != null && dk.getClockOut() == null){
                dayRecord.setYichang("●");
                dayRecord.setRemark("异常打卡");
                exceptionCount = exceptionCount.add(new BigDecimal(1));
                //如果只有上班没有下班 而且上班还迟到了
                if(dk.getClockIn().isAfter(workStartTime1)){
                    dayRecord.setChidao("●");
                    dayRecord.setRemark(dayRecord.getRemark()+"、迟到1次");
                    lateCount ++;
                }
            }

            // 判断是否为休假日加班
            if(Constans.EXPORT_ZHOULIU==week || Constans.EXPORT_ZHOURI== week){
                //上下班都打卡了
                if(dk.getClockIn() != null && dk.getClockOut() != null){
                    double Overtime = 0;
                    if (dk.getClockIn().isBefore(lunchStartTime1)) {
                        // 午休之前 打卡时间在规定上班时间后 使用打卡时间 否则使用规定上班时间 计算
                        Overtime = calculateOvertime(dk.getClockIn().isAfter(workStartTime1)?dk.getClockIn():workStartTime1,
                            dk.getClockOut(),Double.valueOf(lunchTime),true);

                    }else if (dk.getClockIn().isAfter(lunchStartTime1)){
                        //午休之后 打卡时间计算
                        Overtime = calculateOvertime(dk.getClockIn(),dk.getClockOut(),0,false);
                    } else {
                        //午休中 使用午休结束时间计算
                        Overtime = calculateOvertime(lunchEndTime1,dk.getClockOut(),0,false);
                    }
                    //转换时间格式
                    dayRecord.setXiuxiri(formatOvertime(Overtime));
                    //休息日加班合计
                    restOverTime = restOverTime.add(new BigDecimal(Overtime));
                }
            }else {
                // 判断是否为工作日加班
                if(dk.getClockOut() != null){
                    if(dk.getClockOut().isAfter(workEndTime1)){
                        // 计算时间差 规定的下班打卡时间 和下班打卡时间差值
                        double Overtime = calculateOvertime(workEndTime1,dk.getClockOut(),0.5,true);
                        dayRecord.setGongzuori(formatOvertime(Overtime));
                        //工作日加班合计
                        workOverTime = workOverTime.add(new BigDecimal(Overtime));
                    }
                }
            }
            dayRecords.add(dayRecord);
        }

        data.setChidaocishu(lateCount);
        data.setWorkOverTime(workOverTime);
        data.setRestOverTime(restOverTime);
        data.setExceptionCount(exceptionCount);
        data.setDayRecords(dayRecords);
        return data;
    }

    private void fillTemplate(Sheet sheet, EmployeeAttendance data,String date,DkAttendanceGroupAndUser user,Map<String, Map<String,Integer>> summary) {
        // 1.填充标题区域
        setCellValue(sheet, 6, 6, user.getUserName());
        setCellValue(sheet, 6, 9, user.getNickName());
        setCellValue(sheet, 3, 1, date);

        //2.考勤数据区域
        //2.1 生成全部的日期和星期 并设置颜色
        int njCount =0;
        int rowIndex = 10;
        List<CalendarGenerator.DayInfo> dayInfos = CalendarGenerator.getMonthDays(date,"cn");
        for (int i = 0; i < dayInfos.size(); i++) {
            rowIndex = i + 10;
            //初始化天数
            setCellValue(sheet, rowIndex, 1, dayInfos.get(i).getDayNumber());
            //初始化星期
            String weekName = dayInfos.get(i).getDayOfWeek();

            setCellValue(sheet, rowIndex, 2, weekName);
            // 星期六和星期日背景颜色设置
            if ("六".equals(weekName) || "日".equals(weekName)) {
                Row row = sheet.getRow(rowIndex);
                if (row == null) row = sheet.createRow(rowIndex);
                Cell cell = row.getCell(2);
                if (cell == null) {
                    cell = row.createCell(2);
                }
                Workbook workbook = sheet.getWorkbook();

                CellStyle style = workbook.createCellStyle();
                style.cloneStyleFrom(cell.getCellStyle()); // 保留原有样式lightcyan
                style.setFillForegroundColor(IndexedColors.LIGHT_TURQUOISE.getIndex());
                style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                cell.setCellStyle(style);
            }


            //查询当前用户 这个月的年假 审批通过记录
            QueryWrapper<NjBalanceManageDetail> njWrapper = new QueryWrapper<>();
            njWrapper.eq("user_id", user.getUserId());
            njWrapper.eq("status","2");
            njWrapper.like("apply_dates",date);
            List<NjBalanceManageDetail> njList = njBalanceManageDetailMapper.selectList(njWrapper);

            boolean isLeave = false;
            if (njList != null && !njList.isEmpty()) {
                for (NjBalanceManageDetail detail : njList) {
                    String applyDates = detail.getApplyDates();
                    if (applyDates != null && !applyDates.isEmpty()) {
                        // 按逗号分割日期字符串
                        String[] dateArray = applyDates.split(",");
                        for (String dateStr : dateArray) {
                            //这一天是否申请了年假
                            if (dayInfos.get(i).getDate().equals(dateStr.trim())) {
                                isLeave = true;
                                break;
                            }
                        }
                    }
                    if (isLeave) {
                        break;
                    }
                }
            }

            if (isLeave) {
                DayRecord record = new DayRecord();
                record.setNj("●");
                record.setRemark("年假1天");
                fillTemplateCell(sheet, rowIndex, record);
                njCount++;
            }
        }
        //2.2 考勤数据赋值
        for (DayRecord record : data.getDayRecords()) {
            if(record.getDay() >0 &&record.getDay()<=31){
                //从第十行开始 赋值 例如 第一天在第十行 所以+9
                fillTemplateCell(sheet, record.getDay()+9, record);
            }
        }

        //3. 汇总数据区域
        setCellValue(sheet, 41, 5, data.getChidaocishu());
        setCellValue(sheet, 41, 6, data.getExceptionCount());
        setCellValue(sheet, 41, 7, formatOvertime(data.getWorkOverTime()==null?0:data.getWorkOverTime().doubleValue()));
        setCellValue(sheet, 41, 8, formatOvertime(data.getRestOverTime()==null?0:data.getRestOverTime().doubleValue()));
        setCellValue(sheet, 41, 10, njCount);
        if (njCount>0) {
            if (summary.containsKey(user.getNickName())) {
                Map map = summary.get(user.getNickName());
                map.put("njCount",njCount);
            } else {
                Map map = new HashMap();
                map.put("njCount",njCount);
                summary.put(user.getNickName(),map);
            }
        }
    }

    private void fillTemplateCell(Sheet sheet, int rowIndex, DayRecord record) {
        setCellValue(sheet, rowIndex, 3, record.getStartTime());
        setCellValue(sheet, rowIndex, 4, record.getEndTime());
        setCellValue(sheet, rowIndex, 5, record.getChidao());
        setCellValue(sheet, rowIndex, 6, record.getYichang());
        setCellValue(sheet, rowIndex, 7, record.getGongzuori());
        setCellValue(sheet, rowIndex, 8, record.getXiuxiri());
        setCellValue(sheet, rowIndex, 9, record.getFadingjiari());
        setCellValue(sheet, rowIndex, 10, record.getNj());
        setCellValue(sheet, rowIndex, 11, record.getQingjia());
        setCellValue(sheet, rowIndex, 12, record.getRemark());
    }


    /*--------------------------------------------------日本 --------------------------*/

    private EmployeeAttendance prepareSampleDataRiBen(DkCheckInRecordDTO dkCheckInRecordDTO) {

        // 定义员工类对象
        EmployeeAttendance data = new EmployeeAttendance();
        // 设置员工的昵称
        data.setEmployeeName(dkCheckInRecordDTO.getNickName());
        // 设置员工的用户名
        data.setUserName(dkCheckInRecordDTO.getSysUserName());

        // 判断月日是否为空
        if(dkCheckInRecordDTO.getStrMonth() != null){
            data.setDateTime(formatDate(dkCheckInRecordDTO.getStrMonth()));
        }
        if(dkCheckInRecordDTO.getStrDay() != null){
            data.setDateTime(convertToChineseFormat(dkCheckInRecordDTO.getStrDay()));
        }

        // 定义集合，用于存储每天打卡记录
        List<DayRecord> dayRecords = new ArrayList<>();

        // 根据用户的ID 和月份查询该用户所有的打卡记录
        LambdaQueryWrapper<DkCheckInRecord> queryWrapper = buildQueryWrapper(dkCheckInRecordDTO);
        List<DkCheckInRecordDTO> dkCheckInRecordDTOS = dkMapper.selectVoList(queryWrapper);

        //根据userId获取打卡配置信息
        DkAttendanceGroup dkAttendanceGroup = dkMapper.queryConfigByUserId(dkCheckInRecordDTO.getSysUserId());
        // 定义迟到次数
        int lateCount = 0;
        // 构造excel数据
        for(DkCheckInRecordDTO dk : dkCheckInRecordDTOS){
            // 根据打卡时间获取打卡日期
            LocalDate localDate = dk.getCheckInTime() != null ? dk.getCheckInTime().toLocalDate() : LocalDate.now();

            // 获取所属考勤组的上班打卡时间
            String workStartTime = dkAttendanceGroup.getWorkStartTime();
            LocalDateTime workStartTime1 = LocalDateTime.of(localDate, LocalTime.parse(workStartTime));
            // 获取所属考勤组的下班打卡时间
            String workEndTime = dkAttendanceGroup.getWorkEndTime();
            LocalDateTime workEndTime1 = LocalDateTime.of(localDate, LocalTime.parse(workEndTime));

            // 获取所属考勤组的午休开始时间
            String lunchStartTime = dkAttendanceGroup.getLunchStartTime();
            LocalDateTime lunchStartTime1 = LocalDateTime.of(localDate, LocalTime.parse(lunchStartTime));
            // 获取所属考勤组的午休结束时间
            String lunchEndTime = dkAttendanceGroup.getLunchEndTime();
            LocalDateTime lunchEndTime1 = LocalDateTime.of(localDate, LocalTime.parse(lunchEndTime));
            // 获取所属考勤组的午休时间
            String lunchTime = dkAttendanceGroup.getLunchTime();

            // 构造DayRecord
            DayRecord dayRecord = new DayRecord();

            //上班打卡
            dayRecord.setStartTime(null != dk.getClockIn() ? dk.getClockIn().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : "");
            //下班打卡
            dayRecord.setEndTime(null != dk.getClockOut() ? dk.getClockOut().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")) : "");
            dayRecord.setDay(dayRecord.getStartTime()==""?0:localDate.getDayOfMonth());

            //一天工作时间
            double rbHalf = calculateWorkHours(dk.getClockIn(), dk.getClockOut(),
                                               workStartTime1, workEndTime1,
                                               lunchStartTime1, lunchEndTime1);
            dayRecord.setRbHalf(rbHalf);

            // 迟到判断
            if(dk.getClockIn() != null){
                if(dk.getClockIn().isAfter(workStartTime1.plusMinutes(1))&&
                    (dk.getClockIn().getDayOfWeek()==DayOfWeek.MONDAY||
                     dk.getClockIn().getDayOfWeek() == DayOfWeek.TUESDAY||
                     dk.getClockIn().getDayOfWeek() == DayOfWeek.WEDNESDAY||
                     dk.getClockIn().getDayOfWeek() == DayOfWeek.THURSDAY||
                     dk.getClockIn().getDayOfWeek() == DayOfWeek.FRIDAY)){
                    dayRecord.setChidao("●");
                    dayRecord.setRemark("迟到1次");
                    lateCount ++;
                }

            }

            dayRecords.add(dayRecord);
        }

        data.setDayRecords(dayRecords);
        return data;
    }
    //日本excel 整体信息赋值
    private void fillTemplateRiBen(Sheet sheet, EmployeeAttendance data,String date,DkAttendanceGroupAndUser user) {
        // 1.填充标题区域
        setCellValue(sheet, 3, 1, date);
       // setCellValue(sheet, 3, 8, user.getDeptName());
        setCellValue(sheet, 6, 6, user.getUserName());
        setCellValue(sheet, 6, 8, user.getNickName());

        int rowIndex = 10;
        List<CalendarGenerator.DayInfo> dayInfos = CalendarGenerator.getMonthDays(date,"jp");
        for (int i = 0; i < dayInfos.size(); i++) {
            rowIndex = i + 10;
            //初始化天数
            setCellValue(sheet, rowIndex, 1, dayInfos.get(i).getDayNumber());
            //初始化星期 日本的星期名
            String weekName = dayInfos.get(i).getDayOfWeek();
            setCellValue(sheet, rowIndex, 2, weekName);
            // 日本的星期六和星期日背景颜色设置
            if ("土".equals(weekName) || "日".equals(weekName)) {
                Row row = sheet.getRow(rowIndex);
                if (row == null) row = sheet.createRow(rowIndex);
                Cell cell = row.getCell(2);
                if (cell == null) {
                    cell = row.createCell(2);
                }
                Workbook workbook = sheet.getWorkbook();
                CellStyle style = workbook.createCellStyle();
                style.cloneStyleFrom(cell.getCellStyle()); // 保留原有样式
                style.setFillForegroundColor(IndexedColors.LIGHT_TURQUOISE.getIndex());
                style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                cell.setCellStyle(style);
            }
        }

        double hj = 0d;
        //考勤信息区域
        for (DayRecord record : data.getDayRecords()) {
            if(record.getDay() >0 &&record.getDay()<=31){
                fillTemplateRiBenCell(sheet, record.getDay()+9, record);
                hj = hj+record.getRbHalf();
            }
        }
        //合计区域
        setCellValue(sheet, 41, 7, hj==0d?"":hj);

    }
    //日本excel 打卡信息赋值
    private void fillTemplateRiBenCell(Sheet sheet, int rowIndex, DayRecord record) {
        //1. 备注
        setCellValue(sheet, rowIndex, 8, record.getRemark());

        String startTime = record.getStartTime();
        String endTime = record.getEndTime();
        //2. 获取一天的工时
        if (StringUtils.isNotBlank(startTime)&&StringUtils.isNotBlank(endTime)) {
            setCellValue(sheet, rowIndex, 7, record.getRbHalf()==0d?"":record.getRbHalf());
        } else {
            setCellValue(sheet, rowIndex, 7, "");
        }

        //3.上班打卡 、下班打卡
        if (StringUtils.isNotBlank(startTime)) {
            startTime = startTime.substring(11);
        }
        if (StringUtils.isNotBlank(endTime)) {
            endTime = endTime.substring(11);
        }
        setCellValue(sheet, rowIndex, 3, startTime);
        setCellValue(sheet, rowIndex, 4, endTime);
        setCellValue(sheet, rowIndex, 8, record.getRemark());
    }

    /**
     * 计算加班时间，返回格式为 HH:mm:ss。如果加班时间为0则返回空字符串。
     * @param start 开始时间
     * @param end 结束时间
     * @param deductHours 扣除时间（比如 0.5）
     * @param isCalculateDeduct 计算扣除时间
     * @return 加班时长，格式为 "1:30:00"，若无加班则返回 ""
     */
    public static double calculateOvertime(LocalDateTime start, LocalDateTime end, double deductHours,boolean isCalculateDeduct) {
        // 计算时间差（分钟）
        long minutes = Duration.between(start, end).toMinutes();

        // 转换为小时（带小数）
        double totalHours = minutes / 60.0;

        //扣除时间
        double overtime = totalHours - deductHours;

        // 如果加班时间没有超过 deductHours   返回0
        if (overtime <= 0) {
            return 0d;
        }

        double floored = 0d;

        if (isCalculateDeduct) {
             floored = Math.floor(overtime * 2) / 2.0;
        } else {
             floored = Math.floor(totalHours * 2) / 2.0;
        }
        return floored;
    }
    public static String formatOvertime(double Overtime) {
        if (Overtime==0) {
            return "";
        }
        // 拆分小时和分钟部分
        int hours = (int) Overtime;
        int minutesPart = (Overtime % 1 == 0.5) ? 30 : 0;

        // 格式化为 HH:mm:ss 字符串
        return String.format("%d:%02d:00", hours, minutesPart);
    }


    /**
     * 日本模板 计算一天的工作时长（以0.5小时为最小单位）
     */
    public static double calculateWorkHours(
        LocalDateTime clockIn,
        LocalDateTime clockOut,
        LocalDateTime workStartTime,
        LocalDateTime workEndTime,
        LocalDateTime lunchStartTime,
        LocalDateTime lunchEndTime) {

        if (clockIn == null || clockOut == null) {
            return 0.0;
        }

        // 1. 上班时间取规定与打卡的较晚者
        LocalDateTime actualStart = clockIn.isBefore(workStartTime) ? workStartTime : clockIn;

        // 2. 下班时间取打卡与规定的较早者（如果早于0.5小时以内仍算正常下班）
        LocalDateTime actualEnd = clockOut;

        // 如果下班比规定下班早 <= 0.5小时，按规定时间算（不算加班）
        Duration diff = Duration.between(clockOut, workEndTime);
        if (!diff.isNegative() && diff.toMinutes() <= 30) {
            actualEnd = workEndTime;
        }

        // 3. 计算总时长
        long totalMinutes = Duration.between(actualStart, actualEnd).toMinutes();

        // 4. 扣除午休时长（如果上班时间和下班时间跨越了午休）
        long lunchMinutes = 0;
        if (actualStart.isBefore(lunchEndTime) && actualEnd.isAfter(lunchStartTime)) {
            // 午休重叠部分
            LocalDateTime lunchStart = actualStart.isAfter(lunchStartTime) ? actualStart : lunchStartTime;
            LocalDateTime lunchEnd = actualEnd.isBefore(lunchEndTime) ? actualEnd : lunchEndTime;
            lunchMinutes = Duration.between(lunchStart, lunchEnd).toMinutes();
        }

        totalMinutes -= lunchMinutes;

        if (totalMinutes <= 0) {
            return 0.0;
        }

        // 5. 按0.5小时为单位取整
        double hours = totalMinutes / 60.0;
        // 向下取到0.5小时倍数
        return Math.floor(hours * 2) / 2.0;
    }






    //为excel row的各个cell赋值
    private void setCellValue(Sheet sheet, int rowIndex, int colIndex, Object value) {
        Row row = sheet.getRow(rowIndex);
        if (row == null) {
            row = sheet.createRow(rowIndex);
        }

        Cell cell = row.getCell(colIndex);
        if (cell == null) {
            cell = row.createCell(colIndex);
        }

        if (value instanceof String) {
            cell.setCellValue((String) value);
        } else if (value instanceof Integer) {
            cell.setCellValue((Integer) value);
        } else if (value instanceof Double) {
            cell.setCellValue((Double) value);
        } else if (value != null) {
            cell.setCellValue(value.toString());
        }
    }

    public static String convertToChineseFormat(String dateStr) {
        // 解析输入字符串为LocalDate
        LocalDate date = LocalDate.parse(dateStr);

        // 定义目标格式（年-月-日带前导零）
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日");

        // 格式化日期
        return date.format(formatter);
    }

    public static String formatDate(String input) {
        // 解析输入字符串为LocalDate
        LocalDate date = LocalDate.parse(input + "-01");  // 假设输入是年月，补全为月初

        // 定义目标格式
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月");

        // 格式化日期
        return date.format(formatter);
    }

}
