package com.junmp.jyzb.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.junmp.jyzb.api.bean.dto.PlanInitTypeDto;
import com.junmp.jyzb.api.bean.dto.PlanInitiationItemDto;
import com.junmp.jyzb.api.bean.req.PlanInitiationReq;
import com.junmp.jyzb.api.bean.req.UpdateOrderDetailReq;
import com.junmp.jyzb.api.bean.req.UpdateOrderReq;
import com.junmp.jyzb.api.bean.vo.PlanInitOrgTypeVo;
import com.junmp.jyzb.api.bean.vo.PlanInitTypeVo;
import com.junmp.jyzb.api.bean.vo.PlanOrgTypeVo;
import com.junmp.jyzb.api.bean.vo.PlanTypeVo;
import com.junmp.jyzb.api.exception.JYZBAppException;
import com.junmp.jyzb.api.exception.enums.OrderExceptionEnum;
import com.junmp.jyzb.api.exception.enums.UserExceptionEnum;
import com.junmp.jyzb.entity.*;
import com.junmp.jyzb.mapper.OrderMainMapper;
import com.junmp.jyzb.service.*;
import com.junmp.jyzb.mapper.PlanInitiationMapper;
import com.junmp.jyzb.utils.DateTimeUtil;
import com.junmp.v2.common.util.BeanPlusUtil;
import com.junmp.v2.db.api.entity.BaseEntity;
import com.junmp.v2.db.api.factory.PageFactory;
import com.junmp.v2.db.api.factory.PageResultFactory;
import com.junmp.v2.db.api.page.PageResult;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * <pre>
 *
 * 描述：
 * 版本：1.0.0
 * 日期：2024/6/3 9:47
 * 作者：hanz@junmp.com.cn
 * <br>修改记录
 * <br>修改日期        修改人          修改内容
 *
 * </pre>
 */
@Service
@Transactional
public class PlanInitiationServiceImpl extends ServiceImpl<PlanInitiationMapper, PlanInitiation> implements PlanInitiationService{
    @Resource
    private PlanInitiationItemService planInitiationItemService;
    @Resource
    private OrderMainService orderMainService;
    @Resource
    private OrderMainMapper orderMainMapper;

    @Resource
    private BusFormService busFormService;

    /**
     * 分页查询发起预案信息
     * @param req
     * @return
     */
    @Override
    public PageResult<PlanInitiation> getPage(PlanInitiationReq req) {
        LambdaQueryWrapper<PlanInitiation> wp = this.createWrappers(req);
        Page<PlanInitiation> page = this.page(PageFactory.getDefaultPage(req), wp);
        return PageResultFactory.createPageResult(page);
    }

    /**
     * 查询发起预案信息集合
     * @param req
     * @return
     */
    @Override
    public List<PlanInitiation> getList(PlanInitiationReq req) {
        LambdaQueryWrapper<PlanInitiation> wp = this.createWrappers(req);
        return this.list(wp);
    }

    /**
     * 查询发起预案信息详情
     * @param req
     * @return
     */
    @Override
    public PlanInitiation getDetail(PlanInitiationReq req) {
        PlanInitiation one = getById(req.getPlanId());
        List<PlanOrgTypeVo> voList = planInitiationItemService.getDetail(req);
        Map<Long, List<PlanOrgTypeVo>> map = planDetailMap(voList);
        List<PlanTypeVo> list = voList.stream().map(dto -> {
            List<PlanOrgTypeVo> vos = map.get(dto.getTypeId());
            Integer planNum = CollectionUtil.isNotEmpty(vos) ? vos.stream().mapToInt(PlanOrgTypeVo::getPlanNum).sum() : 0;
            Integer actualNum = CollectionUtil.isNotEmpty(vos) ? vos.stream().mapToInt(PlanOrgTypeVo::getActualNum).sum() : 0;

            PlanTypeVo vo = BeanPlusUtil.toBean(dto, PlanTypeVo.class);
            vo.setPlanNum(planNum);
            vo.setActualNum(actualNum);
            vo.setVoList(vos);
            return vo;
        }).distinct().collect(Collectors.toList());
        one.setDetailList(list);
        return one;
    }

