package jnpf.attendance.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.extension.plugins.pagination.PageDTO;
import com.google.common.collect.Maps;
import com.nlf.calendar.Holiday;
import com.nlf.calendar.util.HolidayUtil;
import jnpf.attendance.mapper.AttendanceFestivalSettingMapper;
import jnpf.attendance.service.AttendanceFestivalSettingService;
import jnpf.attendance.service.AttendanceGroupService;
import jnpf.attendance.service.AttendanceHolidaySettingService;
import jnpf.base.UserInfo;
import jnpf.base.service.SuperServiceImpl;
import jnpf.entity.AttendanceGroup;
import jnpf.entity.attendance.AttendanceFestivalSettingEntity;
import jnpf.entity.attendance.AttendanceHolidaySettingEntity;
import jnpf.exception.HandleException;
import jnpf.model.attendance.dto.AttendanceFestivalSettingDto;
import jnpf.model.attendance.vo.AttendanceFestivalSettingVo;
import jnpf.model.attendance.vo.AttendanceGroupVo;
import jnpf.model.attendance.vo.HolidayOptionVo;
import jnpf.util.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * <p>
 * 考勤配置-节日配置 服务实现类
 * </p>
 *
 * @author ahua
 * @since 2023-11-29
 */
@Service
@Slf4j
public class AttendanceFestivalSettingServiceImpl extends SuperServiceImpl<AttendanceFestivalSettingMapper, AttendanceFestivalSettingEntity> implements AttendanceFestivalSettingService {

    @Autowired
    private AttendanceHolidaySettingService attendanceHolidaySettingService;
    @Autowired
    private AttendanceGroupService attendanceGroupService;

    @Override
    @Transactional
    public void save(AttendanceFestivalSettingDto attendanceFestivalSettingDto) throws HandleException {
        synchronized (attendanceFestivalSettingDto.getGroupId()) {
            AttendanceFestivalSettingEntity entity = BeanUtil.toBean(attendanceFestivalSettingDto, AttendanceFestivalSettingEntity.class);
            UserInfo user = UserProvider.getUser();
            if (StringUtil.isNull(entity.getId())) {
                List<AttendanceFestivalSettingEntity> list = lambdaQuery()
                        .eq(AttendanceFestivalSettingEntity::getName, entity.getName())
                        .eq(AttendanceFestivalSettingEntity::getGroupId, attendanceFestivalSettingDto.getGroupId())
                        .eq(AttendanceFestivalSettingEntity::getDeleteMark, Boolean.FALSE)
                        .list();
                Assert.isFalse(CollUtil.isNotEmpty(list),"节日名称不能重复");
                entity.setCreatorTime(new Date());
                entity.setCreatorUserId(user.getUserId());
                entity.setTenantId(user.getTenantId());
            } else {
                entity.setLastModifyTime(new Date());
                entity.setLastModifyUserId(user.getUserId());
            }
            AttendanceFestivalSettingEntity byId = getById(attendanceFestivalSettingDto.getId());
            saveOrUpdate(entity);
            entity.setEnable(Objects.isNull(byId) ? 0 : byId.getEnable());
            autoRest(entity, byId);
        }
    }

