package com.ruoyi.wgz.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.bgt.domain.BgtProjectRecruit;
import com.ruoyi.bgt.domain.BgtProjectRecruitApply;
import com.ruoyi.bgt.domain.dto.BgtAttendanceDTO;
import com.ruoyi.bgt.domain.vo.BgtAttendanceVO;
import com.ruoyi.bgt.service.IBgtProjectRecruitApplyService;
import com.ruoyi.bgt.service.IBgtProjectRecruitService;
import com.ruoyi.common.core.mybatisplus.core.ServicePlusImpl;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.utils.PageUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.wgz.bo.WgzAttendanceQueryBo;
import com.ruoyi.wgz.bo.req.WgzAppSubmitTheClockReq;
import com.ruoyi.wgz.bo.res.WgzAppCardReplacementApplicationRes;
import com.ruoyi.wgz.bo.res.WgzAppPunchTheCalendarRecordRes;
import com.ruoyi.wgz.bo.res.WgzAppUserClockingConditionRes;
import com.ruoyi.wgz.bo.rests.WgzAppCardReplacementApplicationTwo;
import com.ruoyi.wgz.bo.rests.WgzAppPunchTheCalendarRecordThree;
import com.ruoyi.wgz.bo.rests.WgzAppPunchTheCalendarRecordTwo;
import com.ruoyi.wgz.domain.WgzAttendance;
import com.ruoyi.wgz.domain.WgzLeave;
import com.ruoyi.bgt.domain.vo.BgtAttendanceCountVO;
import com.ruoyi.wgz.mapper.WgzAttendanceMapper;
import com.ruoyi.wgz.service.IWgzAttendanceService;
import com.ruoyi.wgz.service.IWgzLeaveService;
import org.aspectj.weaver.ast.Var;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DecimalFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * 考勤打卡Service业务层处理
 *
 * @author ruoyi
 * @date 2025-02-20
 */
@Service
public class WgzAttendanceServiceImpl extends ServicePlusImpl<WgzAttendanceMapper, WgzAttendance> implements IWgzAttendanceService {

	//上班打卡状态 0上 1下
	public static final String Clocking = "0";
	public static final String OffDuty= "1";

	@Autowired
	private IBgtProjectRecruitApplyService iBgtProjectRecruitApplyService;

	@Autowired
	private IBgtProjectRecruitService iBgtProjectRecruitService;

	@Autowired
	private  IWgzLeaveService iWgzLeaveService;


	@Override
    public WgzAttendance queryById(Long id){
        return getById(id);
    }

    @Override
    public TableDataInfo<WgzAttendance> queryPageList(WgzAttendanceQueryBo bo) {
        Page<WgzAttendance> result = page(PageUtils.buildPage(), buildQueryWrapper(bo));
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<WgzAttendance> queryList(WgzAttendanceQueryBo bo) {
        return list(buildQueryWrapper(bo));
    }

    private LambdaQueryWrapper<WgzAttendance> buildQueryWrapper(WgzAttendanceQueryBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<WgzAttendance> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getRecruitId() != null, WgzAttendance::getRecruitId, bo.getRecruitId());
        lqw.eq(bo.getUserId() != null, WgzAttendance::getUserId, bo.getUserId());
        lqw.eq(bo.getLeaveMarkId() != null, WgzAttendance::getLeaveMarkId, bo.getLeaveMarkId());
        lqw.eq(bo.getDailyWage() != null, WgzAttendance::getDailyWage, bo.getDailyWage());
        lqw.eq(bo.getDate() != null, WgzAttendance::getDate, bo.getDate());
        lqw.eq(StrUtil.isNotBlank(bo.getPnchOsition()), WgzAttendance::getPnchOsition, bo.getPnchOsition());
        lqw.eq(bo.getClockInTime() != null, WgzAttendance::getClockInTime, bo.getClockInTime());
        lqw.eq(bo.getClockOutTime() != null, WgzAttendance::getClockOutTime, bo.getClockOutTime());
        lqw.eq(bo.getLate() != null, WgzAttendance::getLate, bo.getLate());
        lqw.eq(bo.getLateTime() != null, WgzAttendance::getLateTime, bo.getLateTime());
        lqw.eq(bo.getEarlyLeave() != null, WgzAttendance::getEarlyLeave, bo.getEarlyLeave());
        lqw.eq(bo.getEarlyLeaveTime() != null, WgzAttendance::getEarlyLeaveTime, bo.getEarlyLeaveTime());
        lqw.eq(bo.getMissedIn() != null, WgzAttendance::getMissedIn, bo.getMissedIn());
        lqw.eq(bo.getMissedOut() != null, WgzAttendance::getMissedOut, bo.getMissedOut());
        lqw.eq(StrUtil.isNotBlank(bo.getExceptionType()), WgzAttendance::getExceptionType, bo.getExceptionType());
        return lqw;
    }