    private Map<Long, List<PlanOrgTypeVo>> planDetailMap(List<PlanOrgTypeVo> list) {
        Map<Long, List<PlanOrgTypeVo>> map = new HashMap<>();
        for (PlanOrgTypeVo dto : list) {
            if (ObjectUtil.isNotNull(dto.getTypeId())) {
                List<PlanOrgTypeVo> orderList = map.get(dto.getTypeId());
                if (CollectionUtil.isEmpty(orderList)) {
                    orderList = new ArrayList<>();
                }
                orderList.add(dto);
                map.put(dto.getTypeId(), orderList);
            }
        }
        return map;
    }

    /**
     * 添加发起预案信息
     * @param req
     * @return
     */
    @Override
    public Boolean add(PlanInitiationReq req) {
        PlanInitiation bean = BeanPlusUtil.toBean(req, PlanInitiation.class);
        if (ObjectUtil.isNull(req.getPlanId())){
            //创建单号
            OrderNum orderNum = busFormService.setOrderCode("planInitiation", req.getStartOrgId());
            String codeValue=String.format("%05d",orderNum.getNum());
            bean.setPlanCode("预-"+orderNum.getYear()+"-"+codeValue);
            boolean flag = this.save(bean);
            if (flag) {
                return this.startPlan(req, bean);
            }
            return false;
        } else {
            boolean flag = this.updateById(bean);
            if (flag) {
                return this.startPlan(req, bean);
            }
            return false;
        }

    }

    /**
     * 发起预案
     * @param req
     * @param bean
     * @return
     */
    private Boolean startPlan(PlanInitiationReq req, PlanInitiation bean) {
        Map<String,String> orderMap = new HashMap<>();
//        //若需要发起预案，则发起领用单据
//        Boolean bool = true;
//        if (req.getIsStart().equals(0)){
//            bool = this.createOrderMain(req, orderMap);
//        }
        planInitiationItemService.remove(Wrappers.<PlanInitiationItem>lambdaQuery().eq(PlanInitiationItem::getPlanId, req.getPlanId()));
        //添加预案单据项
        List<PlanInitiationItem> itemList = req.getDtoList().stream().map(dto -> {
            PlanInitiationItem item = BeanPlusUtil.toBean(dto, PlanInitiationItem.class);
            item.setItemId(null);
            item.setPlanId(bean.getPlanId());
            item.setOrderId(StrUtil.isNotEmpty(orderMap.get(dto.getStartOrgId())) ? orderMap.get(dto.getStartOrgId()) : "0");
            return item;
        }).collect(Collectors.toList());
        return planInitiationItemService.saveBatch(itemList);
    }

    /**
     * 发起领用单据
     *
     * @param req
     */
    public Boolean createUseOrder(PlanInitiationReq req) {
        Map<String,String> orderMap = new HashMap<>();
        Map<String, List<UpdateOrderDetailReq>> map = toOrderMap(req.getDtoList(),"out");
        List<UpdateOrderReq> reqList = req.getDtoList().stream()
                .map(dto -> {
            UpdateOrderReq orderReq = new UpdateOrderReq();
            orderReq.setStartOrgId(dto.getStartOrgId());
            orderReq.setStartOrgName(dto.getStartOrgName());
            orderReq.setEndOrgId(req.getEndOrgId());
            orderReq.setEndOrgName(req.getEndOrgName());
            orderReq.setOrderType("out");
            orderReq.setBussinessType("use");
            orderReq.setExamineState("finished");
            orderReq.setOrderState("ready");
            orderReq.setReturnUserId(req.getEndOrgUserId());
            orderReq.setReturnUser(req.getEndOrgUserName());
            orderReq.setEndOrgUserId(req.getEndOrgUserId());
            orderReq.setEndOrgUserName(req.getEndOrgUserName());
            orderReq.setUseDate(DateTimeUtil.getCurrentDateTime());
            return orderReq;
        }).distinct().collect(Collectors.toList());
        for (UpdateOrderReq orderReq : reqList) {
            String invList = req.getDtoList().stream()
                    .map(PlanInitiationItemDto::getTypeName).distinct().collect(Collectors.joining(", "));
            int sum = req.getDtoList().stream()
                    .mapToInt(PlanInitiationItemDto::getPlanNum).sum();
            orderReq.setInventoryQuantity(sum);
            orderReq.setInvList(invList);
            orderReq.setDetailList(map.get(orderReq.getStartOrgId()));
            List<String> strings = orderMainService.AddOrder(orderReq);
            if (CollectionUtil.isEmpty(strings)){
                return false;
            }
            orderMap.put(orderReq.getStartOrgId(), strings.get(0));
        }
        //查询出有哪些领用单号
        List<PlanInitiationItem> list = planInitiationItemService
                .list(new LambdaQueryWrapper<PlanInitiationItem>().
                        eq(PlanInitiationItem::getPlanId, req.getPlanId()));
        List<PlanInitiationItem> collect = list.stream().map(dto -> {
            dto.setOrderId(StrUtil.isNotEmpty(orderMap.get(dto.getStartOrgId())) ? orderMap.get(dto.getStartOrgId()) : "0");
            return dto;
        }).collect(Collectors.toList());

        //下发后将预案单状态更新为待归还
        this.update(Wrappers.<PlanInitiation>lambdaUpdate().set(PlanInitiation::getState, 2)
                .eq(PlanInitiation::getPlanId, req.getPlanId()));
        return planInitiationItemService.updateBatchById(collect);
    }

