package com.yida.data.attendance.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
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.yida.data.attendance.dto.StaffRuleDTO;
import com.yida.data.attendance.mapper.EduAttendanceStaffRuleMapper;
import com.yida.data.attendance.service.*;
import com.yida.data.attendance.vo.FindStaffRuleVO;
import com.yida.data.attendance.vo.StaffRuleVO;
import com.yida.data.common.core.entity.attendance.*;
import com.yida.data.common.core.entity.user.EduStaff;
import com.yida.data.common.core.exception.FebsException;
import com.yida.data.common.core.utils.Asserts;
import com.yida.data.user.dto.ListStaffDTO;
import com.yida.data.user.feign.RemoteStaffService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 教职工考勤规则 Service实现
 *
 * @author ccl
 * @date 2021-09-27 18:56:21
 */
@Service
@RequiredArgsConstructor
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class EduAttendanceStaffRuleServiceImpl extends ServiceImpl
        <EduAttendanceStaffRuleMapper, EduAttendanceStaffRule> implements EduAttendanceStaffRuleService {

    private static final String JOB_BEAN_NAME = "AttendanceTask";
    private static final String JOB_METHOD_NAME = "remindClock";

    private final EduAttendanceStaffRuleObjService eduAttendanceStaffRuleObjService;
    private final EduAttendanceStaffRuleAdminService eduAttendanceStaffRuleAdminService;
    private final EduAttendanceStaffRuleStaffService eduAttendanceStaffRuleStaffService;
    private final EduAttendanceStaffRuleRemindService eduAttendanceStaffRuleRemindService;
    private final EduAttendanceStaffRuleWhiteListService eduAttendanceStaffRuleWhiteListService;
    private final EduAttendanceStaffRuleSpecialDateService eduAttendanceStaffRuleSpecialDateService;
    private final EduAttendanceStaffRuleTimeService eduAttendanceStaffRuleTimeService;
    private final EduAttendanceStaffRuleAdminRangeService eduAttendanceStaffRuleAdminRangeService;
    private final EduAttendanceStaffRuleDeviceService eduAttendanceStaffRuleDeviceService;

    private final RemoteStaffService remoteStaffService;

    @Override
    public IPage<StaffRuleVO> findStaffRuleList(IPage iPage, String ruleName, String staffName, Long schoolId) {

        List<Long> ruleIds = new ArrayList<>();
        if (staffName != null) {
            List<EduStaff> data = remoteStaffService.listStaff(ListStaffDTO.builder().name(staffName).schoolId(schoolId).build())
                    .getData();
            if (CollectionUtil.isEmpty(data)) {
                return new Page();
            }
            List<Long> staffId = new ArrayList<>();
            for (EduStaff datum : data) {
                staffId.add(datum.getId());
            }
            List<EduAttendanceStaffRuleAdmin> list = eduAttendanceStaffRuleAdminService
                    .list(Wrappers.lambdaQuery(new EduAttendanceStaffRuleAdmin())
                            .in(EduAttendanceStaffRuleAdmin::getStaffId, staffId));
            for (EduAttendanceStaffRuleAdmin staffRuleAdmin : list) {
                ruleIds.add(staffRuleAdmin.getRuleId());
            }
            if (CollectionUtil.isEmpty(ruleIds)) {
                return new Page();
            }
        }

        IPage<StaffRuleVO> staffRuleList = baseMapper.findStaffRuleList(iPage, ruleName, schoolId, ruleIds);
        List<StaffRuleVO> records = staffRuleList.getRecords();
        if (CollectionUtil.isEmpty(records)) {
            return staffRuleList;
        }

        for (StaffRuleVO record : records) {
            List<Long> staffList = record.getStaffList();
            if (CollectionUtil.isNotEmpty(staffList)) {
                List<EduStaff> data =
                        remoteStaffService.listStaff(ListStaffDTO.builder().ids(staffList).build()).getData();
                List<String> name = new ArrayList<>();
                for (EduStaff staff : data) {
                    name.add(staff.getName());
                }
                record.setStaffNameList(name);
            }
        }
        return staffRuleList;
    }

    @Override
    public FindStaffRuleVO findStaffRule(Long ruleId) {

        FindStaffRuleVO staffRuleVO = baseMapper.findStaffRuleById(ruleId);

        //添加使用人员名称
        List<EduAttendanceStaffRuleObj> list = eduAttendanceStaffRuleObjService
                .list(Wrappers.lambdaQuery(new EduAttendanceStaffRuleObj())
                        .eq(EduAttendanceStaffRuleObj::getRuleId, ruleId));
        List<Long> objIds = new ArrayList<>();
        for (EduAttendanceStaffRuleObj obj : list) {
            objIds.add(obj.getObjId());
        }
        if (CollectionUtil.isNotEmpty(objIds)) {
            List<EduAttendanceStaffRuleObj> objNames = new ArrayList<>();
            List<EduStaff> objs =
                    remoteStaffService.listStaff(ListStaffDTO.builder().ids(objIds).build()).getData();
            for (EduStaff staff : objs) {
                EduAttendanceStaffRuleObj obj = new EduAttendanceStaffRuleObj();
                obj.setObjId(staff.getId());
                obj.setObjName(staff.getName());
                objNames.add(obj);
            }
            staffRuleVO.setObjStaffs(objNames);
        }

        //添加管理人员名称
        List<Long> staffIds = new ArrayList<>();
        List<EduAttendanceStaffRuleAdmin> admins = eduAttendanceStaffRuleAdminService
                .list(Wrappers.lambdaQuery(new EduAttendanceStaffRuleAdmin())
                        .eq(EduAttendanceStaffRuleAdmin::getRuleId, ruleId));
        for (EduAttendanceStaffRuleAdmin admin : admins) {
            staffIds.add(admin.getStaffId());
        }

        if (CollectionUtil.isNotEmpty(staffIds)) {
            List<EduAttendanceStaffRuleAdmin> staffName = new ArrayList<>();
            List<EduStaff> staffs =
                    remoteStaffService.listStaff(ListStaffDTO.builder().ids(staffIds).build()).getData();

            for (EduStaff staff : staffs) {
                EduAttendanceStaffRuleAdmin admin = new EduAttendanceStaffRuleAdmin();
                admin.setStaffId(staff.getId());
                admin.setStaffName(staff.getName());
                staffName.add(admin);
            }
            staffRuleVO.setAdminStaffs(staffName);
        }
        //白名单
        List<Long> whiteListId = new ArrayList<>();
        List<EduAttendanceStaffRuleWhiteList> whiteList = eduAttendanceStaffRuleWhiteListService
                .list(Wrappers.lambdaQuery(new EduAttendanceStaffRuleWhiteList())
                        .eq(EduAttendanceStaffRuleWhiteList::getRuleId, ruleId));
        for (EduAttendanceStaffRuleWhiteList white : whiteList) {
            whiteListId.add(white.getStaffId());
        }

        if (CollectionUtil.isNotEmpty(whiteListId)) {
            List<EduStaff> whiteStaff =
                    remoteStaffService.listStaff(ListStaffDTO.builder().ids(whiteListId).build()).getData();

            List<EduAttendanceStaffRuleWhiteList> whiteLists = new ArrayList<>();
            for (EduStaff staff : whiteStaff) {
                EduAttendanceStaffRuleWhiteList white = new EduAttendanceStaffRuleWhiteList();
                white.setStaffId(staff.getId());
                white.setStaffName(staff.getName());
                whiteLists.add(white);
            }
            staffRuleVO.setWhiteList(whiteLists);
        }

        //管理范围
        List<Long> rangeList = new ArrayList<>();
        List<EduAttendanceStaffRuleAdminRange> ranges = eduAttendanceStaffRuleAdminRangeService
                .list(Wrappers.lambdaQuery(new EduAttendanceStaffRuleAdminRange())
                        .eq(EduAttendanceStaffRuleAdminRange::getRuleId, ruleId));
        for (EduAttendanceStaffRuleAdminRange range : ranges) {
            rangeList.add(range.getStaffId());
        }
        if (CollectionUtil.isNotEmpty(rangeList)) {
            List<EduStaff> rangeStaff =
                    remoteStaffService.listStaff(ListStaffDTO.builder().ids(rangeList).build()).getData();
            List<EduAttendanceStaffRuleAdminRange> rangeName = new ArrayList<>();
            for (EduStaff staff : rangeStaff) {
                EduAttendanceStaffRuleAdminRange adminRange = new EduAttendanceStaffRuleAdminRange();
                adminRange.setStaffId(staff.getId());
                adminRange.setStaffName(staff.getName());
                rangeName.add(adminRange);
            }
            staffRuleVO.setAdminRanges(rangeName);
        }

        //打卡时段
        List<EduAttendanceStaffRuleTime> times = eduAttendanceStaffRuleTimeService
                .list(Wrappers.lambdaQuery(new EduAttendanceStaffRuleTime())
                        .eq(EduAttendanceStaffRuleTime::getRuleId, ruleId));
        staffRuleVO.setRuleTimes(times);

        //特殊时段
        List<EduAttendanceStaffRuleSpecialDate> specialDates = eduAttendanceStaffRuleSpecialDateService
                .list(Wrappers.lambdaQuery(new EduAttendanceStaffRuleSpecialDate())
                        .eq(EduAttendanceStaffRuleSpecialDate::getRuleId, ruleId));
        staffRuleVO.setSpecialDate(specialDates);

        //打卡提醒
        List<EduAttendanceStaffRuleRemind> ruleReminds = eduAttendanceStaffRuleRemindService
                .list(Wrappers.lambdaQuery(new EduAttendanceStaffRuleRemind())
                        .eq(EduAttendanceStaffRuleRemind::getRuleId, ruleId));
        staffRuleVO.setRuleReminds(ruleReminds);

        // 打卡设备
        List<EduAttendanceStaffRuleDevice> staffRuleDeviceList = eduAttendanceStaffRuleDeviceService
                .selectStaffRuleDeviceList(ruleId);
        if (CollUtil.isNotEmpty(staffRuleDeviceList)) {
            staffRuleVO.setRuleDevices(
                    staffRuleDeviceList.stream().map(EduAttendanceStaffRuleDevice::getDeviceId).collect(Collectors.toList()));
        }

        return staffRuleVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpStaffRule(StaffRuleDTO staffRuleDTO) {

        EduAttendanceStaffRule staffRule = new EduAttendanceStaffRule();
        staffRule.setId(staffRuleDTO.getId());
        staffRule.setHolidayAttendance(staffRuleDTO.getHolidayAttendance());
        staffRule.setName(staffRuleDTO.getName());
        staffRule.setRoleDate(staffRuleDTO.getRoleDate());
        staffRule.setRoleRemind(staffRuleDTO.getRoleRemind());
        staffRule.setRoleRule(staffRuleDTO.getRoleRule());
        staffRule.setRoleUser(staffRuleDTO.getRoleUser());
        staffRule.setSchoolId(staffRuleDTO.getSchoolId());
        staffRule.setType(staffRuleDTO.getType());
        staffRule.setWeek(staffRuleDTO.getWeek());

        List<EduAttendanceStaffRuleStaff> ruleStaffs = staffRuleDTO.getRuleStaffs();
        ArrayList<Long> staffList = new ArrayList<>();
        for (EduAttendanceStaffRuleStaff ruleStaff : ruleStaffs) {
            staffList.add(ruleStaff.getStaffId());
        }
        List<EduAttendanceStaffRuleObj> list1 = eduAttendanceStaffRuleObjService
                .list(Wrappers.lambdaQuery(new EduAttendanceStaffRuleObj())
                        .in(EduAttendanceStaffRuleObj::getObjId, staffList));

        if (staffRule.getId() == null) {
            if (CollUtil.isNotEmpty(list1)) {
                StringBuilder staffNames = new StringBuilder("员工名单:");
                List<Long> longs = new ArrayList<>();
                for (EduAttendanceStaffRuleObj obj : list1) {
                    longs.add(obj.getObjId());
                }
                List<EduStaff> data =
                        remoteStaffService.listStaff(ListStaffDTO.builder().ids(longs).build()).getData();
                for (EduStaff datum : data) {
                    staffNames.append(",").append(datum.getName());
                }

                throw new FebsException("有员工已有对应考勤规则，请调整设置。" + staffNames);
            }
        }
        List<EduAttendanceStaffRuleAdmin> adminStaffs = staffRuleDTO.getAdminStaffs();
        List<EduAttendanceStaffRuleObj> objStaffs = staffRuleDTO.getObjStaffs();
        List<EduAttendanceStaffRuleAdminRange> adminRanges = staffRuleDTO.getAdminRanges();
        List<EduAttendanceStaffRuleRemind> ruleReminds = staffRuleDTO.getRuleReminds();
        List<EduAttendanceStaffRuleWhiteList> whiteList = staffRuleDTO.getWhiteList();
        List<EduAttendanceStaffRuleSpecialDate> specialDate = staffRuleDTO.getSpecialDate();
        List<EduAttendanceStaffRuleTime> ruleTimes = staffRuleDTO.getRuleTimes();
        List<Long> ruleDevices = staffRuleDTO.getRuleDevices();

        //修改时，先删除对应所有关联信息再新增
        if (staffRule.getId() != null) {
            eduAttendanceStaffRuleObjService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleObj())
                    .eq(EduAttendanceStaffRuleObj::getRuleId, staffRule.getId()));
            eduAttendanceStaffRuleAdminService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleAdmin())
                    .eq(EduAttendanceStaffRuleAdmin::getRuleId, staffRule.getId()));
            eduAttendanceStaffRuleStaffService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleStaff())
                    .eq(EduAttendanceStaffRuleStaff::getRuleId, staffRule.getId()));
            eduAttendanceStaffRuleAdminRangeService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleAdminRange())
                    .eq(EduAttendanceStaffRuleAdminRange::getRuleId, staffRule.getId()));
            eduAttendanceStaffRuleRemindService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleRemind())
                    .eq(EduAttendanceStaffRuleRemind::getRuleId, staffRule.getId()));
            eduAttendanceStaffRuleWhiteListService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleWhiteList())
                    .eq(EduAttendanceStaffRuleWhiteList::getRuleId, staffRule.getId()));
            eduAttendanceStaffRuleSpecialDateService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleSpecialDate())
                    .eq(EduAttendanceStaffRuleSpecialDate::getRuleId, staffRule.getId()));
            eduAttendanceStaffRuleTimeService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleTime())
                    .eq(EduAttendanceStaffRuleTime::getRuleId, staffRule.getId()));
            // 删除教师考勤规则关联设备
            eduAttendanceStaffRuleDeviceService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleDevice())
                    .eq(EduAttendanceStaffRuleDevice::getRuleId, staffRule.getId()));
        }

        //校验职工所属规则唯一
        List<Long> staffId = new ArrayList<>();
        for (EduAttendanceStaffRuleObj objStaff : objStaffs) {
            staffId.add(objStaff.getRuleId());
        }

        List<EduAttendanceStaffRuleStaff> list = eduAttendanceStaffRuleStaffService
                .list(Wrappers.lambdaQuery(new EduAttendanceStaffRuleStaff())
                        .in(EduAttendanceStaffRuleStaff::getStaffId, staffId));

        Asserts.isNotNull(CollectionUtil.isNotEmpty(list), "有教职工已有对应考勤规则");

        saveOrUpdate(staffRule);

        //整理使用人员
        for (EduAttendanceStaffRuleObj objStaff : objStaffs) {
            objStaff.setRuleId(staffRule.getId());
        }
        //整理管理人员
        for (EduAttendanceStaffRuleAdmin adminStaff : adminStaffs) {
            adminStaff.setRuleId(staffRule.getId());
        }
        //整理管理人员
        for (EduAttendanceStaffRuleStaff ruleStaff : ruleStaffs) {
            ruleStaff.setRuleId(staffRule.getId());
        }
        //整理管理范围
        for (EduAttendanceStaffRuleAdminRange adminRange : adminRanges) {
            adminRange.setRuleId(staffRule.getId());
        }
        //整理提醒列表
        for (EduAttendanceStaffRuleRemind ruleRemind : ruleReminds) {
            ruleRemind.setRuleId(staffRule.getId());
        }
        //整理白名单
        if (CollectionUtil.isNotEmpty(whiteList)) {
            for (EduAttendanceStaffRuleWhiteList eduAttendanceStaffRuleWhiteList : whiteList) {
                eduAttendanceStaffRuleWhiteList.setRuleId(staffRule.getId());
            }
            eduAttendanceStaffRuleWhiteListService.saveBatch(whiteList);
        }

        //整理特殊时间
        for (EduAttendanceStaffRuleSpecialDate eduAttendanceStaffRuleSpecialDate : specialDate) {
            // 时间为空不保存
            if (Objects.nonNull(eduAttendanceStaffRuleSpecialDate.getDate())) {
                eduAttendanceStaffRuleSpecialDate.setRuleId(staffRule.getId());
                eduAttendanceStaffRuleSpecialDateService.save(eduAttendanceStaffRuleSpecialDate);
            }
        }
        //整理打卡时间段
        for (EduAttendanceStaffRuleTime ruleTime : ruleTimes) {
            ruleTime.setRuleId(staffRule.getId());
        }
        // 设置教师考勤规则设备数据
        List<EduAttendanceStaffRuleDevice> staffRuleDeviceList = new ArrayList<>();
        for (Long deviceId : ruleDevices) {
            EduAttendanceStaffRuleDevice staffRuleDevice = new EduAttendanceStaffRuleDevice();
            staffRuleDevice.setRuleId(staffRule.getId());
            staffRuleDevice.setDeviceId(deviceId);
            staffRuleDeviceList.add(staffRuleDevice);
        }

        eduAttendanceStaffRuleObjService.saveBatch(objStaffs);
        eduAttendanceStaffRuleAdminService.saveBatch(adminStaffs);
        eduAttendanceStaffRuleStaffService.saveBatch(ruleStaffs);
        eduAttendanceStaffRuleAdminRangeService.saveBatch(adminRanges);
        eduAttendanceStaffRuleRemindService.saveBatch(ruleReminds);