    @Override
    public Boolean insert(WgzAttendance bo) {
        WgzAttendance add = BeanUtil.toBean(bo, WgzAttendance.class);
        validEntityBeforeSave(add);
        return save(add);
    }

    @Override
    public Boolean update(WgzAttendance bo) {
        WgzAttendance update = BeanUtil.toBean(bo, WgzAttendance.class);
        validEntityBeforeSave(update);
        return updateById(update);
    }

    /**
     * 保存前的数据校验
     *
     * @param entity 实体类数据
     */
    private void validEntityBeforeSave(WgzAttendance entity){
        //TODO 做一些数据校验,如唯一约束
    }

    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return removeByIds(ids);
    }


	/**
	 * APP相关
	 * =================================================================================================================
	 * =================================================================================================================
	 * =================================================================================================================
	 */

	@Override
	@Transactional
	public Boolean userSubmitTheClock(WgzAppSubmitTheClockReq req) {
		//1、获取当前用户信息
		Long appUserId = SecurityUtils.getAppUserId();
		//2、获取当前用户所在的工地id
		BgtProjectRecruitApply by = iBgtProjectRecruitApplyService.selectByUserIdProjectRecruitApplyId(appUserId);
		//3、根据工地id得到完整的工地信息
		BgtProjectRecruit appById = iBgtProjectRecruitService.getAppById(by.getId());
//		//4、查看当前用户是否有请假申请，有请假申请并且通过，那就无法进行打卡------------------>此处代码将改写逻辑为：每天凌晨1分的时候直接找出已请假的人然后定时插入数据到打卡记录中标记为请假
//		String formattedDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
//		WgzLeave wgzLeave = iWgzLeaveService.FindAskForLeaveOrNotInfo(appUserId, by.getId(), formattedDate);
//		if (wgzLeave != null) { //表示有请假申请
//			LocalDateTime startTime = wgzLeave.getStartTime();
//			LocalDate localDate = startTime.toLocalDate();
//			throw new RuntimeException("您有已通过的请假申请，请假时间为："+localDate);
//		}
		//5、查看当前人、当前工地、当天的打卡记录
		String formattedDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
		WgzAttendance we = publicFindByUserIdWait(appUserId, by.getId(), formattedDate);
		String exceptionType = we.getExceptionType();
		if (we.getLeaveMarkId() != null && we.getLeaveMarkId()!= 0) {
			throw new RuntimeException("您有已通过的请假申请，请假时间为："+formattedDate);
		}
		//6、组装完整的打卡信息
		WgzAttendance wgzAttendance = new WgzAttendance().
			setRecruitId(appById.getId()).
			setUserId(appUserId).
			setDailyWage(appById.getRecruitAmount()).
			setDate(LocalDate.now()).
			setPnchOsition(req.getPnchOsition());
		LocalDateTime now = LocalDateTime.now(); //当前完整年月日时分秒
		LocalTime localTime = now.toLocalTime(); //获取时分秒
		if (Objects.isNull(we)) { //表示当天第一次打卡---上班
			wgzAttendance.setClockInTime(now);
			LocalTime beginWorkTime = appById.getBeginWorkTime(); //上班
			if (!localTime.isBefore(beginWorkTime)) {
				wgzAttendance.setLate(1); //迟到
				wgzAttendance.setLateTime(now);
				wgzAttendance.setExceptionType("1,");
			}
		}else{ //表示当天不是第一次打卡---下班
			wgzAttendance.setClockOutTime(now);
			LocalTime endWorkTime = appById.getEndWorkTime(); //下班
			if (!localTime.isAfter(endWorkTime)) {
				wgzAttendance.setEarlyLeave(1); //早退
				wgzAttendance.setEarlyLeaveTime(now);
				wgzAttendance.setExceptionType(exceptionType+"2,");
			}
		}
		return baseMapper.insert(wgzAttendance) > 0;
	}

	@Override
	public WgzAppUserClockingConditionRes userClockingCondition() {
		WgzAppUserClockingConditionRes res = new WgzAppUserClockingConditionRes();
		//1、获取打卡信息
		Long appUserId = SecurityUtils.getAppUserId();
		BgtProjectRecruitApply by = iBgtProjectRecruitApplyService.selectByUserIdProjectRecruitApplyId(appUserId);
		String formattedDate = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
		WgzAttendance wgzAttendance = publicFindByUserIdWait(appUserId, by.getId(), formattedDate);
		//2、获取今日用户打卡状态
		if (Objects.isNull(wgzAttendance)) {
			res.setClockingCondition(0); //上班
		}else{
			res.setClockingCondition(1); //下班
			if (wgzAttendance.getLeaveMarkId()!= null && wgzAttendance.getLeaveMarkId()!= 0) {
				res.setClockingCondition(2); //请假
			}
		}
		return res;
	}

	@Override
	public WgzAppPunchTheCalendarRecordRes userPunchTheCalendarRecord() {
		Long appUserId = SecurityUtils.getAppUserId();
		BgtProjectRecruitApply by = iBgtProjectRecruitApplyService.selectByUserIdProjectRecruitApplyId(appUserId);
		//1、获取当月的所有日期
		LocalDate currentDate = LocalDate.now();
		LocalDate firstDayOfMonth = currentDate.with(TemporalAdjusters.firstDayOfMonth());
		LocalDate lastDayOfMonth = currentDate.with(TemporalAdjusters.lastDayOfMonth());
		List<LocalDate> dates = new ArrayList<>();
		LocalDate tempDate = firstDayOfMonth;
		while (!tempDate.isAfter(lastDayOfMonth)) {
			dates.add(tempDate);
			tempDate = tempDate.plusDays(1);
		}
		String format = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM"));
		//2、获取当前人、当前工地、当前月的所有考勤记录
		LambdaQueryWrapper<WgzAttendance> apply = new LambdaQueryWrapper<WgzAttendance>().
			eq(WgzAttendance::getUserId, appUserId).
			eq(WgzAttendance::getRecruitId, by.getId()).
			apply("DATE_FORMAT(date, '%Y-%m') = {0}", format);
		List<WgzAttendance> wgzAttendances = baseMapper.selectList(apply);
		//3、组装返回数据
		Map<LocalDate, WgzAppPunchTheCalendarRecordTwo> mp = new HashMap<>();
		for (LocalDate date : dates) {
			for (WgzAttendance wa : wgzAttendances) {
				WgzAppPunchTheCalendarRecordTwo two = new WgzAppPunchTheCalendarRecordTwo().setId(wa.getId());
				LocalDate clockDate = wa.getDate();
				if (clockDate.equals(date)) {
					//上班
					if (wa.getClockInTime() != null) {
						two.setNum(1);
						two.setSb(sbOrXb(wa, 1));
					}
					//下班
					if (wa.getClockOutTime() != null) {
						two.setNum(2);
						two.setManHour(calculateWorkingHours(wa.getClockInTime(), wa.getClockOutTime()));
						two.setSb(sbOrXb(wa, 2));
					}
				}
				mp.put(date, two);
			}
		}
		return  new WgzAppPunchTheCalendarRecordRes().setMp(mp);
	}

	@Override
	public WgzAttendance findById(Long id) {
		return getById(id);
	}

	@Override
	public WgzAppCardReplacementApplicationRes userCardReplacementApplication() {
		//1、获取当前用户信息
		Long appUserId = SecurityUtils.getAppUserId();
		//2、获取当前用户所在的工地id
		BgtProjectRecruitApply by = iBgtProjectRecruitApplyService.selectByUserIdProjectRecruitApplyId(appUserId);
		//3、根据工地id得到完整的工地信息
		BgtProjectRecruit appById = iBgtProjectRecruitService.getAppById(by.getId());
		//4、查询所有缺卡、迟到、早退的打卡记录
		LambdaQueryWrapper<WgzAttendance> apply = new LambdaQueryWrapper<WgzAttendance>().
			eq(WgzAttendance::getUserId, appUserId).
			eq(WgzAttendance::getRecruitId, by.getId()).
			eq(WgzAttendance::getRecruitId, by.getId())
			.and(wrapper -> wrapper
				.eq(WgzAttendance::getLate, 1)
				.or()
				.eq(WgzAttendance::getEarlyLeave, 1)
				.or()
				.eq(WgzAttendance::getMissedIn, 1)
				.or()
				.eq(WgzAttendance::getMissedOut, 1)
			);
		List<WgzAttendance> wgzAttendances = baseMapper.selectList(apply);
		//4、将这些数据进行拆分
		ArrayList<WgzAppCardReplacementApplicationTwo> list = new ArrayList<>();
		for (WgzAttendance wgzAttendance : wgzAttendances) {
			String exceptionType = wgzAttendance.getExceptionType();
			if (exceptionType.contains("1")) { // 迟到
				addRecord(wgzAttendance, 1, wgzAttendance.getClockInTime(), list);
			}
			if (exceptionType.contains("2")) { // 早退
				addRecord(wgzAttendance, 2, wgzAttendance.getClockOutTime(), list);
			}
			if (exceptionType.contains("3")) { // 上班缺卡
				addRecord(wgzAttendance, 3, LocalDateTime.from(appById.getBeginWorkTime()), list);
			}
			if (exceptionType.contains("4")) { // 下班缺卡
				addRecord(wgzAttendance, 4, LocalDateTime.from(appById.getEndWorkTime()), list);
			}
		}
		return null;
	}

	@Override
	public List<BgtAttendanceCountVO> countByTaskId(Long taskId, LocalDate beginDate, LocalDate endDate) {
		return baseMapper.countByTaskId(taskId, beginDate, endDate);
	}

	@Override
	public BgtAttendanceVO attendanceDetail(BgtAttendanceDTO dto) {




		return null;
	}

	//	@Override