    private void autoRest(AttendanceFestivalSettingEntity entity, AttendanceFestivalSettingEntity hisFestivalSetting) throws HandleException {
        if (Objects.equals(entity.getEnable(), 0)) {
            return;
        }
        if (!Objects.equals(entity.getDistributeType(), 0)) {
            return;
        }
        String groupId = entity.getGroupId();
        Date start = new Date();
        Date end = DateUtil.getEndDayOfMonth();
        List<AttendanceGroup> attendanceGroups = attendanceGroupService.queryDropList();
        AttendanceGroup attendanceGroup = attendanceGroups.stream().filter(group -> StringUtil.equals(groupId, group.getId())).reduce((g1, g2) -> g1).orElse(null);
        if (Objects.isNull(attendanceGroup)) {
            log.error("未查询到当前考勤组");
            throw new HandleException("未查询到当前考勤组");
        }
        if (Objects.equals(attendanceGroup.getFestivalSetting(), 0)) {
            return;
        }
        List<Date> dateList = Arrays.stream(entity.getFestivalDate().split(",")).map(DateDetail::getStr2Date10).collect(Collectors.toList());
        List<Date> collect1 = dateList.stream().filter(date -> DateUtil.getDayEnd().after(date)).collect(Collectors.toList());
        if (CollUtil.isNotEmpty(collect1)) {
            throw new HandleException("请选择大于今天的节日日期");
        }
        HashMap<String, List<AttendanceFestivalSettingEntity>> objectObjectHashMap = Maps.newHashMap();
        List<AttendanceGroupVo> enableGroup = getEnableGroup(groupId);
        List<String> collect = enableGroup.stream().map(AttendanceGroupVo::getId).collect(Collectors.toList());
        collect.add(groupId);
        for (String group : collect) {
            objectObjectHashMap.put(group, CollUtil.newArrayList(entity));
        }
//        attendanceDailyRuleService.addHolidayDailyRule(groupId, start, end, attendanceGroups, objectObjectHashMap, hisFestivalSetting);
    }

    @Override
    public PageDTO<AttendanceFestivalSettingVo> page(String groupId, String year, Integer page, Integer size) throws HandleException {
        if (StringUtil.isEmpty(year)) {
            throw new HandleException("请选择年份");
        }
        List<AttendanceGroup> attendanceGroups = attendanceGroupService.queryDropList();
        Map<String, AttendanceGroup> collect = attendanceGroups.stream().collect(Collectors.toMap(AttendanceGroup::getId, group -> group));
        Map<String, String> groupIdToParent = attendanceGroups.stream().collect(Collectors.toMap(AttendanceGroup::getId, groupVo -> StringUtil.isBlank(groupVo.getParentId()) ? "-1" : groupVo.getParentId()));
        PageDTO<AttendanceFestivalSettingVo> attendanceFestivalSettingVoPageDTO = upPage(groupId, groupIdToParent, collect, year, page, size);
        if (Objects.isNull(attendanceFestivalSettingVoPageDTO)) {
            return new PageDTO<>(page, size);
        }
        return attendanceFestivalSettingVoPageDTO;
    }

    private PageDTO<AttendanceFestivalSettingVo> upPage(String groupId, Map<String, String> groupIdToParent, Map<String, AttendanceGroup> collect, String year, Integer page, Integer size) {
        if (StringUtil.isEmpty(groupId)) {
            return null;
        }
        AttendanceGroup attendanceGroup = collect.get(groupId);
        if (Objects.isNull(attendanceGroup)) {
            return null;
        }
        if (Objects.equals(attendanceGroup.getFestivalSetting(), 1)) {
            PageDTO<AttendanceFestivalSettingEntity> page1 = lambdaQuery()
                    .likeRight(AttendanceFestivalSettingEntity::getEndDate, year)
                    .eq(AttendanceFestivalSettingEntity::getGroupId, groupId)
                    .eq(AttendanceFestivalSettingEntity::getDeleteMark, Boolean.FALSE)
                    .orderByAsc(AttendanceFestivalSettingEntity::getStatutoryEnable, AttendanceFestivalSettingEntity::getDay)
                    .page(new PageDTO<>(page, size));
            return (PageDTO<AttendanceFestivalSettingVo>) page1.convert(x -> BeanUtil.toBean(x, AttendanceFestivalSettingVo.class));
        }
        return upPage(groupIdToParent.get(groupId), groupIdToParent, collect, year, page, size);
    }

    @Override
    public AttendanceFestivalSettingVo getOne(String id) {
        AttendanceFestivalSettingEntity one = lambdaQuery().eq(AttendanceFestivalSettingEntity::getId, id)
                .eq(AttendanceFestivalSettingEntity::getDeleteMark, Boolean.FALSE)
                .one();
        return BeanUtil.toBean(one, AttendanceFestivalSettingVo.class);
    }