    /**
     * 创建归还单
     * @param req
     * @return
     */
    @Override
    @Transactional
    public Boolean createReturnOrder(PlanInitiationReq req) {
        PlanInitiation plan = this.getById(req.getPlanId());
        if (ObjectUtil.isNull(plan)){
            throw new JYZBAppException(OrderExceptionEnum.ORDER_NOT_EXIST);
        }
        //将判断预案完成的数量是多少进行生成归还单
        List<PlanOrgTypeVo> dtoList = planInitiationItemService.getDetail(req);
        List<String> collect = dtoList.stream().map(PlanOrgTypeVo::getOrderId).distinct().collect(Collectors.toList());
        //校验该预案单生成的出库单是否存在尚未记账的,若存在,则不允许归还
        if (CollectionUtil.isNotEmpty(collect)){

            //将未记账的单子在dtoList中进行删除（未记账的领用出库单直接不需要进行归还操作）-- 或者记账数量全为0的单子
            dtoList = dtoList.stream().filter(dto -> !dto.getOrderId().equals("0")).collect(Collectors.toList());
            dtoList = dtoList.stream()
                    .collect(Collectors.groupingBy(PlanOrgTypeVo::getOrderId))  // 按 orderId 进行分组
                    .values().stream()  // 获取分组后的值
                    .flatMap(group -> group.stream()
                            .anyMatch(order -> order.getActualNum() != 0)  // 如果有 real_num 不为 0，则保留该组
                            ? group.stream() : group.stream().filter(order -> false))  // 否则过滤掉该组
                    .collect(Collectors.toList());
        }

        //归还单ids列表
        List<String> collect1=new ArrayList<>();
        List<OrderMain> orderList = orderMainService.list(
                new LambdaQueryWrapper<OrderMain>().in(OrderMain::getId, collect));

        Map<String, List<UpdateOrderDetailReq>> map = new HashMap<>();
        if (CollectionUtil.isNotEmpty(dtoList)){
            List<PlanInitiationItemDto> beanList = BeanPlusUtil.toBeanList(dtoList, PlanInitiationItemDto.class);
            map=toOrderMap(beanList,"in");
        }

        List<UpdateOrderReq> reqList = dtoList.stream()
                .map(dto -> {
                    UpdateOrderReq orderReq = new UpdateOrderReq();
                    orderReq.setStartOrgId(req.getEndOrgId().toString());
                    orderReq.setStartOrgName(req.getEndOrgName());
                    orderReq.setOrderType("in");
                    orderReq.setBussinessType("return");
                    orderReq.setExamineState("finished");
                    orderReq.setOrderState("ready");
                    orderReq.setEndOrgId(dto.getStartOrgId());
                    orderReq.setEndOrgName(dto.getStartOrgName());
                    orderReq.setReturnUserId(req.getEndOrgUserId());
                    orderReq.setReturnUser(req.getEndOrgUserName());
                    orderReq.setStartOrgUserId(req.getEndOrgUserId());
                    orderReq.setStartOrgUserName(req.getEndOrgUserName());
                    orderReq.setUseDate(DateTimeUtil.getCurrentDateTime());
                    Optional<OrderMain> first = orderList.stream()
                            .filter(orderMain -> String.valueOf(orderMain.getStartOrgId()).equals(dto.getStartOrgId().toString()))
                            .findFirst();
                    if (first.isPresent()){
                        OrderMain orderMain = first.get();
                        orderMain.setOrderCurrentState(0);
                        orderReq.setBussinessCode(orderMain.getOrderCode());
                    }
                    return orderReq;
                }).distinct().collect(Collectors.toList());

        for (UpdateOrderReq orderReq : reqList) {
            String invList = dtoList.stream()
                    .map(PlanOrgTypeVo::getTypeName).distinct().collect(Collectors.joining(", "));
            int sum = dtoList.stream()
                    .mapToInt(PlanOrgTypeVo::getPlanNum).sum();
            orderReq.setInventoryQuantity(sum);
            orderReq.setInvList(invList);
            orderReq.setDetailList(map.get(orderReq.getEndOrgId().toString()));
            List<String> strings = orderMainService.AddOrder(orderReq);
            if (CollectionUtil.isEmpty(strings)){
                return false;
            }else {
                collect1.add(strings.get(0));
            }
            orderMainService.updateBatchById(orderList);
        }
        //记完账之后将detailJson进行赋值，否则记账报错
        //直接update方法进行更新
        if (CollectionUtil.isNotEmpty(collect) && CollectionUtil.isNotEmpty(collect1)){

            orderMainMapper.updateToReturnOrder(collect,collect1);
        }

        //归还后将预案单状态更新为已完成
        this.update(Wrappers.<PlanInitiation>lambdaUpdate().set(PlanInitiation::getState, 3)
                .eq(PlanInitiation::getPlanId, req.getPlanId()));
        return true;
    }

