package org.dromara.personnel.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.validation.constraints.NotNull;
import org.apache.seata.spring.annotation.GlobalTransactional;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.mybatis.core.page.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 lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.personnel.domain.OpsCaigouPlanChanpin;
import org.dromara.personnel.domain.OpsCaigouPlanFiles;
import org.dromara.personnel.domain.OpsTenderSupplierInput;
import org.dromara.personnel.domain.bo.OpsCaigouPlanChanpinBo;
import org.dromara.personnel.domain.bo.OpsCaigouPlanFilesBo;
import org.dromara.personnel.domain.bo.OpsCaigouPlanReq;
import org.dromara.personnel.domain.enums.OpsCaigouPlanEnum;
import org.dromara.personnel.domain.vo.OpsCaigouPlanChanpinListVo;
import org.dromara.personnel.domain.vo.OpsCaigouPlanCountVo;
import org.dromara.personnel.service.IOpsCaigouPlanChanpinService;
import org.dromara.personnel.service.IOpsCaigouPlanFilesService;
import org.dromara.personnel.service.IOpsTenderSupplierInputService;
import org.dromara.personnel.utils.CglxdIdGenerator;
import org.dromara.resource.api.RemoteFileService;
import org.dromara.system.api.model.LoginUser;
import org.springframework.stereotype.Service;
import org.dromara.personnel.domain.bo.OpsCaigouPlanBo;
import org.dromara.personnel.domain.vo.OpsCaigouPlanVo;
import org.dromara.personnel.domain.OpsCaigouPlan;
import org.dromara.personnel.mapper.OpsCaigouPlanMapper;
import org.dromara.personnel.service.IOpsCaigouPlanService;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 运维-物资-采购计划单Service业务层处理
 *
 * @author LionLi
 * @date 2025-09-24
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class OpsCaigouPlanServiceImpl extends ServiceImpl<OpsCaigouPlanMapper,OpsCaigouPlan> implements IOpsCaigouPlanService {

    private final OpsCaigouPlanMapper baseMapper;

    private final IOpsCaigouPlanFilesService caigouPlanFilesService;

    private final IOpsCaigouPlanChanpinService caigouPlanChanpinService;
    private final RemoteFileService remoteFileService;

    private final IOpsTenderSupplierInputService tenderSupplierInputService;



    /**
     * 查询运维-物资-采购计划单
     *
     * @param id 主键
     * @return 运维-物资-采购计划单
     */
    @Override
    public OpsCaigouPlanVo queryById(Long id){
        OpsCaigouPlanVo opsCaigouPlanVo = baseMapper.selectVoById(id);
        if (opsCaigouPlanVo.getGonyingshangId() != null){
            OpsTenderSupplierInput supplierInput = tenderSupplierInputService.getById(opsCaigouPlanVo.getGonyingshangId());
            opsCaigouPlanVo.setGonyingshangName(supplierInput.getSupplierName());
        }
        opsCaigouPlanVo.setOpsCaigouPlanChanpinVos(caigouPlanChanpinService.getVoByCaiGouPlanId(id));
        opsCaigouPlanVo.setOpsCaigouPlanFilesVos(caigouPlanFilesService.getVoByCaiGouPlanId(id));
        return opsCaigouPlanVo;
    }

    /**
     * 分页查询运维-物资-采购计划单列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 运维-物资-采购计划单分页列表
     */
    @Override
    public TableDataInfo<OpsCaigouPlanVo> queryPageList(OpsCaigouPlanReq bo, PageQuery pageQuery) {
        LambdaQueryWrapper<OpsCaigouPlan> lqw = buildQueryWrapper(bo);
        Page<OpsCaigouPlanVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询符合条件的运维-物资-采购计划单列表
     *
     * @param bo 查询条件
     * @return 运维-物资-采购计划单列表
     */
    @Override
    public List<OpsCaigouPlanVo> queryList(OpsCaigouPlanReq bo) {
        LambdaQueryWrapper<OpsCaigouPlan> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<OpsCaigouPlan> buildQueryWrapper(OpsCaigouPlanReq bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<OpsCaigouPlan> lqw = Wrappers.lambdaQuery();
        lqw.orderByAsc(OpsCaigouPlan::getCreateTime);
        lqw.eq(bo.getProjectId() != null, OpsCaigouPlan::getProjectId, bo.getProjectId());
        lqw.like(StringUtils.isNotBlank(bo.getJihuaName()), OpsCaigouPlan::getJihuaName, bo.getJihuaName());
        lqw.eq(StringUtils.isNotBlank(bo.getJihuaBianhao()), OpsCaigouPlan::getJihuaBianhao, bo.getJihuaBianhao());
        lqw.eq(StringUtils.isNotBlank(bo.getStatus()), OpsCaigouPlan::getStatus, bo.getStatus());
        return lqw;
    }

    /**
     * 新增运维-物资-采购计划单
     *
     * @param bo 运维-物资-采购计划单
     * @return 是否新增成功
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Boolean insertByBo(OpsCaigouPlanBo bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        OpsCaigouPlan add = MapstructUtils.convert(bo, OpsCaigouPlan.class);
        add.setJingbanren(loginUser.getUserId());
        add.setJingbanrenName(loginUser.getUsername());
        add.setCaigouDanwei(loginUser.getDeptId());
        add.setCaigouDanweiName(loginUser.getDeptName());
        add.setJihuaBianhao(CglxdIdGenerator.generateId("CGLXD-"));
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
            if (bo.getOpsCaigouPlanChanpinBos() ==null){
                throw new ServiceException("产品信息不能为空！！！");
            }
            List<OpsCaigouPlanChanpinBo> opsCaigouPlanChanpinBos = bo.getOpsCaigouPlanChanpinBos();
            BigDecimal yujiJine = opsCaigouPlanChanpinBos.stream()
                // 步骤1：设置 caigouPlanId（副作用，也可单独处理）
                .peek(chanpin -> {
                    chanpin.setCaigouPlanId(add.getId());
                    chanpin.setProjectId(add.getProjectId());
                    chanpin.setChanpinBianhao(CglxdIdGenerator.generateId("CP-"));
                })
                // 步骤2：提取要累加的 totalPrice
                .map(OpsCaigouPlanChanpinBo::getTotalPrice)
                // 步骤3：过滤 null（避免 NPE）
                .filter(Objects::nonNull)
                // 步骤4：累加所有 BigDecimal（初始值为 BigDecimal.ZERO）
                .reduce(BigDecimal.ZERO, BigDecimal::add);
            add.setYujiJine(yujiJine);
            baseMapper.updateById(add);
            List<OpsCaigouPlanChanpin> planChanpinList = BeanUtil.copyToList(opsCaigouPlanChanpinBos, OpsCaigouPlanChanpin.class);
            caigouPlanChanpinService.saveBatch(planChanpinList);
            List<OpsCaigouPlanFilesBo> opsCaigouPlanFilesBos = bo.getOpsCaigouPlanFilesBos();
            opsCaigouPlanFilesBos.forEach(fileBo -> {
                fileBo.setCaigouPlanId(add.getId());
            });
            List<OpsCaigouPlanFiles> planFilesList = MapstructUtils.convert(opsCaigouPlanFilesBos, OpsCaigouPlanFiles.class);
            caigouPlanFilesService.saveBatch(planFilesList);
        }
        return flag;
    }

    /**
     * 修改运维-物资-采购计划单
     *
     * @param bo 运维-物资-采购计划单
     * @return 是否修改成功
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Boolean updateByBo(OpsCaigouPlanBo bo) {
        if (!OpsCaigouPlanEnum.CAOGAO.getValue().equals(bo.getStatus()) && !OpsCaigouPlanEnum.WEITONGUO.getValue().equals(bo.getStatus())) {
            throw new ServiceException("已开始审核，不允许修改");
        }
        List<OpsCaigouPlanChanpinBo> opsCaigouPlanChanpinBos = bo.getOpsCaigouPlanChanpinBos();
        if (opsCaigouPlanChanpinBos == null) {
            throw new ServiceException("产品信息不能为空！！！");
        }

        //查询该计划下产品信息列表
        List<OpsCaigouPlanChanpin> opsCaigouPlanChanpins = caigouPlanChanpinService.getBaseMapper().selectList(new LambdaQueryWrapper<OpsCaigouPlanChanpin>().eq(OpsCaigouPlanChanpin::getCaigouPlanId, bo.getId()));
        OpsCaigouPlan update = MapstructUtils.convert(bo, OpsCaigouPlan.class);
        validEntityBeforeSave(update);
        BigDecimal yujiJine = opsCaigouPlanChanpinBos.stream()
            // 步骤3：过滤 null（避免 NPE）
            .filter(Objects::nonNull)
            // 步骤2：提取要累加的 totalPrice
            .map(OpsCaigouPlanChanpinBo::getTotalPrice)
            // 步骤4：累加所有 BigDecimal（初始值为 BigDecimal.ZERO）
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        update.setYujiJine(yujiJine);
        if (opsCaigouPlanChanpins != null) {
            //获取已存在产品id
            Set<Long> chanpinOldIds = opsCaigouPlanChanpins.stream().filter(Objects::nonNull).map(OpsCaigouPlanChanpin::getId).collect(Collectors.toSet());
            //获取新的产品id列表
            Set<Long> chanpinNowIds = opsCaigouPlanChanpinBos.stream().filter(Objects::nonNull).map(OpsCaigouPlanChanpinBo::getId).collect(Collectors.toSet());
            //获取需要删除的产品id
            List<Long> detChanpinIds = new ArrayList<>();
            chanpinOldIds.forEach(detChanpinId -> {
                if (!chanpinNowIds.contains(detChanpinId)) {
                    detChanpinIds.add(detChanpinId);
                }
            });
            //判断需要删除产品id是否为空，不为空则删除
            if (!detChanpinIds.isEmpty()) {
                caigouPlanChanpinService.getBaseMapper().deleteByIds(detChanpinIds);
            }
            //过滤掉不存在的产品，对原有产品进行修改
            List<OpsCaigouPlanChanpinBo> list =opsCaigouPlanChanpinBos.stream()
                .filter(Objects::nonNull)
                .filter(chanpin -> chanpinOldIds.contains(chanpin.getId()))
                .toList();
            List<OpsCaigouPlanChanpin> planChanpinList = MapstructUtils.convert(list, OpsCaigouPlanChanpin.class);
            caigouPlanChanpinService.updateBatchById(planChanpinList);
            //过滤掉存在产品，并新增产品
            List<OpsCaigouPlanChanpinBo> chanpinBoList = opsCaigouPlanChanpinBos.stream()
                .filter(Objects::nonNull)
                .filter(opsCaigouPlanChanpinBo -> opsCaigouPlanChanpinBo.getId() == null).toList();
            for (OpsCaigouPlanChanpinBo chanpin : chanpinBoList) {
                if (chanpin != null) {
                    chanpin.setCaigouPlanId(update.getId());
                    chanpin.setProjectId(update.getProjectId());
                    chanpin.setChanpinBianhao(CglxdIdGenerator.generateId("CP-"));
                }
            }
            List<OpsCaigouPlanChanpin> planChanpinNowList = MapstructUtils.convert(chanpinBoList, OpsCaigouPlanChanpin.class);
            caigouPlanChanpinService.saveBatch(planChanpinNowList);
        }else {
            for (OpsCaigouPlanChanpinBo chanpin : opsCaigouPlanChanpinBos) {
                if (chanpin != null) {
                    chanpin.setCaigouPlanId(update.getId());
                    chanpin.setChanpinBianhao(CglxdIdGenerator.generateId("CP-"));
                }
            }
            List<OpsCaigouPlanChanpin> planChanpinList = MapstructUtils.convert(opsCaigouPlanChanpinBos, OpsCaigouPlanChanpin.class);
            caigouPlanChanpinService.saveBatch(planChanpinList);
        }
//        caigouPlanChanpinService.getBaseMapper().delete(new LambdaQueryWrapper<OpsCaigouPlanChanpin>().eq(OpsCaigouPlanChanpin::getCaigouPlanId, bo.getId()));
        //查询该计划文件id

        caigouPlanFilesService.getBaseMapper().delete(new LambdaQueryWrapper<OpsCaigouPlanFiles>().eq(OpsCaigouPlanFiles::getCaigouPlanId, bo.getId()));
        List<OpsCaigouPlanFilesBo> opsCaigouPlanFilesBos = bo.getOpsCaigouPlanFilesBos();
        if (opsCaigouPlanFilesBos != null) {
            //保存文件
            opsCaigouPlanFilesBos.forEach(fileBo -> {
                fileBo.setCaigouPlanId(update.getId());
            });
            List<OpsCaigouPlanFiles> planFilesList = MapstructUtils.convert(opsCaigouPlanFilesBos, OpsCaigouPlanFiles.class);
            caigouPlanFilesService.saveBatch(planFilesList);
        }
        return baseMapper.updateById(update) > 0;
    }

    private List<Long> detPlanFileIds(List<Long> chanpinId) {
        List<OpsCaigouPlanFiles> opsCaigouPlanFiles = caigouPlanFilesService.getBaseMapper()
            .selectList(new LambdaQueryWrapper<OpsCaigouPlanFiles>()
                .in(OpsCaigouPlanFiles::getCaigouPlanId, chanpinId));
        List<Long> ossIds = new ArrayList<>();
        opsCaigouPlanFiles.forEach(fileBo -> {ossIds.add(fileBo.getId());});

        return ossIds;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(OpsCaigouPlan entity){
        //TODO 做一些数据校验,如唯一约束
        Long count = baseMapper.selectCount(new LambdaQueryWrapper<OpsCaigouPlan>()
            .eq(OpsCaigouPlan::getProjectId, entity.getProjectId())
            .eq(OpsCaigouPlan::getJihuaName, entity.getJihuaName())
            .ne(entity.getId() != null,OpsCaigouPlan::getId, entity.getId()));
        if (count > 0) {
            throw new ServiceException("计划名称已存在！");
        }
    }

    /**
     * 校验并批量删除运维-物资-采购计划单信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
            List<OpsCaigouPlanVo> opsCaigouPlanVos = baseMapper.selectVoByIds(ids);
            opsCaigouPlanVos.forEach(vo -> {
                if (!OpsCaigouPlanEnum.CAOGAO.getValue().equals(vo.getStatus())) {
                    throw new ServiceException("已开始审核，不允许修改");
                }
            });
            caigouPlanChanpinService
                .getBaseMapper()
                .delete(new LambdaQueryWrapper<OpsCaigouPlanChanpin>()
                    .in(OpsCaigouPlanChanpin::getCaigouPlanId,ids));
            List<Long> ossIds = detPlanFileIds((List<Long>) ids);
            if (!ossIds.isEmpty()){
                remoteFileService.deleteFileByIds(ossIds);
            }
            caigouPlanFilesService
                .getBaseMapper()
                .delete(new LambdaQueryWrapper<OpsCaigouPlanFiles>()
                    .in(OpsCaigouPlanFiles::getCaigouPlanId,ids));
        }
        return baseMapper.deleteByIds(ids) > 0;
    }

    /**
     * 统计各个状态数量
     * @param projectId
     * @return
     */
    @Override
    public List<OpsCaigouPlanCountVo> getCountVo(Long projectId) {
        return baseMapper.getCountVo(projectId);
    }

    /**
     * 填写修改实际采购金额
     * @param bo
     * @return
     */
    @Override
    public Boolean setJinE(OpsCaigouPlanBo bo) {
        OpsCaigouPlan opsCaigouPlan = baseMapper.selectById(bo.getId());
        if (opsCaigouPlan == null) {
            throw new ServiceException("修改对象不存在");
        }
        if (!OpsCaigouPlanEnum.CAIGOUZHON.getValue().equals(opsCaigouPlan.getStatus())){
            throw new ServiceException("只有处于采购中时才能填写实际采购金额！！");
        }
        if (opsCaigouPlan.getYujiJine().compareTo(bo.getShijiJine()) < 0){
            throw new ServiceException("实际金额不能超过预计采购金额");
        }
        opsCaigouPlan.setShijiJine(bo.getShijiJine());
        return baseMapper.updateById(opsCaigouPlan) > 0;
    }

    @Override
    public OpsCaigouPlanVo getJinE(Long projectId) {
        LocalDateTime now = LocalDateTime.now();
        // 重置为当年1月1日0时0分0秒
        LocalDateTime startTime = now.withMonth(1)    // 月份设为1月（1-12）
            .withDayOfMonth(1)  // 日期设为1日
            .withHour(0)        // 小时设为0
            .withMinute(0)      // 分钟设为0
            .withSecond(0)      // 秒设为0
            .withNano(0);
        List<OpsCaigouPlanVo> opsCaigouPlanVos = baseMapper.selectVoList(new LambdaQueryWrapper<OpsCaigouPlan>()
            .eq(OpsCaigouPlan::getProjectId, projectId)
            .between(OpsCaigouPlan::getCreateTime, startTime, now));
        BigDecimal shijiJine = opsCaigouPlanVos.stream()
            // 步骤2：提取要累加的 totalPrice
            .map(OpsCaigouPlanVo::getShijiJine)
            // 步骤3：过滤 null（避免 NPE）
            .filter(Objects::nonNull)
            // 步骤4：累加所有 BigDecimal（初始值为 BigDecimal.ZERO）
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal yujiJine = opsCaigouPlanVos.stream()
            // 步骤2：提取要累加的 totalPrice
            .map(OpsCaigouPlanVo::getYujiJine)
            // 步骤3：过滤 null（避免 NPE）
            .filter(Objects::nonNull)
            // 步骤4：累加所有 BigDecimal（初始值为 BigDecimal.ZERO）
            .reduce(BigDecimal.ZERO, BigDecimal::add);
        OpsCaigouPlanVo opsCaigouPlanVo = new OpsCaigouPlanVo();
        opsCaigouPlanVo.setShijiJine(shijiJine);
        opsCaigouPlanVo.setYujiJine(yujiJine);
        return opsCaigouPlanVo;
    }

    @Override
    public Boolean editStatus(OpsCaigouPlanBo bo) {
        OpsCaigouPlan opsCaigouPlan = baseMapper.selectById(bo.getId());
        opsCaigouPlan.setStatus(OpsCaigouPlanEnum.YIWANCHENG.getValue());
        return baseMapper.updateById(opsCaigouPlan) > 0;
    }

    @Override
    public List<OpsCaigouPlanChanpinListVo> getChanpinList(OpsCaigouPlanReq bo) {
        return baseMapper.getChanpinList(bo.getProjectId());
    }
}