    @Override
    public void del(String id) {
        lambdaUpdate().set(AttendanceFestivalSettingEntity::getDeleteMark, Boolean.TRUE)
                .set(AttendanceFestivalSettingEntity::getDeleteUserId, UserProvider.getLoginUserId())
                .set(AttendanceFestivalSettingEntity::getDeleteTime, new Date())
                .eq(AttendanceFestivalSettingEntity::getId, id)
                .update();
    }

    @Override
    public Map<String, List<AttendanceFestivalSettingEntity>> getEnableFestivalSetting(List<String> groupIds, List<AttendanceGroup> attendanceGroupVos) {
        return getEnableFestivalSetting(groupIds,attendanceGroupVos, Boolean.TRUE);
    }

    private Map<String, List<AttendanceFestivalSettingEntity>> getEnableFestivalSetting(List<String> groupIds, List<AttendanceGroup> attendanceGroupVos, Boolean isFilterDisable) {
        List<AttendanceFestivalSettingEntity> list = lambdaQuery().eq(isFilterDisable, AttendanceFestivalSettingEntity::getEnable, Boolean.TRUE)
                .eq(AttendanceFestivalSettingEntity::getDeleteMark, Boolean.FALSE)
                .list();
        Map<String, Boolean> collect1 = attendanceGroupVos.stream().collect(Collectors.toMap(AttendanceGroup::getId, group -> group.getFestivalSetting() == 1));
        Map<String, List<AttendanceFestivalSettingEntity>> collect = list.stream().filter(base -> collect1.getOrDefault(base.getGroupId(), Boolean.FALSE)).collect(Collectors.groupingBy(AttendanceFestivalSettingEntity::getGroupId));
        Map<String, List<AttendanceFestivalSettingEntity>> map = Maps.newHashMap();
        Map<String, String> groupIdToParent = attendanceGroupVos.stream().collect(Collectors.toMap(AttendanceGroup::getId, groupVo -> StringUtil.isBlank(groupVo.getParentId()) ? "-1" : groupVo.getParentId()));
        groupIds.forEach(groupId -> map.put(groupId, findNextBaseSetting(collect, groupIdToParent, groupId)));
        return map;
    }

//    @Override
//    @Deprecated(since = "在2.0中已过期", forRemoval = true)
//    public void autoGrantBalance() {
//        log.error("开始节日自动发放劵");
//        List<AttendanceGroup> attendanceGroups = attendanceGroupService.queryDropList();
//        List<String> groupIds = attendanceGroups.stream().map(AttendanceGroup::getId).collect(Collectors.toList());
//        Map<String, List<AttendanceFestivalSettingEntity>> enableFestivalSetting = getEnableFestivalSetting(groupIds, attendanceGroups);
//        List<AttendanceGroupUser> attendanceGroupUsers = attendanceUserService.queryByUsersGroupIds(groupIds);
//        Map<String, List<AttendanceGroupUser>> collect = attendanceGroupUsers.stream().collect(Collectors.groupingBy(AttendanceGroupUser::getGroupId));
//        enableFestivalSetting.forEach((groupId, list) -> {
//            List<AttendanceGroupUser> attendanceGroupUsers1 = collect.get(groupId);
//            if (CollUtil.isEmpty(attendanceGroupUsers1)) {
//                return;
//            }
//            if (CollUtil.isEmpty(list)) {
//                return;
//            }
//            list.forEach(setting -> {
//                if (!Objects.equals(setting.getDistributeType(), 1)) {
//                    return;
//                }
//                attendanceGroupUsers1.forEach(user -> {
//                    Date date = DateUtil.getDayBegin();
//                    Date dateByMonthAndDay;
//                    if (setting.getGiveType() == 1) {
//                        dateByMonthAndDay = DateDetail.getDateByMonthAndDay(date, date.getMonth() + 1, setting.getGiveDay());
//                    } else {
//                        dateByMonthAndDay = DateDetail.getDateByMonthAndDay(date, setting.getGiveMonth(), setting.getGiveDay());
//                    }
//                    if (date.compareTo(dateByMonthAndDay) != 0) {
//                        return;
//                    }
//                    if (setting.getExpiresType() == 1) {
//                        Integer expiresDay = setting.getExpiresDayNumber();
//                        date = DateUtil.dateAddDays(date, expiresDay);
//                    } else if (Objects.equals(setting.getExpiresType(), 2)) {
//                        date = DateDetail.getDateByMonthAndDay(date, setting.getExpiresMonth(), setting.getExpiresDay());
//                    } else {
//                        date = null;
//                    }
//                    BigDecimal dayNum = new BigDecimal(setting.getDay());
//                    log.error("考勤组[{}]节日[{}]自动发放劵[{}]", user.getGroupId(), setting.getName(), dayNum);
//                    attendanceBalanceRecordMapper.grantBalance(RandomUtil.uuId(), user.getUserId(), setting.getName(), dayNum, date, 2, 0, null, setting.getPaidSalaryEnable(), 1, setting.getId());
//                });
//            });
//        });
//        log.error("节日自动发放劵结束");
//    }

