package com.zhgd.xmgl.modules.basicdata.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.NumberUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zhgd.xmgl.async.AsyncAttendance;
import com.zhgd.xmgl.modules.basicdata.dto.WorkerInfoDto;
import com.zhgd.xmgl.modules.basicdata.entity.AttendanceStatistics;
import com.zhgd.xmgl.modules.basicdata.entity.WorkerInfo;
import com.zhgd.xmgl.modules.basicdata.entity.WorkerType;
import com.zhgd.xmgl.modules.basicdata.mapper.AttendanceStatisticsMapper;
import com.zhgd.xmgl.modules.basicdata.mapper.WorkerInfoMapper;
import com.zhgd.xmgl.modules.basicdata.mapper.WorkerTypeMapper;
import com.zhgd.xmgl.modules.basicdata.service.IWorkerInfoService;
import com.zhgd.xmgl.modules.basicdata.statistics.WorkerAttributeStat;
import com.zhgd.xmgl.modules.basicdata.statistics.WorkerInfoStat;
import com.zhgd.xmgl.util.ParamEnum;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Description: 人员
 * @author： pengj
 * @date：   2023-03-13
 * @version： V1.0
 */
@Service
public class WorkerInfoServiceImpl extends ServiceImpl<WorkerInfoMapper, WorkerInfo> implements IWorkerInfoService {

    @Autowired
    private WorkerTypeMapper workerTypeMapper;

    @Autowired
    private AttendanceStatisticsMapper attendanceStatisticsMapper;

    @Autowired
    private AsyncAttendance asyncAttendance;

    @Override
    public Page<WorkerInfoDto> getDetailPageList(Page page, Wrapper<WorkerInfo> wrapper) {
        Page<WorkerInfoDto> pageList = baseMapper.getDetailPageList(page, wrapper);
        for (WorkerInfoDto workerInfoDto : pageList.getRecords()) {
            workerInfoDto.setAge(DateUtil.ageOfNow(workerInfoDto.getBirthday()));
        }
        return pageList;
    }

    @Override
    public Page<WorkerInfo> getPageList(Page page, Wrapper<WorkerInfo> wrapper) {
        Page<WorkerInfo> pageList = baseMapper.selectPage(page, wrapper);
        for (WorkerInfo workerInfo : pageList.getRecords()) {
            workerInfo.setAge(DateUtil.ageOfNow(workerInfo.getBirthday()));
        }
        return pageList;
    }

    @Override
    public boolean updateInServiceType(Integer type, List<String> ids) {
        LambdaUpdateWrapper<WorkerInfo> wrapper = Wrappers.<WorkerInfo>lambdaUpdate();
        wrapper.set(WorkerInfo::getInServiceType, type);
        wrapper.in(WorkerInfo::getId, ids);
        return this.update(wrapper);
    }

    @Override
    public WorkerInfoStat statistics() {
        Map<String, Object> workerMap = baseMapper.statisticsMap();
        Integer total = MapUtils.getInteger(workerMap, "total");
        Integer inService = MapUtils.getInteger(workerMap, "inService");
        Integer man = MapUtils.getInteger(workerMap, "man");
        Integer inServiceMan = MapUtils.getInteger(workerMap, "inServiceMan");
        Integer woman = MapUtils.getInteger(workerMap, "woman");
        Integer inServiceWoman = MapUtils.getInteger(workerMap, "inServiceWoman");
        WorkerInfoStat workerInfoStat = new WorkerInfoStat();
        workerInfoStat.setWorkerNum(total);
        workerInfoStat.setInServiceWorkerNum(inService);
        // 工种统计
        List<WorkerType> workerTypes = workerTypeMapper.selectList(null);
        List<WorkerAttributeStat> workerType = baseMapper.statGroupByWorkerType();
        workerType.forEach(w -> {
            w.setAttribute(workerTypes.stream().filter(t -> t.getId().toString().equals(w.getAttribute())).findFirst().get().getTypeName());
            w.setRatio(total == 0 ? 0 : NumberUtil.round(w.getWorkerNum() * 100F / total, 2).floatValue());
        });
        // 地域统计
        workerInfoStat.setWorkerTypes(workerType);
        List<WorkerAttributeStat> workerRegister = baseMapper.statGroupByRegister();
        workerRegister.forEach(w -> {
            w.setRatio(total == 0 ? 0 : NumberUtil.round(w.getWorkerNum() * 100F / total, 2).floatValue());
        });
        workerInfoStat.setWorkerAddresses(workerRegister);
        // 民族统计
        List<WorkerAttributeStat> workerNations = baseMapper.statGroupByNation();
        workerNations.forEach(w -> {
            w.setRatio(total == 0 ? 0 : NumberUtil.round(w.getWorkerNum() * 100F / total, 2).floatValue());
        });
        workerInfoStat.setWorkerNations(workerNations);
        // 年龄分布统计
        List<WorkerInfo> workerByAge = baseMapper.statAge();
        List<WorkerAttributeStat> workerAge = new ArrayList<>();
        workerAge.add(age("20岁以下", 0, 20, workerByAge, total));
        workerAge.add(age("21-30岁", 21, 30, workerByAge, total));
        workerAge.add(age("31-50岁", 31, 50, workerByAge, total));
        workerAge.add(age("51-60岁", 51, 60, workerByAge, total));
        workerAge.add(age("60岁以上", 61, 200, workerByAge, total));
        workerInfoStat.setWorkerAge(workerAge);
        // 男女比例统计
        List<WorkerAttributeStat> workerSex = new ArrayList<>();
        workerSex.add(build("男性在册", man, inServiceMan, total));
        workerSex.add(build("女性在册", woman, inServiceWoman, total));
        workerInfoStat.setWorkerNations(workerSex);
        return workerInfoStat;
    }

