package cn.iocoder.yudao.module.system.service.attendance.groupuser;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.iocoder.yudao.framework.common.Constants;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserCreateOrDelVO;
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.groupuser.vo.AttendanceGroupUserSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.groupuser.AttendanceGroupUserDO;
import cn.iocoder.yudao.module.system.dal.dataobject.attendance.punchrecord.AttendancePunchRecordDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysetting.HolidaySettingDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidaysettingrange.HolidaySettingRangeDO;
import cn.iocoder.yudao.module.system.dal.dataobject.holiday.holidayworkingage.HolidayWorkingAgeDO;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.groupuser.AttendanceGroupUserMapper;
import cn.iocoder.yudao.module.system.dal.mysql.attendance.punchrecord.AttendancePunchRecordMapper;
import cn.iocoder.yudao.module.system.service.attendance.punch.dto.AttendanceOnTheDayDTO;
import cn.iocoder.yudao.module.system.service.attendance.punchrecord.AttendancePunchRecordService;
import cn.iocoder.yudao.module.system.service.holiday.holidaysetting.HolidaySettingService;
import cn.iocoder.yudao.module.system.service.holiday.holidaysettingrange.HolidaySettingRangeService;
import cn.iocoder.yudao.module.system.service.holiday.holidayuserrecord.HolidayUserRecordService;
import cn.iocoder.yudao.module.system.service.holiday.holidayworkingage.HolidayWorkingAgeService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.GROUP_USER_NOT_EXISTS;

/**
 * 考勤组人员 Service 实现类
 *
 * @author 艾楷
 */
@Service
@Validated
public class AttendanceGroupUserServiceImpl implements AttendanceGroupUserService {

    @Resource
    private AttendanceGroupUserMapper groupUserMapper;
    @Resource
    private StringRedisTemplate stringRedisTemplate;
    @Resource
    private AttendancePunchRecordMapper attendancePunchRecordMapper;
    @Resource
    private AttendancePunchRecordService attendancePunchRecordService;
    @Resource
    private HolidayUserRecordService holidayUserRecordService;
    @Resource
    private HolidaySettingRangeService holidaySettingRangeService;
    @Resource
    @Lazy
    private HolidaySettingService holidaySettingService;
    @Resource
    private HolidayWorkingAgeService holidayWorkingAgeService;

    @Override
    public AttendanceGroupUserCreateOrDelVO createOrDel(Long attendanceGroupId, List<Long> userIds) {
        AttendanceGroupUserCreateOrDelVO vo = new AttendanceGroupUserCreateOrDelVO();

        List<AttendanceGroupUserDO> groupUserList = groupUserMapper.selectList(AttendanceGroupUserDO::getAttendanceGroupId, attendanceGroupId);
        List<AttendanceGroupUserDO> list = new ArrayList<>();

        if (CollectionUtil.isEmpty(userIds)) {
            userIds = Collections.emptyList();
        }
        List<Long> oldUserIds = groupUserList.stream().map(AttendanceGroupUserDO::getUserId).collect(Collectors.toList());
        List<Long> delIds = new ArrayList<>(CollectionUtil.subtract(oldUserIds, userIds));
        List<Long> saveIds = new ArrayList<>(CollectionUtil.subtract(userIds, oldUserIds));
        if (CollectionUtil.isNotEmpty(delIds)) {
            groupUserMapper.delete(new LambdaQueryWrapper<AttendanceGroupUserDO>().eq(AttendanceGroupUserDO::getAttendanceGroupId, attendanceGroupId)
                    .in(AttendanceGroupUserDO::getUserId, delIds));
        }
        if (CollectionUtil.isNotEmpty(saveIds)) {
            List<HolidaySettingRangeDO> items = new ArrayList<>();
            for (Long userId : saveIds) {
                list.add(new AttendanceGroupUserDO().setUserId(userId).setAttendanceGroupId(attendanceGroupId));

                HolidaySettingRangeDO item = new HolidaySettingRangeDO();
                item.setType(3);
                item.setObjectId(userId);
                items.add(item);
            }
            groupUserMapper.insertBatch(list);
            // -- 新添加到考勤组的 需要同步更新员工假期余额
            // -- 获取当前用户所在的考勤组 - 再根据考勤组 查询对应的加班规则
            List<Long> holidaySettingIds = holidaySettingRangeService.getHolidaySettingIdsByGroupId(attendanceGroupId);

            if (CollUtil.isNotEmpty(holidaySettingIds)) {
                List<HolidayWorkingAgeDO> holidayWorkingAgeDOS = holidayWorkingAgeService.selectBySettingIds(holidaySettingIds);
                Map<Long, List<HolidayWorkingAgeDO>> holidayWorkingAgeDOMap = holidayWorkingAgeDOS.stream().collect(Collectors.groupingBy(HolidayWorkingAgeDO::getHolidaySettingId, Collectors.toList()));

                List<HolidaySettingDO> holidaySettings = holidaySettingService.getHolidaySettingByIds(holidaySettingIds);
                Map<Long, HolidaySettingDO> holidaySettingMap = holidaySettings.stream().collect(Collectors.toMap(HolidaySettingDO::getId, holidaySettingDO -> holidaySettingDO));
                for (HolidaySettingDO holidaySetting : holidaySettings) {
                    holidayUserRecordService.grant(holidaySetting,
                            items, holidaySettingMap.get(holidaySetting.getId()).getHolidayBalanceSettingDO(), holidayWorkingAgeDOMap.get(holidaySetting.getId()), true);
                }
            }
        }
        vo.setAttendanceGroupId(attendanceGroupId);
        vo.setDelUserIds(delIds);
        vo.setSaveUserIds(saveIds);
        return vo;
    }