    private List<AttendanceGroupVo> getEnableGroup(String groupId) {
        List<AttendanceGroup> attendanceGroupVos = attendanceGroupService.queryDropList();
        if (CollUtil.isEmpty(attendanceGroupVos)) {
            log.error("未查询到考勤组信息");
            return CollUtil.newArrayList();
        }
        AttendanceGroup attendanceGroup = attendanceGroupVos.stream().filter(group -> StringUtil.equals(group.getId(), groupId)).reduce((g1, g2) -> g1).orElse(null);
        if (Objects.equals(attendanceGroup.getFestivalSetting(), 0)) {
            log.error("当前考勤组未开启节日配置");
            return CollUtil.newArrayList();
        }
        Map<String, List<AttendanceGroup>> groupIdToParent = attendanceGroupVos.stream().collect(Collectors.groupingBy(AttendanceGroup::getParentId));
        List<AttendanceGroupVo> groupVos = CollUtil.newArrayList();
        List<AttendanceGroup> orDefault = groupIdToParent.getOrDefault(groupId, CollUtil.newArrayList());
        if (CollUtil.isEmpty(orDefault)) {
            return CollUtil.newArrayList();
        }
        getEnableSingleGroup(orDefault, groupVos, groupIdToParent);
        return groupVos;
    }

    private void getEnableSingleGroup(List<AttendanceGroup> groups, List<AttendanceGroupVo> groupVos, Map<String, List<AttendanceGroup>> groupIdToParent) {
        groups.forEach(group -> {
            if (Objects.equals(group.getFestivalSetting(), 1)) {
                return;
            }
            groupVos.add(BeanUtil.toBean(group, AttendanceGroupVo.class));
            List<AttendanceGroup> attendanceGroups = groupIdToParent.get(group.getId());
            if (CollUtil.isEmpty(attendanceGroups)) {
                return;
            }
            getEnableSingleGroup(attendanceGroups, groupVos, groupIdToParent);
        });
    }

    /**
     * 获取考勤组下个考勤组配置
     *
     * @param collect
     * @param groupIdToParent
     * @param groupId
     * @return
     */
    private List<AttendanceFestivalSettingEntity> findNextBaseSetting(Map<String, List<AttendanceFestivalSettingEntity>> collect, Map<String, String> groupIdToParent, String groupId) {
        if (StringUtil.isBlank(groupId)) {
            return CollUtil.newArrayList();
        }
        if (!collect.containsKey(groupId)) {
            return findNextBaseSetting(collect, groupIdToParent, groupIdToParent.get(groupId));
        }
        return collect.get(groupId);
    }