//        eduAttendanceStaffRuleSpecialDateService.saveBatch(specialDate);
        eduAttendanceStaffRuleTimeService.saveBatch(ruleTimes);
        // 保存教师考勤规则关联设设备
        eduAttendanceStaffRuleDeviceService.saveBatch(staffRuleDeviceList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeStaffRule(Long ruleId) {

        removeById(ruleId);
        eduAttendanceStaffRuleObjService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleObj())
                .eq(EduAttendanceStaffRuleObj::getRuleId, ruleId));
        eduAttendanceStaffRuleAdminService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleAdmin())
                .eq(EduAttendanceStaffRuleAdmin::getRuleId, ruleId));
        eduAttendanceStaffRuleStaffService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleStaff())
                .eq(EduAttendanceStaffRuleStaff::getRuleId, ruleId));
        eduAttendanceStaffRuleAdminRangeService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleAdminRange())
                .eq(EduAttendanceStaffRuleAdminRange::getRuleId, ruleId));
        eduAttendanceStaffRuleRemindService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleRemind())
                .eq(EduAttendanceStaffRuleRemind::getRuleId, ruleId));
        eduAttendanceStaffRuleWhiteListService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleWhiteList())
                .eq(EduAttendanceStaffRuleWhiteList::getRuleId, ruleId));
        eduAttendanceStaffRuleSpecialDateService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleSpecialDate())
                .eq(EduAttendanceStaffRuleSpecialDate::getRuleId, ruleId));
        eduAttendanceStaffRuleTimeService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleTime())
                .eq(EduAttendanceStaffRuleTime::getRuleId, ruleId));
        // 删除教师考勤规则关联设备
        eduAttendanceStaffRuleDeviceService.remove(Wrappers.lambdaQuery(new EduAttendanceStaffRuleDevice())
                .eq(EduAttendanceStaffRuleDevice::getRuleId, ruleId));
    }

    @Override
    public FindStaffRuleVO selectMatchStaffRule(EduAttendanceStaffRecord staffRecord) {
        FindStaffRuleVO staffRuleVO = baseMapper.selectMatchStaffRule(staffRecord);
        if (Objects.nonNull(staffRuleVO)) {
            // 查询打卡时间段
            List<EduAttendanceStaffRuleTime> times = eduAttendanceStaffRuleTimeService
                    .list(Wrappers.lambdaQuery(new EduAttendanceStaffRuleTime())
                            .eq(EduAttendanceStaffRuleTime::getRuleId, staffRuleVO.getId()));
            staffRuleVO.setRuleTimes(times);
            // 查询白名单
            List<EduAttendanceStaffRuleWhiteList> whiteList = eduAttendanceStaffRuleWhiteListService
                    .list(Wrappers.lambdaQuery(new EduAttendanceStaffRuleWhiteList())
                            .eq(EduAttendanceStaffRuleWhiteList::getRuleId, staffRuleVO.getId()));
            staffRuleVO.setWhiteList(whiteList);
            // 查询特殊节日
            List<EduAttendanceStaffRuleSpecialDate> specialDateList = eduAttendanceStaffRuleSpecialDateService.list(Wrappers.lambdaQuery(new EduAttendanceStaffRuleSpecialDate())
                    .eq(EduAttendanceStaffRuleSpecialDate::getRuleId, staffRuleVO.getId()));
            staffRuleVO.setSpecialDate(specialDateList);
        }
        return staffRuleVO;
    }
}
