package com.ruoyi.oa.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.oa.domain.LaborCostData;
import com.ruoyi.oa.domain.OaAttendanceRecord;
import com.ruoyi.oa.domain.vo.AttendanceMonthlyCount;
import com.ruoyi.oa.domain.vo.SysOaProjectVo;
import com.ruoyi.oa.domain.vo.SysUserVo;
import com.ruoyi.oa.mapper.OaAttendanceRecordMapper;
import com.ruoyi.oa.service.ISysOaProjectService;
import com.ruoyi.system.mapper.SysUserRoleMapper;
import com.ruoyi.system.service.ISysUserService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.oa.domain.bo.SysOaAttendanceBo;
import com.ruoyi.oa.domain.vo.SysOaAttendanceVo;
import com.ruoyi.oa.domain.SysOaAttendance;
import com.ruoyi.oa.mapper.SysOaAttendanceMapper;
import com.ruoyi.oa.service.ISysOaAttendanceService;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 人员考勤Service业务层处理
 *
 * @author hdka
 * @date 2024-11-05
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class SysOaAttendanceServiceImpl implements ISysOaAttendanceService {

    private final SysOaAttendanceMapper baseMapper;

    @Autowired
    private ISysUserService sysUserService;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private ISysOaProjectService projectService;

    @Autowired
    private OaAttendanceRecordMapper recordMapper;

    /**
     * 查询人员考勤
     */
    @Override
    public SysOaAttendanceVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询人员考勤列表
     */
    @Override
    public TableDataInfo<SysOaAttendanceVo> queryPageList(SysOaAttendanceBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<SysOaAttendance> lqw = buildQueryWrapper(bo);
        Page<SysOaAttendanceVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询人员考勤列表
     */
    @Override
    public List<SysOaAttendanceVo> queryList(SysOaAttendanceBo bo) {
        LambdaQueryWrapper<SysOaAttendance> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<SysOaAttendance> buildQueryWrapper(SysOaAttendanceBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<SysOaAttendance> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getUserId() != null, SysOaAttendance::getUserId, bo.getUserId());
        lqw.eq(bo.getAttendanceDay() != null, SysOaAttendance::getAttendanceDay, bo.getAttendanceDay());
        lqw.eq(bo.getProjectId() != null, SysOaAttendance::getProjectId, bo.getProjectId());
        lqw.eq(bo.getDayLength() != null, SysOaAttendance::getDayLength, bo.getDayLength());
        lqw.eq(bo.getHour() != null, SysOaAttendance::getHour, bo.getHour());
        lqw.like(bo.getCreateTime() != null, SysOaAttendance::getCreateTime, bo.getCreateTime());
        return lqw;
    }

    /**
     * 新增人员考勤
     */
    @Override
    public Boolean insertByBo(SysOaAttendanceBo bo) {
        SysOaAttendanceBo sysOaAttendanceBo = new SysOaAttendanceBo();

        BeanUtil.copyProperties(bo, sysOaAttendanceBo);
        sysOaAttendanceBo.setProjectId(null);
        // 如果这个时间为空，则默认查询当月记录
        Date firstDay;
        Date lastDay = getLastDay(bo.getSelectTime());
        List<SysOaAttendanceVo> sysOaAttendanceVos;


        Date day = getFirstDay(bo.getSelectTime());
        firstDay = getFormatDay(bo.getSelectTime(), bo.getAttendanceDay());

        sysOaAttendanceVos = baseMapper.queryListByTime(sysOaAttendanceBo.getUserId(), sysOaAttendanceBo.getAttendanceDay(), day, lastDay);

        if (sysOaAttendanceVos.isEmpty()) {
            bo.setCreateTime(firstDay);
            SysOaAttendance add = BeanUtil.toBean(bo, SysOaAttendance.class);
            validEntityBeforeSave(add);
            boolean flag = baseMapper.insert(add) > 0;
            if (flag) {
                bo.setId(add.getId());
            }
            return flag;
        } else {
            SysOaAttendanceVo sysOaAttendanceVo = sysOaAttendanceVos.get(0);
            sysOaAttendanceVo.setProjectId(bo.getProjectId());
            sysOaAttendanceVo.setCreateTime(firstDay);
            sysOaAttendanceVo.setDelFlag(0L);
            sysOaAttendanceVo.setDayLength(bo.getDayLength() != null ? bo.getDayLength() : 0);
            sysOaAttendanceVo.setHour(bo.getHour() != null ? bo.getHour() : 0);
            return baseMapper.updateDelAttendance(BeanUtil.toBean(sysOaAttendanceVo, SysOaAttendance.class)) > 0;
        }

    }

    /**
     * 修改人员考勤
     */
    @Override
    public Boolean updateByBo(SysOaAttendanceBo bo) {
        SysOaAttendance update = BeanUtil.toBean(bo, SysOaAttendance.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(SysOaAttendance entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除人员考勤
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public TableDataInfo<SysUserVo> workerList(SysOaAttendanceBo bo) {
        List<Long> userIds = sysUserRoleMapper.selectUserIdsByRoleId(1852970465740505090L);
        // 如果这个时间为空，则默认查询当月记录
        Date firstDay;
        Date lastDay;
        if (Objects.isNull(bo.getSelectTime())) {
            firstDay = getFirstDay(new Date());

        } else {
            firstDay = getFirstDay(bo.getSelectTime());
        }
        lastDay = getLastDay(firstDay);
        Page<SysUserVo> result = new Page<>();
        result.setRecords(baseMapper.selectUserListAndAttendanceListAndProjectListByUserIds(userIds, firstDay, lastDay));

        // 这个total写当月有多长时间
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(firstDay);
        result.setTotal(calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        // 优化查询
        return TableDataInfo.build(result);
    }

    @Override
    public int insertBatch(SysOaAttendanceBo bo) {
        List<Long> userIds = sysUserRoleMapper.selectUserIdsByRoleId(1852970465740505090L);
        for (Long userId : userIds) {
            SysOaAttendanceBo sysOaAttendanceBo = BeanUtil.toBean(bo, SysOaAttendanceBo.class);
            sysOaAttendanceBo.setUserId(userId);
            this.insertByBo(sysOaAttendanceBo);
        }
        return 1;
    }


    /**
     * 计算人力成本
     *
     * @param time 月份
     * @return
     */
    @Override
    public List<LaborCostData> workerCalc(Date time) {

        Date firstDay = getFirstDay(time);
        Date lastDay = getLastDay(time);
        // 查询所有的工人
        List<Long> userIds = sysUserRoleMapper.selectUserIdsByRoleId(1852970465740505090L);
        List<Long> workerIds = baseMapper.selectNowMonthUserId(firstDay);
        // 合并并去重
        workerIds = Stream
                .concat(userIds.stream(), workerIds.stream())
                .distinct()
                .collect(Collectors.toList());
        List<LaborCostData> costDataList = new ArrayList<>();


        // 检测当天是否生成了完全一样的数据
        List<Long> recordIds = recordMapper.listCommonDateRecord(DateUtils.getDate(), firstDay);
        if (!recordIds.isEmpty()) {
            // 如果有重复的就删掉
            recordMapper.deleteBatchIds(recordIds);
        }

        // 开始写入
        for (Long userId : workerIds) {
            SysUserVo sysUser = BeanUtil.toBean(sysUserService.selectUserByIdIncludingDel(userId), SysUserVo.class);
            SysOaAttendanceVo sysOaAttendanceVo = new SysOaAttendanceVo();
            sysOaAttendanceVo.setUserId(sysUser.getUserId());

            // 查询某月记录
            List<SysOaAttendanceVo> sysOaAttendanceVos = baseMapper.selectVoListAndTime(userId, firstDay, lastDay);
            List<SysOaProjectVo> projectVos = new ArrayList<>();
            Double workTimes = 0.0;
            Double hourWorkTimes = 0.0;
            Double overTime = 0.0;
            Double tripDays = 0.0;
            Double leaveCount = 0.0;
            Set<Long> projSet = new HashSet<>();
            for (SysOaAttendanceVo oaAttendanceVo : sysOaAttendanceVos) {
                tripDays += oaAttendanceVo.getTripDays();
                leaveCount+=oaAttendanceVo.getAbsenceDays();
                workTimes += oaAttendanceVo.getWorkTimes();
                hourWorkTimes += oaAttendanceVo.getHourWorkTimes();
                overTime += oaAttendanceVo.getOverTime();
                if (oaAttendanceVo.getProjectId() != 0L && oaAttendanceVo.getProjectId() != 1L) {
                    SysOaProjectVo sysOaProjectVo = projectService.queryById(oaAttendanceVo.getProjectId());
                    oaAttendanceVo.setColor(sysOaProjectVo.getColor());
                    oaAttendanceVo.setSysOaProjectVo(sysOaProjectVo);
                    oaAttendanceVo.setProjectName(sysOaProjectVo.getProjectName());
                    projectVos.add(sysOaProjectVo);
                    projSet.add(oaAttendanceVo.getProjectId());
                }
            }
            // 此为所有小时计的综合
            projectVos.stream().distinct().collect(Collectors.toList());
            LaborCostData laborCostData = new LaborCostData();
            laborCostData.setProjects(projectVos);
            laborCostData.setAttendances(sysOaAttendanceVos);
            laborCostData.setSysUser(sysUser);
            laborCostData.setWorkTimes(workTimes);
            laborCostData.setTripTimes(tripDays);
            laborCostData.setAbsenceDays(leaveCount);
            laborCostData.setHourWorkTime(hourWorkTimes);
            // 加班时间
            laborCostData.setOvertime(overTime);
            costDataList.add(laborCostData);
            // 构造并保存记录
            addGenData(firstDay, sysUser, tripDays, leaveCount, workTimes, projSet, overTime);
        }


        return costDataList;
    }

    private void addGenData(Date firstDay, SysUserVo sysUser, Double tripDays, Double leaveCount, Double workDays, Set<Long> projSet, Double overtimeSum) {
        OaAttendanceRecord rec = new OaAttendanceRecord();
        // relationMonth 只保留年月，可直接传入 firstDay（其 day=1）
        rec.setRelationMonth(firstDay);
        // calcTime 为当前时间
        rec.setCalcTime(new Date());
        // 当前操作人昵称
        rec.setNickName(sysUser.getNickName());
        rec.setUserId(sysUser.getUserId());
        rec.setTrips(new BigDecimal(tripDays.toString()));
        rec.setNotNum(new BigDecimal(leaveCount.toString()));
        rec.setWorks(new BigDecimal(workDays.toString()));
        rec.setProjectIds(
                String.join(",",
                        projSet.stream().map(String::valueOf).toArray(String[]::new)
                )
        );
        rec.setOverNum(BigDecimal.valueOf(overtimeSum));
        rec.setRemark("自动统计生成");
        recordMapper.insert(rec);

    }

    /**
     * 删除当月某日所有人的记录
     *
     * @param day 日期
     * @return
     */
    @Override
    public int delOaAttendanceAll(Long day) {

        Date now = new Date();
        return baseMapper.delOaAttendanceAll(getFirstDay(now), getLastDay(now), day);
    }

    @Override
    public List<AttendanceMonthlyCount> selectLastSixMonthsByMonth(String refDate) {

        return baseMapper.selectLastSixMonthsByMonth(refDate);
    }


    @Override
    public AttendanceMonthlyCount selectAttendanceMonthlyCountByMonth(String refDate) {

        return baseMapper.selectAttendanceMonthlyCountByMonth(refDate);
    }

    @Override
    public List<AttendanceMonthlyCount> selectMonthlyCounts(String refDate) {

        return baseMapper.selectMonthlyCounts(refDate);
    }

    private Date getFirstDay(Date time) {
        String firstDay = DateUtils.parseDateToStr("yyyy-MM-01", time);
        return DateUtils.parseDate(firstDay);
    }

    private Date getFormatDay(Date time, Long attendanceDay) {
        String firstDay = DateUtils.parseDateToStr("yyyy-MM-" + attendanceDay, time);
        return DateUtils.parseDate(firstDay);
    }

    private Date getLastDay(Date time) {
        String format = "yyyy-MM-";
        // 计算某月的天数
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(time);
        String dateLength = String.valueOf(calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        // 将字符串拼接
        format += dateLength;
        format += " 23:59:59";
        return DateUtils.parseDate(DateUtils.parseDateToStr(format, time));
    }
}
