package com.mortals.xhx.module.attendance.service.impl;

import cn.hutool.core.date.DateUtil;
import com.mortals.framework.common.Rest;
import com.mortals.framework.model.PageInfo;
import com.mortals.xhx.common.code.GoWorkResultEnum;
import com.mortals.xhx.common.code.OffWorkResultEnum;
import com.mortals.xhx.module.attendance.model.AttendanceRecordQuery;
import com.mortals.xhx.module.attendance.model.vo.AttendStatInfo;
import org.springframework.stereotype.Service;
import com.mortals.framework.service.impl.AbstractCRUDServiceImpl;
import com.mortals.framework.exception.AppException;
import com.mortals.framework.model.Context;
import com.mortals.xhx.module.attendance.dao.AttendanceRecordDao;
import com.mortals.xhx.module.attendance.model.AttendanceRecordEntity;
import com.mortals.xhx.module.attendance.service.AttendanceRecordService;
import org.springframework.beans.factory.annotation.Autowired;
import com.mortals.xhx.module.attendance.model.AttendanceRecordDetailEntity;
import com.mortals.xhx.module.attendance.model.AttendanceRecordDetailQuery;
import com.mortals.xhx.module.attendance.service.AttendanceRecordDetailService;
import org.springframework.util.ObjectUtils;

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

/**
 * AttendanceRecordService
 * 考勤打卡记录信息 service实现
 *
 * @author zxfei
 * @date 2023-04-07
 */
@Service("attendanceRecordService")
public class AttendanceRecordServiceImpl extends AbstractCRUDServiceImpl<AttendanceRecordDao, AttendanceRecordEntity, Long> implements AttendanceRecordService {
    @Autowired
    private AttendanceRecordDetailService attendanceRecordDetailService;


    @Override
    protected void findAfter(AttendanceRecordEntity params, PageInfo pageInfo, Context context, List<AttendanceRecordEntity> list) throws AppException {
        list.stream().map(item -> {
            List<AttendanceRecordDetailEntity> attendanceRecordDetailEntities = attendanceRecordDetailService.find(new AttendanceRecordDetailQuery().recordId(item.getId()));

            item.setAttendanceRecordDetailList(attendanceRecordDetailEntities);
            return item;
        }).collect(Collectors.toList());
    }

    @Override
    protected void findAfter(AttendanceRecordEntity entity, Context context, List<AttendanceRecordEntity> list) throws AppException {
        Map<Long, List<AttendanceRecordDetailEntity>> collect = attendanceRecordDetailService.find(new AttendanceRecordDetailQuery()).parallelStream().collect(Collectors.groupingBy(x -> x.getRecordId()));
        list.stream().map(item -> {
            List<AttendanceRecordDetailEntity> attendanceRecordDetailEntities = collect.getOrDefault(item.getId(), new ArrayList<>());
            attendanceRecordDetailEntities.forEach(i -> {
                i.setStaffId(item.getStaffId());
            });
            //List<AttendanceRecordDetailEntity> attendanceRecordDetailEntities = attendanceRecordDetailService.find(new AttendanceRecordDetailQuery().recordId(item.getId()));
            item.setAttendanceRecordDetailList(attendanceRecordDetailEntities);
            return item;
        }).collect(Collectors.toList());
    }

    @Override
    protected void saveAfter(AttendanceRecordEntity entity, Context context) throws AppException {
        if (!ObjectUtils.isEmpty(entity.getAttendanceRecordDetailList())) {
            entity.getAttendanceRecordDetailList().stream().peek(item -> {
                item.setRecordId(entity.getId());
                item.setCreateUserId(this.getContextUserId(context));
                item.setCreateTime(new Date());
            }).count();
            attendanceRecordDetailService.save(entity.getAttendanceRecordDetailList());
        }
        super.saveAfter(entity, context);
    }