    @Override
    public void statutoryUpdate(String groupId, String year) {
        List<AttendanceFestivalSettingEntity> list1 = lambdaQuery().eq(AttendanceFestivalSettingEntity::getGroupId, groupId)
                .likeRight(AttendanceFestivalSettingEntity::getEndDate, year)
                .eq(AttendanceFestivalSettingEntity::getDeleteMark, Boolean.FALSE)
                .eq(AttendanceFestivalSettingEntity::getStatutoryEnable, 1)
                .list();
        Map<String, AttendanceFestivalSettingEntity> collect1 = list1.stream().collect(Collectors.toMap(AttendanceFestivalSettingEntity::getName, entity -> entity));
        List<Holiday> holidays = HolidayUtil.getHolidays(year);
        holidays.addAll(HolidayUtil.getHolidays(DateDetail.getPreviousYear(year)));
        Map<String, List<Holiday>> collect = holidays.stream().filter(festival -> festival.getTarget().contains(year)).collect(Collectors.groupingBy(Holiday::getName));
        List<AttendanceFestivalSettingEntity> entities = CollUtil.newArrayList();
        UserInfo user = UserProvider.getUser();
        collect.forEach((name, list) -> {
            List<Holiday> workHolidays = list.stream().filter(Holiday::isWork).collect(Collectors.toList());
            List<Holiday> notWorkHolidays = list.stream().filter(holiday -> !holiday.isWork()).collect(Collectors.toList());
            Holiday firstHoliday = notWorkHolidays.stream().sorted(Comparator.comparing(Holiday::getDay)).reduce((h1, h2) -> h1).orElse(null);
            Holiday lastHoliday = notWorkHolidays.stream().sorted(Comparator.comparing(Holiday::getDay)).reduce((h1, h2) -> h2).orElse(null);
            AttendanceFestivalSettingEntity orDefault = collect1.getOrDefault(name, AttendanceFestivalSettingEntity.builder().groupId(groupId).deleteMark(0).statutoryEnable(1).name(name).creatorTime(new Date()).creatorUserId(user.getUserId()).tenantId(user.getTenantId()).build());
            orDefault.setStartDate(DateUtil.stringToDates(firstHoliday.getDay()));
            orDefault.setEndDate(DateUtil.stringToDates(lastHoliday.getDay()));
            String compensateInDate = workHolidays.stream().map(Holiday::getDay).reduce((r1, r2) -> r1 + "," + r2).orElse("");
            orDefault.setCompensateInDate(compensateInDate);
            entities.add(orDefault);
        });
        // 这里需要处理每年同日更新的配置

        saveOrUpdateBatch(entities.stream().sorted(Comparator.comparing(AttendanceFestivalSettingEntity::getStartDate)).collect(Collectors.toList()));
    }

    @Override
    @Transactional
    public void updateStatus(String id, Integer enable) throws HandleException {
        if (Objects.equals(enable, 1)) {
            AttendanceFestivalSettingEntity byId = getById(id);
            if(StringUtil.isEmpty(byId.getFestivalDate())){
                throw new HandleException("请选择节日日期");
            }

            if(Objects.isNull(byId.getExpiresType())){
                throw new HandleException("请设置过期天数");
            }

            if(Objects.equals(byId.getExpiresType(),1) && Objects.isNull(byId.getExpiresDayNumber())){
                throw new HandleException("请设置过期天数");
            }
            if(Objects.equals(byId.getExpiresType(),2) && Objects.isNull(byId.getExpiresDay())){
                throw new HandleException("请设置过期日期");
            }
            List<Date> dateList = Arrays.stream(byId.getFestivalDate().split(",")).map(DateDetail::getStr2Date10).collect(Collectors.toList());
            List<Date> collect1 = dateList.stream().filter(date -> DateUtil.getDayEnd().after(date)).collect(Collectors.toList());
            if (CollUtil.isNotEmpty(collect1)) {
                throw new HandleException("请选择大于今天的节日日期");
            }
        }

        lambdaUpdate().set(AttendanceFestivalSettingEntity::getEnable, enable)
                .eq(AttendanceFestivalSettingEntity::getId, id)
                .update();
        autoRest(getById(id), null);
    }