//	public WgzAttendance findByUserIdWait(Long appUserId, Long recruitId, String date) {
//		LambdaQueryWrapper<WgzAttendance> qw = new LambdaQueryWrapper<>();
//		qw.eq(WgzAttendance::getRecruitId,recruitId);
//		qw.eq(WgzAttendance::getUserId,appUserId);
//		return null;
//	}

	/**
	 * 获取指定人、指定工地、指定日期的打卡记录
	 * @param appUserId 务工者用户id
	 * @param recruitId 工地id
	 * @param date	具体日期
	 * @return WgzAttendance
	 */
	public WgzAttendance publicFindByUserIdWait(Long appUserId, Long recruitId, String date) {
		LambdaQueryWrapper<WgzAttendance> qw = new LambdaQueryWrapper<>();
		qw.eq(WgzAttendance::getRecruitId,recruitId);
		qw.eq(WgzAttendance::getUserId,appUserId);
		qw.eq(WgzAttendance::getDate,date);
		return baseMapper.selectOne(qw);
	}

	/**
	 * 计算两个时间之间的工作小时数
	 *
	 * @param startTime 开始时间
	 * @param endTime   结束时间
	 * @return 工作小时数
	 */
	public double calculateWorkingHours(LocalDateTime startTime, LocalDateTime endTime) {
		// 计算两个时间之间的持续时间
		Duration duration = Duration.between(startTime, endTime);

		// 将持续时间转换为分钟
		long minutes = duration.toMinutes();

		// 将分钟转换为小时
		double hours = (double) minutes / 60;

		// 使用 DecimalFormat 保留两位小数
		DecimalFormat df = new DecimalFormat("#.00");
		String formattedHours = df.format(hours);

		// 将格式化后的字符串转换回 double 类型
		return Double.parseDouble(formattedHours);
	}

	/**
	 * 组装上班、下班打卡记录
	 * @param wa 打卡记录
	 * @param num 1上班 2下班
	 * @return WgzAppPunchTheCalendarRecordThree
	 */
	public WgzAppPunchTheCalendarRecordThree sbOrXb( WgzAttendance wa,int num) {
		WgzAppPunchTheCalendarRecordThree sbb = new WgzAppPunchTheCalendarRecordThree().
			setClockingTime(wa.getClockInTime()).
			setPnchOsition(wa.getPnchOsition()).
			setClockingCondition(0); //正常
		//判断是否请假
		if (wa.getLeaveMarkId()!=null && wa.getLeaveMarkId()!=0) {
			sbb.setClockingCondition(7);
		}
		if (num == 1){
			//判断上班迟到
			if (wa.getLate() == 1) {
				sbb.setClockingCondition(1);
			}
			//判断是否上班补卡
			if (wa.getExceptionType().contains("5")) {
				sbb.setClockingCondition(5);
			}
		}
		if (num == 2){
			//判断下班早退
			if (wa.getEarlyLeave() == 1) {
				sbb.setClockingCondition(2);
			}
			//判断是否下班补卡
			if (wa.getExceptionType().contains("6")) {
				sbb.setClockingCondition(6);
			}
		}
		return sbb;
	}

	/**
	 * 补卡
	 * @param wgzAttendance 打卡记录
	 * @param type 1上班 2下班
	 * @param fillingDataTime 补卡时间
	 * @param list 补卡记录
	 */
	private void addRecord(WgzAttendance wgzAttendance, int type, LocalDateTime fillingDataTime, List<WgzAppCardReplacementApplicationTwo> list) {
		LocalDate date = wgzAttendance.getDate();
		DayOfWeek dayOfWeek = date.getDayOfWeek();
		String week = dayOfWeek.toString();
		WgzAppCardReplacementApplicationTwo two = new WgzAppCardReplacementApplicationTwo()
			.setId(wgzAttendance.getId())
			.setType(type)
			.setFillingData(date)
			.setWeek(week)
			.setFillingDataTime(fillingDataTime);
		list.add(two);
	}
}