    @Override
    protected void updateAfter(AttendanceRecordEntity entity, Context context) throws AppException {
        if (!ObjectUtils.isEmpty(entity.getAttendanceRecordDetailList())) {
            Long[] attendanceRecordDetailIds = attendanceRecordDetailService.find(new AttendanceRecordDetailQuery().recordId(entity.getId())).stream().map(AttendanceRecordDetailEntity::getId).toArray(Long[]::new);
            attendanceRecordDetailService.remove(attendanceRecordDetailIds, context);
            entity.getAttendanceRecordDetailList().stream().peek(item -> {
                item.setRecordId(entity.getId());
                item.setCreateUserId(this.getContextUserId(context));
                item.setCreateTime(new Date());
                item.setUpdateUserId(this.getContextUserId(context));
                item.setUpdateTime(new Date());
            }).count();
            attendanceRecordDetailService.save(entity.getAttendanceRecordDetailList());
        }
        super.updateAfter(entity, context);
    }

    @Override
    protected void removeAfter(Long[] ids, Context context, int result) throws AppException {
        List<AttendanceRecordDetailEntity> attendanceRecordDetaillist = attendanceRecordDetailService.find(new AttendanceRecordDetailQuery().recordIdList(Arrays.asList(ids)));
        attendanceRecordDetailService.removeList(attendanceRecordDetaillist, context);
        super.removeAfter(ids, context, result);
    }

    @Override
    public Rest<AttendStatInfo> statByDay(Context context) {
        AttendStatInfo attendStatInfo = new AttendStatInfo();

        AttendanceRecordQuery attendanceRecordQuery = new AttendanceRecordQuery();
        attendanceRecordQuery.setAttendanceDateStart(DateUtil.today());
        attendanceRecordQuery.setAttendanceDateEnd(DateUtil.today());
        List<AttendanceRecordEntity> attendanceRecordEntities = this.find(attendanceRecordQuery);
        //去掉重复
        long total = attendanceRecordEntities.parallelStream().map(item -> item.getStaffId()).distinct().count();
        attendStatInfo.setTotal(total);

        //迟到次数
        long beLate = attendanceRecordEntities.parallelStream()
                .flatMap(item -> item.getAttendanceRecordDetailList().stream())
                .filter(f -> GoWorkResultEnum.迟到.getValue() == f.getGoWorkResult() || OffWorkResultEnum.迟到.getValue() == f.getOffWorkResult())
                .map(i->i.getStaffId())
                .distinct()
                .count();
        attendStatInfo.setBeLate(beLate);

        //早退次数
        long leaveEarly = attendanceRecordEntities.parallelStream()
                .flatMap(item -> item.getAttendanceRecordDetailList().stream())
                .filter(f -> GoWorkResultEnum.早退.getValue() == f.getGoWorkResult() || OffWorkResultEnum.早退.getValue() == f.getOffWorkResult())
                .map(i->i.getStaffId())
                .distinct()
                .count();
        attendStatInfo.setLeaveEarly(leaveEarly);

        //缺卡人数
        long lackOfCards = attendanceRecordEntities.parallelStream()
                .flatMap(item -> item.getAttendanceRecordDetailList().stream())
                .filter(f -> GoWorkResultEnum.缺卡.getValue() == f.getGoWorkResult() || OffWorkResultEnum.缺卡.getValue() == f.getOffWorkResult())
                .map(i->i.getStaffId())
                .distinct()
                .count();
        attendStatInfo.setLackOfCards(lackOfCards);
        //未考勤
        long noAtt = lackOfCards;
        long att = total - noAtt;

        if (att != 0L) {
            BigDecimal bigDecimal = new BigDecimal(att).divide(new BigDecimal(total)).multiply(new BigDecimal(100)).setScale(2, BigDecimal.ROUND_CEILING);
            attendStatInfo.setAttPercentage(bigDecimal.toString() + "%");
        } else {
            attendStatInfo.setAttPercentage("0%");
        }

        return Rest.ok(attendStatInfo);
    }
}