    @Override
    public void initFestivalSetting(String groupId) {
        List<AttendanceFestivalSettingEntity> list = lambdaQuery().eq(AttendanceFestivalSettingEntity::getGroupId, groupId)
                .eq(AttendanceFestivalSettingEntity::getDeleteMark, Boolean.FALSE)
                .list();
        if (CollUtil.isNotEmpty(list)) {
            return;
        }
        List<AttendanceGroup> attendanceGroups = attendanceGroupService.queryDropList();
        Map<String, List<AttendanceFestivalSettingEntity>> enableBaseSetting = getEnableFestivalSetting(CollUtil.newArrayList(groupId), attendanceGroups, Boolean.FALSE);
        List<AttendanceFestivalSettingEntity> attendanceBaseSettings = enableBaseSetting.get(groupId);
        if (CollUtil.isNotEmpty(attendanceBaseSettings)) {
            attendanceBaseSettings.forEach(attendanceBaseSetting -> {
                attendanceBaseSetting.setId(RandomUtil.uuId());
                attendanceBaseSetting.setGroupId(groupId);
                attendanceBaseSetting.setCreatorTime(new Date());
                attendanceBaseSetting.setCreatorUserId(UserProvider.getLoginUserId());
            });
            saveBatch(attendanceBaseSettings);
        }
    }

    @Override
    public List<HolidayOptionVo> getHolidayOptions(String groupId) {
        List<HolidayOptionVo> holidays = CollUtil.newArrayList();
        List<AttendanceGroup> attendanceGroups = attendanceGroupService.queryDropList();
        Map<String, List<AttendanceFestivalSettingEntity>> festivalMap = getEnableFestivalSetting(CollUtil.newArrayList(groupId), attendanceGroups);
        List<AttendanceFestivalSettingEntity> entities = festivalMap.getOrDefault(groupId, CollUtil.newArrayList());
        entities.forEach(festival -> {
            if(Objects.equals(festival.getDistributeType(),1) || Objects.equals(festival.getDistributeType(),0)){
                return;
            }
            holidays.add(HolidayOptionVo.builder()
                    .id(festival.getId())
                    .dayType(1)
                    .name(festival.getName())
                    .day(festival.getDay())
                    .expiresDayNumber(festival.getExpiresDayNumber())
                    .expiresMonth(festival.getExpiresMonth())
                    .expiresDay(festival.getExpiresDay())
                    .expiresType(festival.getExpiresType())
                    .type(1)
                    .build());
        });
        Map<String, List<AttendanceHolidaySettingEntity>> enableFestivalSetting = attendanceHolidaySettingService.getEnableFestivalSetting(CollUtil.newArrayList(groupId), attendanceGroups);
        List<AttendanceHolidaySettingEntity> entities1 = enableFestivalSetting.getOrDefault(groupId, CollUtil.newArrayList());
        entities1.forEach(holiday -> {
            if(Objects.equals(holiday.getGiveType(),1)){
                return;
            }
            holidays.add(HolidayOptionVo.builder()
                    .id(holiday.getId())
                    .name(holiday.getName())
                    .dayType(holiday.getDayType())
                    .yoeMultiple(holiday.getYoeMultiple())
                    .yosMultiple(holiday.getYosMultiple())
                    .day(holiday.getDayNumber())
                    .expiresDayNumber(holiday.getExpiresDayNumber())
                    .expiresMonth(holiday.getExpiresMonth())
                    .expiresDay(holiday.getExpiresDay())
                    .expiresType(holiday.getExpiresType())
                    .type(2)
                    .build());
        });
        return holidays;
    }
}