    /**
     * 提取各个发物单位的装备数据
     * @param list
     * @return
     */
    private Map<String, List<UpdateOrderDetailReq>> toOrderMap(List<PlanInitiationItemDto> list,String type) {
        Map<String, List<UpdateOrderDetailReq>> map = new HashMap<>();
        for (PlanInitiationItemDto dto : list) {
            if (StrUtil.isNotEmpty(dto.getStartOrgId())) {
                List<UpdateOrderDetailReq> orderList = map.get(dto.getStartOrgId());
                if (CollectionUtil.isEmpty(orderList)) {
                    orderList = new ArrayList<>();
                }
                UpdateOrderDetailReq bean = BeanPlusUtil.toBean(dto, UpdateOrderDetailReq.class);
                bean.setTotalPrice(BigDecimal.ZERO);
                bean.setType(type);
                orderList.add(bean);
                map.put(dto.getStartOrgId(), orderList);
            }
        }
        return map;
    }

    /**
     * 更新发起预案信息
     * @param req
     * @return
     */
    @Override
    public Boolean edit(PlanInitiationReq req) {
        PlanInitiation bean = BeanPlusUtil.toBean(req, PlanInitiation.class);
        bean.setUpdateTime(new Date());
        boolean flag = this.updateById(bean);
        List<PlanInitiationItemDto> dtoList = req.getDtoList().stream().filter(dto -> ObjectUtil.isNull(dto.getItemId())).collect(Collectors.toList());
        if (flag && CollectionUtil.isNotEmpty(dtoList) && dtoList.size() > 0) {
            planInitiationItemService.remove(Wrappers.<PlanInitiationItem>lambdaQuery().eq(PlanInitiationItem::getPlanId, bean.getPlanId()));
            List<PlanInitiationItem> itemList = req.getDtoList().stream().map(dto -> {
                PlanInitiationItem item = BeanPlusUtil.toBean(dto, PlanInitiationItem.class);
                item.setItemId(null);
                item.setPlanId(bean.getPlanId());
                return item;
            }).collect(Collectors.toList());
            planInitiationItemService.saveBatch(itemList);
        }
        return flag;
    }

    /**
     * 删除发起预案信息
     * @param req
     * @return
     */
    @Override
    public Boolean delete(PlanInitiationReq req) {
        boolean flag = this.removeById(req);
        if (flag){
            planInitiationItemService.remove(Wrappers.<PlanInitiationItem>lambdaQuery()
                    .eq(PlanInitiationItem::getPlanId, req.getPlanId()));
        }
        return flag;
    }

    /**
     * 根据装备获取其库存信息
     * @param req
     * @return
     */
    @Override
    public List<PlanInitTypeVo> getDetailList(PlanInitiationReq req) {
        List<PlanInitTypeDto> dtoList = req.getTypeList();
        List<String> typeIdList = dtoList.stream().map(PlanInitTypeDto::getTypeId).distinct().collect(Collectors.toList());
        List<PlanInitOrgTypeVo> voList = baseMapper.getDetailList(req.getOrgId(), typeIdList);

        List<PlanInitTypeVo> list = BeanPlusUtil.toBeanList(dtoList, PlanInitTypeVo.class);
        for (PlanInitTypeVo typeVo : list) {
            List<PlanInitOrgTypeVo> typeVoList = voList.stream().filter(vo -> vo.getTypeId().equals(typeVo.getTypeId())).collect(Collectors.toList());
            int sum = voList.stream().filter(vo -> vo.getTypeId().equals(typeVo.getTypeId())).mapToInt(PlanInitOrgTypeVo::getStockNum).sum();
            typeVo.setStockNum(sum);
            typeVo.setRealNum(typeVo.getPlanNum());
            typeVo.setVoList(typeVoList);
        }

        return list;
    }