    @Override
    public void updateGroupUser(AttendanceGroupUserSaveReqVO updateReqVO) {
        // 校验存在
        validateGroupUserExists(updateReqVO.getId());
        // 更新
        AttendanceGroupUserDO updateObj = BeanUtils.toBean(updateReqVO, AttendanceGroupUserDO.class);
        groupUserMapper.updateById(updateObj);
    }

    @Override
    public void deleteGroupUser(Long id) {
        // 校验存在
        validateGroupUserExists(id);
        // 删除
        groupUserMapper.deleteById(id);
    }

    private void validateGroupUserExists(Long id) {
        if (groupUserMapper.selectById(id) == null) {
            throw exception(GROUP_USER_NOT_EXISTS);
        }
    }

    @Override
    public AttendanceGroupUserDO getGroupUser(Long id) {
        return groupUserMapper.selectById(id);
    }

    @Override
    public PageResult<AttendanceGroupUserDO> getGroupUserPage(AttendanceGroupUserPageReqVO pageReqVO) {
        return groupUserMapper.selectPage(pageReqVO);
    }

    @Override
    public List<Long> getUserIdsByGroupId(Long id) {
        List<AttendanceGroupUserDO> list = groupUserMapper.selectList(new LambdaQueryWrapper<AttendanceGroupUserDO>()
                .eq(AttendanceGroupUserDO::getAttendanceGroupId, id));
        return list.stream().map(AttendanceGroupUserDO::getUserId).collect(Collectors.toList());
    }

    @Override
    public void effectiveImmediately(AttendanceGroupUserCreateOrDelVO vo) {
        LocalDateTime now = LocalDateTime.now();
        String time = now.format(Constants.REPO_DATE_FORMAT);
        String yesterdayStr = LocalDateTimeUtil.offset(now, 1, ChronoUnit.DAYS).format(Constants.REPO_DATE_FORMAT);
        // 删除掉redis 中的记录 -
        if (CollectionUtil.isNotEmpty(vo.getDelUserIds())) {
            String key = Constants.ATTENDANCE + Constants.UNDERLINE + vo.getAttendanceGroupId() + Constants.UNDERLINE; // + 时间
            stringRedisTemplate.opsForHash().delete(key + time, vo.getDelUserIds().stream().map(String::valueOf).toArray(String[]::new));
            stringRedisTemplate.opsForHash().delete(key + yesterdayStr, vo.getDelUserIds().stream().map(String::valueOf).toArray(String[]::new));
            //删除掉这些人员在这个考勤组里的记录
            attendancePunchRecordMapper.delete(new LambdaQueryWrapper<AttendancePunchRecordDO>()
                    .eq(AttendancePunchRecordDO::getAttendanceGroupId, vo.getAttendanceGroupId())
                    .in(AttendancePunchRecordDO::getUserId, vo.getDelUserIds())
                    .and(a -> a.eq(AttendancePunchRecordDO::getNextDayFlag, Constants.TRUE)
                            .or()
                            .eq(AttendancePunchRecordDO::getStatus, AttendanceOnTheDayDTO.PUNCH_STATUS_UN_PUNCH))
            );
        }
        if (CollectionUtil.isNotEmpty(vo.getSaveUserIds())) {
            attendancePunchRecordService.defaultPersistence(vo.getAttendanceGroupId(), vo.getSaveUserIds(), LocalDateTime.now());
        }
    }

    @Override
    public List<Long> getUserIdsByGroupIds(List<Long> groupIds) {
        if (CollectionUtil.isEmpty(groupIds)) {
            return Collections.emptyList();
        }
        return groupUserMapper.selectList(new LambdaQueryWrapper<AttendanceGroupUserDO>()
                        .in(AttendanceGroupUserDO::getAttendanceGroupId, groupIds))
                .stream().map(AttendanceGroupUserDO::getUserId).collect(Collectors.toList());
    }

}
