package com.ruoyi.zhushi.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.common.core.domain.PageQuery;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.zhushi.entity.*;
import com.ruoyi.zhushi.mapper.*;
import com.ruoyi.zhushi.service.NjBalanceManageService;
import com.ruoyi.zhushi.util.Constans;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Service
public class NjBalanceManageServiceImpl implements NjBalanceManageService {

    @Autowired
    private NjBalanceManageMapper njBalanceManageMapper;
    @Autowired
    private NjBalanceManageDetailMapper njBalanceManageDetailMapper;

    @Autowired
    private NjRuleConfigMapper njRuleConfigMapper;

    @Autowired
    private NjRuleConfigAndUserMapper njRuleConfigAndUserMapper;

    @Override
    public TableDataInfo<NjBalanceManageDTO> queryPageList(NjBalanceManageDTO njBalanceManageDTO, PageQuery pageQuery) {
        LambdaQueryWrapper<NjBalanceManage> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(njBalanceManageDTO.getUserName()!= null, NjBalanceManage::getUserName, njBalanceManageDTO.getUserName());
        queryWrapper.eq(njBalanceManageDTO.getNickName()!= null, NjBalanceManage::getNickName, njBalanceManageDTO.getNickName());
        IPage<NjBalanceManageDTO> njBalanceManageDTOS = njBalanceManageMapper.selectVoPage(pageQuery.build(), queryWrapper, NjBalanceManageDTO.class);
        return TableDataInfo.build(njBalanceManageDTOS);
    }

    @Override
    public void insertBatch(List<NjBalanceManage> njBalanceManages) {
        njBalanceManageMapper.insertBatch(njBalanceManages);
    }

