package com.ruoyi.oa.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
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.vo.EmployeeSalaryRecordVo;
import com.ruoyi.oa.domain.vo.OaBindingItemDetailVo;
import com.ruoyi.oa.mapper.*;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.oa.domain.bo.OaEmployeeTemplateBindingBo;
import com.ruoyi.oa.domain.vo.OaEmployeeTemplateBindingVo;
import com.ruoyi.oa.service.IOaEmployeeTemplateBindingService;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Collection;
import java.util.stream.Collectors;

/**
 * 员工模板绑定及月度发放记录Service业务层处理
 *
 * @author ruoyi
 * @date 2025-06-23
 */
@RequiredArgsConstructor
@Service
public class OaEmployeeTemplateBindingServiceImpl implements IOaEmployeeTemplateBindingService {
    @Autowired
    private final OaEmployeeTemplateBindingMapper baseMapper;
    @Autowired
    private final OaBindingItemDetailMapper bindingItemDetailMapper;
    @Autowired
    private final OaEmployeeMapper employeeMapper;
    @Autowired
    private final OaSalaryTemplateDetailMapper salaryDetailMapper;
    @Autowired
    private final OaInsuranceTemplateDetailMapper insuranceDetailMapper;


    /**
     * 查询员工模板绑定及月度发放记录
     */
    @Override
    public OaEmployeeTemplateBindingVo queryById(Long bindingId){
        return baseMapper.selectVoById(bindingId);
    }