    /**
     * 查询发起预案单信息详情
     * @param req
     * @return
     */
    @Override
    public List<PlanInitTypeVo> getPlanDetail(PlanInitiationReq req) {
        List<PlanInitTypeVo> arrayList = planInitiationItemService.getPlanInfo(req);

        List<String> typeIdList = arrayList.stream().map(PlanInitTypeVo::getTypeId).distinct().collect(Collectors.toList());
        List<PlanInitOrgTypeVo> allList = baseMapper.getDetailList(req.getOrgId(), typeIdList);

        List<PlanInitOrgTypeVo> voList = planInitiationItemService.getPlanDetail(req.getPlanId());
        for (PlanInitOrgTypeVo allVo : allList) {
            for (PlanInitOrgTypeVo vo : voList) {
                if (allVo.getStartOrgId().equals(vo.getStartOrgId()) && allVo.getTypeId().equalsIgnoreCase(vo.getTypeId())){
                    allVo.setPlanNum(vo.getPlanNum());
                }
            }
        }

        for (PlanInitTypeVo typeVo : arrayList) {
            List<PlanInitOrgTypeVo> typeVoList = allList.stream().filter(vo -> vo.getTypeId().equals(typeVo.getTypeId())).collect(Collectors.toList());
            int sum = allList.stream().filter(vo -> vo.getTypeId().equals(typeVo.getTypeId())).mapToInt(PlanInitOrgTypeVo::getStockNum).sum();
            typeVo.setStockNum(sum);
            typeVo.setRealNum(typeVo.getPlanNum());
            typeVo.setVoList(typeVoList);
        }

        return arrayList;
    }

    /**
     * 手动更新完成状态
     * @param req
     * @return
     */
    @Override
    public Boolean updateToFinished(PlanInitiationReq req) {
        PlanInitiation initiation = getById(req.getPlanId());
        initiation.setState(ObjectUtil.isNotNull(req.getState())? req.getState() : 2);
        return updateById(initiation);
    }

    /**
     * 构建查询条件
     * @param req
     * @return
     */
    private LambdaQueryWrapper<PlanInitiation> createWrappers(PlanInitiationReq req) {
        LambdaQueryWrapper<PlanInitiation> wp = Wrappers.<PlanInitiation>lambdaQuery();
        wp.like(StrUtil.isNotEmpty(req.getPlace()), PlanInitiation::getPlace, req.getPlace());
        wp.like(StrUtil.isNotEmpty(req.getPlanName()), PlanInitiation::getPlanName, req.getPlanName());
        wp.ge(StrUtil.isNotEmpty(req.getStartTime()), BaseEntity::getCreateTime, req.getStartTime());
        wp.le(StrUtil.isNotEmpty(req.getEndTime()), BaseEntity::getCreateTime, req.getEndTime());
        wp.eq(ObjectUtil.isNotEmpty(req.getEndOrgId()), PlanInitiation::getEndOrgId, req.getEndOrgId());
        wp.eq(ObjectUtil.isNotEmpty(req.getStartOrgId()), PlanInitiation::getStartOrgId, req.getStartOrgId());
        wp.like(ObjectUtil.isNotEmpty(req.getEndOrgName()), PlanInitiation::getEndOrgName, req.getEndOrgName());
        wp.like(ObjectUtil.isNotEmpty(req.getStartOrgName()), PlanInitiation::getStartOrgName, req.getStartOrgName());
        wp.eq(ObjectUtil.isNotEmpty(req.getEndOrgUserId()), PlanInitiation::getEndOrgUserId, req.getEndOrgUserId());
        wp.like(ObjectUtil.isNotEmpty(req.getEndOrgUserName()), PlanInitiation::getEndOrgUserName, req.getEndOrgUserName());
        wp.eq(ObjectUtil.isNotNull(req.getState()), PlanInitiation::getState, req.getState());
        wp.orderByDesc(BaseEntity::getCreateTime);
        return wp;
    }
}




