package com.ruoyi.oa.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.esotericsoftware.minlog.Log;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.helper.LoginHelper;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.core.page.TableDataInfo;
import com.ruoyi.common.core.domain.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.oa.domain.*;
import com.ruoyi.oa.domain.bo.OaBonusProjectRelBo;
import com.ruoyi.oa.mapper.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.oa.domain.bo.OaBonusPoolBo;
import com.ruoyi.oa.domain.vo.OaBonusPoolVo;
import com.ruoyi.oa.service.IOaBonusPoolService;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 奖金池Service业务层处理
 *
 * @author ruoyi
 * @date 2025-10-23
 */
@RequiredArgsConstructor
@Service
public class OaBonusPoolServiceImpl implements IOaBonusPoolService {

    private final OaBonusPoolMapper baseMapper;

    @Autowired
    private OaBonusProjectRelMapper bonusProjectRelMapper;

    private final OaProjectScheduleMapper projectScheduleMapper;
    private final SysOaProjectMapper projectMapper;

    @Autowired
    private OaProjectScheduleStepMapper projectScheduleStepMapper;

    @Autowired
    private OaBonusAllocationMapper bonusAllocationMapper;


    /**
     * 查询奖金池
     */
    @Override
    public OaBonusPoolVo queryById(Long poolId) {
        return baseMapper.selectVoById(poolId);
    }

    /**
     * 查询奖金池列表
     */
    @Override
    public TableDataInfo<OaBonusPoolVo> queryPageList(OaBonusPoolBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<OaBonusPool> lqw = buildQueryWrapper(bo);
        Page<OaBonusPoolVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询奖金池列表
     */
    @Override
    public List<OaBonusPoolVo> queryList(OaBonusPoolBo bo) {
        LambdaQueryWrapper<OaBonusPool> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<OaBonusPool> buildQueryWrapper(OaBonusPoolBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<OaBonusPool> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getPoolName()), OaBonusPool::getPoolName, bo.getPoolName());
        lqw.eq(bo.getStartDate() != null, OaBonusPool::getStartDate, bo.getStartDate());
        lqw.eq(bo.getEndDate() != null, OaBonusPool::getEndDate, bo.getEndDate());
        return lqw;
    }

    /**
     * 新增奖金池
     */
    @Override
    public Boolean insertByBo(OaBonusPoolBo bo) {
        OaBonusPool add = BeanUtil.toBean(bo, OaBonusPool.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setPoolId(add.getPoolId());
        }
        return flag;
    }