    @Override
    public BigDecimal getUnUsedDayByUserId(long userId) {
        // 根据用户id获取年假余额
        LambdaQueryWrapper<NjBalanceManage> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BeanUtil.isNotEmpty(userId), NjBalanceManage::getUserId, userId);
        NjBalanceManageDTO njBalanceManageDTO = njBalanceManageMapper.selectVoOne(queryWrapper);
        return njBalanceManageDTO.getUnusedDay();
    }

    @Override
    public int update(NjBalanceManageDTO njBalanceManageDTO) {
        NjBalanceManage njBalanceManage = new NjBalanceManage();
        BeanUtil.copyProperties(njBalanceManageDTO, njBalanceManage);
        int i = njBalanceManageMapper.updateById(njBalanceManage);
        return i;
    }

    /**
     * 计算年假   保存年假规则会调用   定时任务每年1月1日会调用这个接口
     */
    @Override
    public void generateYearBalance() {
        // 查询年假配置管理
        LambdaQueryWrapper<NjRuleConfig> queryWrapper = Wrappers.lambdaQuery();
        List<NjRuleConfigDTO> njRuleConfigDTOS = njRuleConfigMapper.selectVoList(queryWrapper, NjRuleConfigDTO.class);

        if (njRuleConfigDTOS!=null&&njRuleConfigDTOS.size()>0) {
            // 遍历所有年假配置，判断是否适用全部人员，判断年假的生成方式
            for (NjRuleConfigDTO njRuleConfigDTO : njRuleConfigDTOS) {
                // 用户年假集合
                List<NjBalanceManage> njBalanceManages = new ArrayList<>();
                // 1.根据年假配置查询下面的用户
                LambdaQueryWrapper<NjRuleConfigAndUser> queryWrapper1 = Wrappers.lambdaQuery();
                queryWrapper1.eq(NjRuleConfigAndUser::getNjRuleConfigId, njRuleConfigDTO.getId());
                List<NjRuleConfigAndUserDTO> njRuleConfigAndUserDTOS = njRuleConfigAndUserMapper.selectVoList(queryWrapper1);
                //2.根据用户入职时间 计算对于的年假额度
                for (NjRuleConfigAndUserDTO njRuleConfigAndUserDTO : njRuleConfigAndUserDTOS) {
                    //2.1 根据 人员id 查询年假信息
                    LambdaQueryWrapper<NjBalanceManage> queryWrapper2 = new LambdaQueryWrapper<>();
                    queryWrapper2.eq(NjBalanceManage::getUserId, njRuleConfigAndUserDTO.getUserId());
                    int year = LocalDate.now().getYear();
                    queryWrapper2.apply("YEAR(create_time) = {0}", year);
                    NjBalanceManage njBalanceManage = njBalanceManageMapper.selectOne(queryWrapper2);
                    if (njBalanceManage==null) {
                        njBalanceManage = new NjBalanceManage();
                    }

                    //2.2 查询明细表中的已使用年假
                    BigDecimal  used_days = new BigDecimal(0);
                    QueryWrapper detailQuery =new QueryWrapper();
                    detailQuery.select("sum(used_day) used_days");
                    detailQuery.eq("user_id",njRuleConfigAndUserDTO.getUserId());
                    List<Map> detailList= njBalanceManageDetailMapper.selectMaps(detailQuery);
                    if (detailList!=null&&detailList.size()>0) {
                        Map map =detailList.get(0);
                        if (map!=null) {
                            used_days =  (BigDecimal )map.get("used_days");
                        }
                    }

                    // 获取入职时间
                    LocalDate joinedDate = njRuleConfigAndUserDTO.getJoinedDate() == null ? LocalDate.now() : njRuleConfigAndUserDTO.getJoinedDate();
                    //年假总额
                    njBalanceManage.setAnnualLeave(new BigDecimal(calculateAnnualLeave(joinedDate)));
                    // 已使用天数
                    njBalanceManage.setUsedDay(used_days);
                    // 剩余天数 = 年假总额 - 已使用年假
                    njBalanceManage.setUnusedDay(njBalanceManage.getAnnualLeave().subtract(used_days));
                    //上年结转
                    njBalanceManage.setLastYearUnusedDay(BigDecimal.valueOf(Constans.ANNUALLEAVETIERS_0));
                    // 转态
                    njBalanceManage.setIsEnable(true);
                    // 获取用户信息
                    njBalanceManage.setUserId(njRuleConfigAndUserDTO.getUserId());
                    njBalanceManage.setUserName(njRuleConfigAndUserDTO.getUserName());
                    njBalanceManage.setNickName(njRuleConfigAndUserDTO.getNickName());
                    njBalanceManage.setDeptName(njRuleConfigAndUserDTO.getDeptName());

                    njBalanceManages.add(njBalanceManage);
                }

                // 批量插入
                njBalanceManageMapper.insertOrUpdateBatch(njBalanceManages);
            }
        }

    }

    /**
     * 年假计算
     * 年假发放规则 入职满一年（5天):5, 入职满10年（10天):10,入职满20年（15天）:15
     * 1年：
     * （当年年末-入职满1年日期）/当年天数 * 5
     * 10年：
     * (入职满10年日期-当年年初)/当年天数*5+（当年年末-入职满10年日期）/当年天数 * 10
     * 20年：
     * (入职满20年日期-当年年初)/当年天数*10+（当年年末-入职满20年日期）/当年天数 *15
     * 最后的年假结果去掉小数，假如是7.99天 也按照7天算
     * 下面举一个例子假设:
     * 员工a 20240603入职
     * 员工b 20150603入职
     * 员工c 20050603入职
     * 年假分别为:
     * 员工a  2天
     * 员工b  7天
     * 员工c  12天
     * @param hireDate
     * @return
     */

    public static int calculateAnnualLeave(LocalDate hireDate) {
        LocalDate now = LocalDate.now();
        int currentYear = now.getYear();
        LocalDate startOfYear = LocalDate.of(currentYear, 1, 1);
        LocalDate endOfYear = LocalDate.of(currentYear, 12, 31);
        long daysOfYear = ChronoUnit.DAYS.between(startOfYear, endOfYear) + 1;

        LocalDate oneYearDate = hireDate.plusYears(1);
        LocalDate tenYearDate = hireDate.plusYears(10);
        LocalDate twentyYearDate = hireDate.plusYears(20);

        double annualLeave = 0;

        if (oneYearDate.isAfter(endOfYear)) {
            // 未满一年
            return 0;
        }

        if (tenYearDate.isAfter(endOfYear)) {
            // 满1年 不满10年
            LocalDate begin = oneYearDate.isBefore(startOfYear) ? startOfYear : oneYearDate;
            long days = ChronoUnit.DAYS.between(begin, endOfYear) + 1;
            annualLeave = (days * 5.0) / daysOfYear;
        } else if (twentyYearDate.isAfter(endOfYear)) {
            // 满10年 不满20年
            LocalDate firstStart = startOfYear;
            LocalDate firstEnd = tenYearDate.isAfter(startOfYear) ? tenYearDate.minusDays(1) : startOfYear.minusDays(1);
            long firstDays = ChronoUnit.DAYS.between(firstStart, firstEnd) + 1;
            if (firstDays < 0) firstDays = 0;

            LocalDate secondStart = tenYearDate.isBefore(startOfYear) ? startOfYear : tenYearDate;
            long secondDays = ChronoUnit.DAYS.between(secondStart, endOfYear) + 1;

            annualLeave = (firstDays * 5.0 + secondDays * 10.0) / daysOfYear;
        } else {
            // 满20年
            if (twentyYearDate.isBefore(startOfYear)) {
                // 全年都满20年，全部按15天
                annualLeave = 15.0;
            } else if (twentyYearDate.isAfter(endOfYear)) {
                // 实际不会到这一步，但保险加上
                annualLeave = 10.0;
            } else {
                // 当前年内刚满20年，按10 + 15规则
                LocalDate firstEnd = twentyYearDate.minusDays(1);
                long firstDays = ChronoUnit.DAYS.between(startOfYear, firstEnd) + 1;

                LocalDate secondStart = twentyYearDate;
                long secondDays = ChronoUnit.DAYS.between(secondStart, endOfYear) + 1;

                annualLeave = (firstDays * 10.0 + secondDays * 15.0) / daysOfYear;
            }
        }

        return (int) annualLeave;
    }
}