    /**
     * 查询员工模板绑定及月度发放记录列表
     */
    @Override
    public TableDataInfo<OaEmployeeTemplateBindingVo> queryPageList(OaEmployeeTemplateBindingBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<OaEmployeeTemplateBinding> lqw = buildQueryWrapper(bo);
        Page<OaEmployeeTemplateBindingVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        // 根据bindingid和template_type(salary)去求和paid_amount字段
        if (CollectionUtils.isNotEmpty(result.getRecords())) {
            // 提取所有bindingId
            List<Long> bindingIds = result.getRecords().stream()
                    .map(OaEmployeeTemplateBindingVo::getBindingId)
                    .collect(Collectors.toList());

            // 批量查询每个bindingId对应的薪资总额
            Map<Long, BigDecimal> salaryTotalMap = calculateSalaryTotalByBindingIds(bindingIds);

            // 将计算结果设置到对应的VO对象中
            for (OaEmployeeTemplateBindingVo vo : result.getRecords()) {
                vo.setTotalSalary(salaryTotalMap.getOrDefault(vo.getBindingId(), BigDecimal.ZERO));
            }
        }

        return TableDataInfo.build(result);
    }
    /**
     * 根据绑定记录ID集合批量计算薪资总额
     * @param bindingIds 绑定记录ID集合
     * @return 绑定记录ID与薪资总额的映射关系
     */
    private Map<Long, BigDecimal> calculateSalaryTotalByBindingIds(List<Long> bindingIds) {
        if (CollectionUtils.isEmpty(bindingIds)) {
            return Collections.emptyMap();
        }

        // 创建查询条件
        LambdaQueryWrapper<OaBindingItemDetail> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(OaBindingItemDetail::getBindingId, bindingIds)
                .eq(OaBindingItemDetail::getTemplateType, "salary") // 只查询薪资类型
                .eq(OaBindingItemDetail::getDelFlag, 0); // 只查询未删除的记录

        // 查询所有符合条件的明细记录
        List<OaBindingItemDetail> details = bindingItemDetailMapper.selectList(queryWrapper);

        // 使用流处理按bindingId分组并计算总额
        return details.stream()
                .collect(Collectors.groupingBy(
                        OaBindingItemDetail::getBindingId,
                        Collectors.reducing(
                                BigDecimal.ZERO,
                                OaBindingItemDetail::getPaidAmount,
                                BigDecimal::add
                        )
                ));
    }
    /**
     * 查询员工模板绑定及月度发放记录列表
     */
    @Override
    public List<OaEmployeeTemplateBindingVo> queryList(OaEmployeeTemplateBindingBo bo) {
        LambdaQueryWrapper<OaEmployeeTemplateBinding> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<OaEmployeeTemplateBinding> buildQueryWrapper(OaEmployeeTemplateBindingBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<OaEmployeeTemplateBinding> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getEmployeeId() != null, OaEmployeeTemplateBinding::getEmployeeId, bo.getEmployeeId());
        lqw.eq(bo.getInsuranceTemplateId() != null, OaEmployeeTemplateBinding::getInsuranceTemplateId, bo.getInsuranceTemplateId());
        lqw.eq(bo.getSalaryTemplateId() != null, OaEmployeeTemplateBinding::getSalaryTemplateId, bo.getSalaryTemplateId());
        lqw.eq(bo.getPayYear() != null, OaEmployeeTemplateBinding::getPayYear, bo.getPayYear());
        lqw.eq(bo.getPayMonth() != null, OaEmployeeTemplateBinding::getPayMonth, bo.getPayMonth());
        lqw.eq(bo.getNetSalary() != null, OaEmployeeTemplateBinding::getNetSalary, bo.getNetSalary());
        lqw.eq(bo.getTotalCompanyCost() != null, OaEmployeeTemplateBinding::getTotalCompanyCost, bo.getTotalCompanyCost());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), OaEmployeeTemplateBinding::getStatus, bo.getStatus());
        return lqw;
    }

    /**
     * 新增员工模板绑定及月度发放记录
     */
    @Override
    public Boolean insertByBo(OaEmployeeTemplateBindingBo bo) {
        OaEmployeeTemplateBinding add = BeanUtil.toBean(bo, OaEmployeeTemplateBinding.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setBindingId(add.getBindingId());
        }
        return flag;
    }

    /**
     * 修改员工模板绑定及月度发放记录
     */
    @Override
    public Boolean updateByBo(OaEmployeeTemplateBindingBo bo) {
        OaEmployeeTemplateBinding update = BeanUtil.toBean(bo, OaEmployeeTemplateBinding.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

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

    /**
     * 批量删除员工模板绑定及月度发放记录
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public Boolean calculateSalary(List<Long> employeeIds, Long payYear, Long payMonth,
                                   Long defaultInsuranceTemplateId, Long defaultSalaryTemplateId) {
        // 参数校验
        if (defaultInsuranceTemplateId == null || defaultSalaryTemplateId == null) {
            throw new RuntimeException("请选择默认的薪资模板和社保模板");
        }

        for (Long employeeId : employeeIds) {
            // 1. 检查本月是否已存在记录
            OaEmployeeTemplateBinding exist = baseMapper.findByEmployeeAndMonth(employeeId, payYear, payMonth);
            if (exist != null) {
                // 已存在，跳过
                continue;
            }

            // 2. 获取上月记录
            Long lastMonth = (payMonth == 1) ? 12 : payMonth - 1;
            Long lastYear = (payMonth == 1) ? payYear - 1 : payYear;
            OaEmployeeTemplateBinding lastBinding = baseMapper.findByEmployeeAndMonth(employeeId, lastYear, lastMonth);

            // 3. 新建本月主表记录
            OaEmployeeTemplateBinding binding = new OaEmployeeTemplateBinding();
            binding.setEmployeeId(employeeId);
            binding.setPayYear(payYear);
            binding.setPayMonth(payMonth);
            binding.setStatus("待发");

            if (lastBinding != null) {
                // 存在上月记录，复制上月的模板ID
                binding.setInsuranceTemplateId(lastBinding.getInsuranceTemplateId());
                binding.setSalaryTemplateId(lastBinding.getSalaryTemplateId());
            } else {
                // 首次配置，使用默认模板
                binding.setInsuranceTemplateId(defaultInsuranceTemplateId);
                binding.setSalaryTemplateId(defaultSalaryTemplateId);
            }

            // 插入主表记录
            baseMapper.insert(binding);

            // 4. 生成明细快照
            if (lastBinding != null) {
                // 如果存在上月记录，复制上月的实际支付金额
                copyLastMonthDetails(lastBinding.getBindingId(), binding.getBindingId());
            } else {
                // 首次配置，使用模板默认金额
                createNewDetails(binding.getBindingId(), binding.getSalaryTemplateId(),
                        binding.getInsuranceTemplateId());
            }

            // 5. 更新主表的汇总金额
            updateBindingTotals(binding.getBindingId());
        }
        return true;
    }

    /**
     * 复制上月明细记录
     */
    private void copyLastMonthDetails(Long lastBindingId, Long newBindingId) {
        // 查询上月所有明细
        List<OaBindingItemDetail> lastDetails = bindingItemDetailMapper.findByBindingId(lastBindingId);

        for (OaBindingItemDetail lastDetail : lastDetails) {
            OaBindingItemDetail newDetail = new OaBindingItemDetail();
            newDetail.setBindingId(newBindingId);
            newDetail.setTemplateType(lastDetail.getTemplateType());
            newDetail.setItemDetailId(lastDetail.getItemDetailId());
            newDetail.setPaidAmount(lastDetail.getPaidAmount()); // 复制实际支付金额
            bindingItemDetailMapper.insert(newDetail);
        }
    }

    /**
     * 创建新的明细记录（使用模板默认值）
     */
    private void createNewDetails(Long bindingId, Long salaryTemplateId, Long insuranceTemplateId) {
        // 薪资明细
        List<OaSalaryTemplateDetail> salaryDetails = salaryDetailMapper.findByTemplateId(salaryTemplateId);
        for (OaSalaryTemplateDetail detail : salaryDetails) {
            OaBindingItemDetail item = new OaBindingItemDetail();
            item.setBindingId(bindingId);
            item.setTemplateType("salary");
            item.setItemDetailId(detail.getSalaryDetailId());
            item.setPaidAmount(detail.getAmount() != null ? detail.getAmount() : BigDecimal.ZERO);
            bindingItemDetailMapper.insert(item);
        }

        // 社保明细
        List<OaInsuranceTemplateDetail> insuranceDetails = insuranceDetailMapper.findByTemplateId(insuranceTemplateId);
        for (OaInsuranceTemplateDetail detail : insuranceDetails) {
            OaBindingItemDetail item = new OaBindingItemDetail();
            item.setBindingId(bindingId);
            item.setTemplateType("insurance");
            item.setItemDetailId(detail.getInsuranceDetailId());
            item.setPaidAmount(detail.getAmount() != null ? detail.getAmount() : BigDecimal.ZERO);
            bindingItemDetailMapper.insert(item);
        }
    }

    /**
     * 更新主表的汇总金额
     */
    private void updateBindingTotals(Long bindingId) {
        // 查询该binding下所有明细
        List<OaBindingItemDetail> details = bindingItemDetailMapper.findByBindingId(bindingId);

        BigDecimal totalSalary = BigDecimal.ZERO;
        BigDecimal totalCost = BigDecimal.ZERO;

        for (OaBindingItemDetail detail : details) {
            if (detail.getPaidAmount() != null) {
                if ("salary".equals(detail.getTemplateType())) {
                    totalSalary = totalSalary.add(detail.getPaidAmount());
                }
                totalCost = totalCost.add(detail.getPaidAmount());
            }
        }

        // 更新主表
        OaEmployeeTemplateBinding binding = new OaEmployeeTemplateBinding();
        binding.setBindingId(bindingId);
        binding.setNetSalary(totalSalary);
        binding.setTotalCompanyCost(totalCost);
        baseMapper.updateById(binding);
    }


    @Override
    public Boolean finalizeSalary(List<String> bindingIds) {
        for (String id : bindingIds) {
            OaEmployeeTemplateBinding binding = baseMapper.selectById(id);
            if (binding != null && !"已发".equals(binding.getStatus())) {
                binding.setStatus("已发");
                //TODO 这里可以算到财务支出等逻辑
                baseMapper.updateById(binding);
            }
        }
        return true;
    }

    @Override
    public List<EmployeeSalaryRecordVo> querySalaryHistory(Long employeeId) {
        List<OaEmployeeTemplateBinding> list = baseMapper.selectList(
                new LambdaQueryWrapper<OaEmployeeTemplateBinding>().eq(OaEmployeeTemplateBinding::getEmployeeId, employeeId)
                        .orderByDesc(OaEmployeeTemplateBinding::getPayYear, OaEmployeeTemplateBinding::getPayMonth)
        );
        return list.stream().map(this::toVo).collect(Collectors.toList());
    }

    // 工具方法：主表转VO并查明细
    private EmployeeSalaryRecordVo toVo(OaEmployeeTemplateBinding binding) {
        if (binding == null) return null;
        EmployeeSalaryRecordVo vo = new EmployeeSalaryRecordVo();
        BeanUtils.copyProperties(binding, vo);
        OaEmployee emp = employeeMapper.selectById(binding.getEmployeeId());
        if (emp != null) {
            vo.setEmployeeName(emp.getEmployeeName());
            vo.setCompany(emp.getCompany());
        }
        List<OaBindingItemDetail> allDetails = bindingItemDetailMapper.selectList(
                new LambdaQueryWrapper<OaBindingItemDetail>().eq(OaBindingItemDetail::getBindingId, binding.getBindingId())
        );
        vo.setSalaryDetails(allDetails.stream().filter(d -> "salary".equals(d.getTemplateType()))
                .map(this::toDetailVo).collect(Collectors.toList()));
        vo.setInsuranceDetails(allDetails.stream().filter(d -> "insurance".equals(d.getTemplateType()))
                .map(this::toDetailVo).collect(Collectors.toList()));
        return vo;
    }

    private OaBindingItemDetailVo toDetailVo(OaBindingItemDetail detail) {
        OaBindingItemDetailVo vo = new OaBindingItemDetailVo();
        BeanUtils.copyProperties(detail, vo);
        // 可补充itemName等
        return vo;
    }
}