    /**
     * 修改奖金池
     */
    @Override
    public Boolean updateByBo(OaBonusPoolBo bo) {
        OaBonusPool update = BeanUtil.toBean(bo, OaBonusPool.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(OaBonusPool entity) {
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除奖金池
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    //现在需要知道项目id查询对应的项目负责人然后在进度里面查找对应项目的进度负责人
    //总金额是绑定项目的时候填每个项目对应的金额 填入到奖金池与项目的绑定表中的分配给该项目的金额 然后统计这个金额字段
    //所以此处是一个项目负责人和n个进度负责人  然后绑定奖金池id和进度负责人的nickname和项目负责人的nickname 作为分配比例的依据
    //看他完成的任务情况也就是status的值 查项目负责人负责了多少项目，进度负责人负责了多少进度 进度完成的咋样 是否有延期或者未完成的 是多少
    //然后就是每个项目负责人和进度负责人的分配比例手填  填他们的金额分配比例 拿到对应的金额
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchAdd(OaBonusPoolBo bo) {
        // 插入奖金池主表
        OaBonusPool pool = BeanUtil.toBean(bo, OaBonusPool.class);
        validEntityBeforeSave(pool);
        boolean flag = baseMapper.insert(pool) > 0;
        if (!flag) {
            Log.warn("奖金池主表插入失败");
            return false;
        }

        // 获取插入后的主键
        Long poolId = pool.getPoolId();
        // 校验项目ID列表
        if (CollUtil.isEmpty(bo.getProjectIds())) {
            Log.warn("批量添加奖金池失败：项目ID列表为空");
            return false;
        }

        // 收集所有负责人昵称（项目负责人 + 进度负责人），通过Set自动去重
        Set<String> allNickNames = new HashSet<>();

        // 获取项目负责人昵称（sys_oa_project.functionary）
        List<SysOaProject> projects = projectMapper.selectList(
                Wrappers.<SysOaProject>lambdaQuery()
                        .in(SysOaProject::getProjectId, bo.getProjectIds())
                        .select(SysOaProject::getFunctionary)
        );
        if (CollUtil.isEmpty(projects)) {
            Log.warn("批量添加奖金池失败：未找到项目ID对应的项目记录");
            return false;
        }
        projects.stream()
                .filter(Objects::nonNull) // 过滤null项目对象
                .map(SysOaProject::getFunctionary)
                .filter(StrUtil::isNotBlank) // 过滤空昵称
                .forEach(allNickNames::add); // Set自动去重

        // 通过项目ID查询进度主表，获取schedule_id
        List<OaProjectSchedule> schedules = projectScheduleMapper.selectList(
                Wrappers.<OaProjectSchedule>lambdaQuery()
                        .in(OaProjectSchedule::getProjectId, bo.getProjectIds())
                        .eq(OaProjectSchedule::getDelFlag, "0")
                        .select(OaProjectSchedule::getScheduleId)
        );
        // 收集进度负责人（oa_project_schedule_step.header）
        if (CollUtil.isEmpty(schedules)) {
            Log.warn("项目ID对应的进度主表记录为空，仅收集项目负责人");
        } else {
            List<Long> scheduleIds = schedules.stream()
                    .filter(Objects::nonNull) // 过滤null进度对象
                    .map(OaProjectSchedule::getScheduleId)
                    .filter(Objects::nonNull) // 再过滤null的scheduleId
                    .collect(Collectors.toList());

            List<OaProjectScheduleStep> scheduleSteps = projectScheduleStepMapper.selectList(
                    Wrappers.<OaProjectScheduleStep>lambdaQuery()
                            .in(OaProjectScheduleStep::getScheduleId, scheduleIds)
                            .eq(OaProjectScheduleStep::getDelFlag, "0")
                            .select(OaProjectScheduleStep::getNodeHeader)
            );
            scheduleSteps.stream()
                    .filter(Objects::nonNull) // 过滤null步骤对象
                    .map(OaProjectScheduleStep::getNodeHeader)
                    .filter(StrUtil::isNotBlank) // 过滤null/空字符串的header
                    .forEach(allNickNames::add); // Set自动去重
        }

        // 校验去重后的昵称集合
        if (allNickNames.isEmpty()) {
            Log.warn("批量添加奖金池失败：未找到任何有效负责人昵称");
            return false;
        }

        // 循环插入奖金池分配表
        for (String nickName : allNickNames) {
            OaBonusAllocation allocation = new OaBonusAllocation();
            allocation.setPoolId(poolId);           // 关联当前奖金池ID
            allocation.setNickName(nickName);       // 单个负责人昵称
            allocation.setAllocationRatio(new BigDecimal("0.00")); // 默认分配比例
            allocation.setCreateBy(LoginHelper.getUsername());    // 创建人
            allocation.setCreateTime(new Date());                  // 创建时间
            allocation.setDelFlag("0");             // 未删除

            int insertResult = bonusAllocationMapper.insert(allocation);
            if (insertResult <= 0) {
                Log.error("插入奖金池分配记录失败：poolId={}, nickName={}");
                throw new RuntimeException("分配记录插入失败，触发回滚");
            }
        }

        // 插入奖金池与项目关联表
        for (Long projectId : bo.getProjectIds()) {
            OaBonusProjectRel rel = new OaBonusProjectRel();
            rel.setPoolId(poolId);
            rel.setProjectId(projectId);
            rel.setCreateBy(LoginHelper.getUsername());
            rel.setCreateTime(new Date());
            rel.setDelFlag("0");
            int result = bonusProjectRelMapper.insert(rel);
            if (result <= 0) {
                Log.error("插入奖金池-项目关联记录失败，projectId={}");
                throw new RuntimeException("关联记录插入失败，触发回滚");
            }
        }

        Log.info("奖金池批量创建成功，poolId={}，去重后负责人数量={}");
        return true;
    }
}