    @Override
    public Map<String, Object> getByType() {
        return baseMapper.getByType();
    }

    @Override
    public Page<Map<String, Object>> attendanceStat(Page page, Map<String, Object> map) {
        String personName = MapUtils.getString(map, "personName");
        String teamName = MapUtils.getString(map, "teamName");
        String month = MapUtils.getString(map, "month");
        String engineeringSn = MapUtils.getString(map, "engineeringSn");
        String personType = MapUtils.getString(map, "personType");
        QueryWrapper<WorkerInfo> wrapper = Wrappers.<WorkerInfo>query();
        if (StringUtils.isNotBlank(personName)) {
            wrapper.like("w.person_name", personName);
        }
        if (StringUtils.isNotBlank(teamName)) {
            wrapper.like("t.team_name", teamName);
        }
        if (StringUtils.isNotBlank(personType)) {
            wrapper.eq("w.person_type", personType);
        }
        if (StringUtils.isNotBlank(engineeringSn)) {
            wrapper.like("w.engineering_sn", engineeringSn);
        }
        Page<Map<String, Object>> pageList = baseMapper.attendStat(page, wrapper);
        List<AttendanceStatistics> attendStatList = new ArrayList<>();
        if (pageList.getRecords().size() > 0) {
            attendStatList = attendanceStatisticsMapper.selectList(Wrappers.<AttendanceStatistics>lambdaQuery()
                    .in(AttendanceStatistics::getWorkerId, pageList.getRecords().stream().map(m -> m.get("id")).collect(Collectors.toList()))
                    .ge(AttendanceStatistics::getDayDate, month + "-01")
                    .le(AttendanceStatistics::getDayDate, month + "31"));
        }
        for (Map<String, Object> record : pageList.getRecords()) {
            record.put("lateDay", attendStatList.stream().filter(a -> a.getEntryState() == 2 && record.get("id").toString().equals(a.getWorkerId())).count());
            record.put("earlyDay", attendStatList.stream().filter(a -> a.getExitState() == 2 && record.get("id").toString().equals(a.getWorkerId())).count());
            int hourTotal = attendStatList.stream().filter(a -> record.get("id").toString().equals(a.getWorkerId())).mapToInt(AttendanceStatistics::getWorkHour).sum();
            record.put("workerHour", hourTotal / 60 + "时" + hourTotal % 60 + "分");
            for (int i = 1; i < 32; i++) {
                String time = i < 10 ? month + "-0" + i : month + i;
                List<AttendanceStatistics> attendanceStatistics = attendStatList.stream().filter(
                        a -> DateUtil.format(a.getDayDate(), "yyyy-MM-dd").equals(time)
                                && record.get("id").toString().equals(a.getWorkerId())).collect(Collectors.toList());
                record.put("day" + i, attendanceStatistics.size() == 0 ? 0 : attendanceStatistics.get(0).getEntryState());
            }
        }
        return pageList;
    }

    @Override
    public boolean saveInfo(WorkerInfo workerInfo) {
        workerInfo.setRegisterProvince(workerInfo.getRegisterAddress().substring(0, workerInfo.getRegisterAddress().indexOf("省") + 1));
        boolean flag = this.save(workerInfo);
        if (flag) {
            asyncAttendance.syncAttendanceWorker(ParamEnum.SysDictType.ATTEND_WORKER_ADD_API.getValue(), workerInfo);
        }
        return flag;
    }

    @Override
    public boolean updateInfo(WorkerInfo workerInfo) {
        workerInfo.setRegisterProvince(workerInfo.getRegisterAddress().substring(0, workerInfo.getRegisterAddress().indexOf("省") + 1));
        return this.updateById(workerInfo);
    }

    @Override
    public boolean delInfo(WorkerInfo workerInfo) {
        boolean flag = this.removeById(workerInfo.getId());
        if (flag) {
            asyncAttendance.syncAttendanceWorker(ParamEnum.SysDictType.ATTEND_WORKER_DEL_API.getValue(), workerInfo);
        }
        return flag;
    }

    private WorkerAttributeStat age(String attribute, Integer start, Integer end,  List<WorkerInfo> workerByAge, Integer workerSum) {
        int num = workerByAge.stream().filter(w -> start <= DateUtil.ageOfNow(w.getBirthday())
                && DateUtil.ageOfNow(w.getBirthday()) <= end).collect(Collectors.toList()).size();
        int inServiceNum = workerByAge.stream().filter(w -> start <= DateUtil.ageOfNow(w.getBirthday())
                && DateUtil.ageOfNow(w.getBirthday()) <= end && w.getInServiceType() == 1).collect(Collectors.toList()).size();
        return build(attribute, num, inServiceNum, workerSum);
    }

    private WorkerAttributeStat build(String attribute, Integer workerNum, Integer inServiceWorkerNum, Integer workerSum) {
        WorkerAttributeStat workerAttributeStat = new WorkerAttributeStat();
        workerAttributeStat.setAttribute(attribute);
        workerAttributeStat.setWorkerNum(workerNum);
        workerAttributeStat.setInServiceWorkerNum(inServiceWorkerNum);
        workerAttributeStat.setRatio(workerSum == 0 ? 0 : NumberUtil.round(workerNum * 100F / workerSum, 2).floatValue());
        workerAttributeStat.setInServiceRatio(workerSum == 0 ? 0 : NumberUtil.round(inServiceWorkerNum * 100F / workerSum, 2).floatValue());
        return workerAttributeStat;
    }
}
