package com.sifang.modules.supply.warehouse.service;

import com.google.common.collect.Maps;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Record;
import com.sifang.modules.flowable.service.ProcessFlowableService;
import com.sifang.modules.flowable.utils.FormUtils;
import com.sifang.modules.flowpath.constant.BondApplyConstant;
import com.sifang.modules.flowpath.dao.BondApplyDao;
import com.sifang.modules.flowpath.entity.CashOutApply;
import com.sifang.modules.flowpath.entity.PriceCoefficientApply;
import com.sifang.modules.flowpath.service.PriceCoefficientApplyService;
import com.sifang.modules.flowpath.vo.UserApplyVo;
import com.sifang.modules.order.utils.excelExt.ExcelReader;
import com.sifang.modules.platform.utils.PlantformUtils;
import com.sifang.modules.sunshine.SystemSetting.utils.BusinessException;
import com.sifang.modules.sunshine.SystemSetting.utils.StringUtil;
import com.sifang.modules.supply.order.constant.DeliverOrderConstants;
import com.sifang.modules.supply.order.dao.MaterialDeliverDetailDao;
import com.sifang.modules.supply.order.dao.MaterialDeliverOrderMsgDao;
import com.sifang.modules.supply.order.dao.SupplyOrderAuditDao;
import com.sifang.modules.supply.order.entity.CrmSupplyMaterialDeliverOrder;
import com.sifang.modules.supply.order.entity.CrmSupplyMaterialDeliverOrderDetail;
import com.sifang.modules.supply.stock.dao.SupplyMaterialDao;
import com.sifang.modules.supply.stock.entity.SupplyMaterial;
import com.sifang.modules.supply.stock.handler.ExcelPurchaseImportMaterialHandler;
import com.sifang.modules.supply.warehouse.vo.AddPurchaseOrderVo;
import com.sifang.modules.supply.warehouse.vo.PurchaseImportMaterialVo;
import com.sifang.modules.supply.warehouse.vo.PurchaseOrderDetailVo;
import com.sifang.modules.sys.common.UserUtils;
import com.sifang.modules.sys.common.entity.User;
import com.sifang.modules.sys.common.service.BaseService;
import com.sifang.modules.sys.common.utils.DateUtils;
import com.sifang.modules.sys.common.utils.IdGen;
import com.sifang.modules.sys.util.CrmUtils;
import com.sifang.modules.sys.util.LayuiPage;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class SupplyPurchaseOrderAuditService extends BaseService {

    @Autowired
    SupplyOrderAuditDao supplyOrderAuditDao;

    @Autowired
    private SupplyMaterialDao materialDao;

    @Autowired
    private MaterialDeliverDetailDao materialDeliverDetailDao;

    @Autowired
    private MaterialDeliverOrderMsgDao deliverOrderMsgDao;

    @Autowired
    private ProcessFlowableService flowableService;

    @Autowired
    TaskService taskService;

    @Autowired
    private BondApplyDao bondApplyDao;

    @Autowired
    private PriceCoefficientApplyService priceCoefficientApplyService;


    public void purchaseOrderAuditDate(LayuiPage page, Map<String, String> map){
        User user = UserUtils.getUser();
        List<Record> list=supplyOrderAuditDao.purchaseListData(page,map,user);
        //判断是否有审批权限
        String roleIds=user.getRoleIds();    //用户角色
        if(StringUtil.isNotBlank(roleIds) && list.size()>0){
            for(Record r:list){
                r.set("status",r.getStr("purchase_order_examine_status"));
            }
         /*   bondApplyDao.checkPermission(list,roleIds,"", FormUtils.PURCHASE_ORDER_APPLICATION);*/
        }
        Long count=supplyOrderAuditDao.purchaseListCount(map,user);
        page.setData(list);
        page.setCount(count);
    }

    public Record purchaseOrderDetail(String id){
        return supplyOrderAuditDao.orderDetail(id);
    }

    //物料信息
    public List<Record> getOrderMaterials(String id){
        List<Record> mates=supplyOrderAuditDao.getOrderMaterials(id);
        return mates;
    }

    //新建采购单
    @Transactional(rollbackFor = Exception.class)
    public void savePurchaseOrder(AddPurchaseOrderVo orderVo){
        logger.info(">>>>>>>>>>>>savePurchaseOrder  orderVo.id:{},supplyId:{}",orderVo.getId(),orderVo.getSupplierId());
        checkBeforeSave(orderVo);
        CrmSupplyMaterialDeliverOrder order;
        User user = UserUtils.getUser();
        Date date=new Date();
        short type=DeliverOrderConstants.OPT_CREATE;
        String content="新增采购单";
        if(StringUtil.isBlank(orderVo.getId())){
            order=new CrmSupplyMaterialDeliverOrder();
            order.setId(IdGen.uuid());
            order.setNumber(PlantformUtils.findOrderNumber("CG"));
            order.setType(DeliverOrderConstants.TYPE_PURCHASE);
            order.setPattern(DeliverOrderConstants.PATTERN_PLAT_PURCHASE);
            order.setSupplyId(orderVo.getSupplierId());
            order.setDeliverId(orderVo.getSupplierId());
            order.setInWarehouseId(orderVo.getInWarehouseId());
            order.setRemarks(orderVo.getRemark());
            order.setPlaceBy("a");
            order.setPlaceName(user.getUserName());
            order.setPlaceTime(date);
            order.setCreateBy(user.getId());
            order.setCreator(user.getUserName());
            order.setCreateTime(date);
        }else {
            order=supplyOrderAuditDao.get(orderVo.getId());
            order.setSupplyId(orderVo.getSupplierId());
            order.setDeliverId(orderVo.getSupplierId());
            order.setInWarehouseId(orderVo.getInWarehouseId());
            order.setRemarks(orderVo.getRemark());
            type=DeliverOrderConstants.OPT_EDIT;
            content="编辑采购单";
        }
        List<PurchaseOrderDetailVo> details= orderVo.getDetails();
        List<CrmSupplyMaterialDeliverOrderDetail> saveList=new ArrayList<>();
        int i=0;
        BigDecimal totalAmount=BigDecimal.ZERO;
        for(PurchaseOrderDetailVo detailVo:details){
            logger.info(">>>>>>>>>>>>savePurchaseOrder  detailVo.id:{}",detailVo);
            CrmSupplyMaterialDeliverOrderDetail orderDetail=new CrmSupplyMaterialDeliverOrderDetail();
            orderDetail.setMainId(order.getId());
            orderDetail.setMaterialType(detailVo.getMaterialType());
            orderDetail.setMaterialSpec(detailVo.getMaterialSpec());
            orderDetail.setMaterialId(detailVo.getMaterialId());
            orderDetail.setSalesPrice(detailVo.getSalesPrice());
            orderDetail.setPurchasePrice(detailVo.getPurchasePrice());
            orderDetail.setApplyAmount(detailVo.getApplyAmount());
            orderDetail.setOutAmount(detailVo.getApplyAmount());
            orderDetail.setSort(i++);
            orderDetail.setStatus("0");
            saveList.add(orderDetail);
            totalAmount.add(orderDetail.getApplyAmount());
        }
        order.setMaterialTypeAmount(new BigDecimal(i));
        order.setTotalApplyAmount(totalAmount);

        //拒发货编辑过来的，那么要重新启动流程审批
        if(StringUtil.isBlank(orderVo.getId()) || "b".equals(order.getStatus())){
            Record rd = FormUtils.getdefLatest(FormUtils.PURCHASE_ORDER_APPLICATION);
            if(rd == null){
                throw  new BusinessException("采购审批流程未定义，不可发布申请");
            }
            String processName="采购申请-"+user.getUserName()+'-'+ DateUtils.formatDate(date,"yyyy-MM-dd HH:mm:ss");
            String processInstanceId=flowableService.startProcessFlowable(user,order.getId(),rd,FormUtils.PURCHASE_ORDER_APPLICATION,date,user.getUserName(),orderVo.getRemark(),processName,"");
            logger.info(">>>>>>>>>>>>>savePurchaseOrder processInstanceId:{} ",processInstanceId);
            order.setPurchaseProcessInstanceId(processInstanceId);
            order.setProcessDefId(rd.getStr("id"));

            order.setOperateUserIds(user.getId()+","+rd.getStr("oneAuditUseId"));
            String taskName=FormUtils.getOneStepTaskName(rd.getStr("id"));
            order.setTaskName(taskName);

            logger.info(">>>>>>>>>>>>>>savePurchaseOrder>>>>>>>>>processInstanceId:{},taskName:{}",processInstanceId,taskName);

        }else if(StringUtil.isNotBlank(order.getPurchaseProcessInstanceId())){
            logger.info(">>>>>>>>>>>>>>savePurchaseOrder2  processInstanceId:{} ",order.getPurchaseProcessInstanceId());
           /* flowableService.approveTask(order.getTaskId(),"编辑后提交",order.getId(),user,date,FormUtils.PURCHASE_ORDER_APPLICATION,order.getProcessDefId());
            Task vacationApply = taskService.createTaskQuery().processInstanceId(order.getPurchaseProcessInstanceId()).singleResult();
            if(vacationApply!=null){
                order.setTaskName(vacationApply.getName());
                order.setTaskId(vacationApply.getId());
            }*/
            Task task = taskService.createTaskQuery().processInstanceId(order.getPurchaseProcessInstanceId()).taskAssignee(user.getId()).singleResult();
            flowableService.approveTask2(task,"编辑后提交",order.getId(),user, FormUtils.PURCHASE_ORDER_APPLICATION);
        }
        order.setStatus(DeliverOrderConstants.STATUS_PROCUREMENT_APPROVAL);
        order.setPurchaseOrderExamineStatus(BondApplyConstant.APPLYSTATUS_ONE);

        //删除历史数据
        supplyOrderAuditDao.deleteDetails(order.getId());

        supplyOrderAuditDao.save(order);

        materialDeliverDetailDao.save(saveList);
        //保存过程信息
        deliverOrderMsgDao.saveOrderOpe(order.getId(),content,user.getUserName(),user.getId(),type);
    }

    public void checkBeforeSave(AddPurchaseOrderVo orderVo){
        List<PurchaseOrderDetailVo> details = orderVo.getDetails();
        int index = 1;
        List<String> mateId=new ArrayList<>();
        for (PurchaseOrderDetailVo detail : details) {
            if(mateId.contains(detail.getMaterialId())){
                throw new BusinessException("第" + index + "行物料已添加，请勿重复添加!");
            }
            SupplyMaterial material = materialDao.get(detail.getMaterialId());
            if (!StrKit.notNull(material)) {
                throw new BusinessException("第" + index + "行物料不存在");
            }
            if (BigDecimal.ZERO.compareTo(detail.getApplyAmount()) == 0) {
                throw new BusinessException("第" + index + "行数量不能为零");
            }
        }
    }

    //审批通过
    @Transactional(rollbackFor = Exception.class)
    public void examinePurchaseOrderApprove(UserApplyVo userApplyVo){
        logger.info(">>>>>>>>>>>>>examinePurchaseOrderApprove  id:{},task:{}",userApplyVo.getId(),userApplyVo.getTaskId());
        User user = UserUtils.getUser();
        CrmSupplyMaterialDeliverOrder order=supplyOrderAuditDao.get(userApplyVo.getId());
       /* logger.info(">>>>>>>>>>>>>>>>examinePurchaseOrderApprove   taskName:{}",order.getTaskName());
        Date date=new Date();
        //审批通过
        flowableService.approveTask(order.getTaskId(),userApplyVo.getContent(),userApplyVo.getId(),user,date,FormUtils.PURCHASE_ORDER_APPLICATION,order.getProcessDefId());
        Task vacationApply = taskService.createTaskQuery().processInstanceId(order.getPurchaseProcessInstanceId()).singleResult();
        if(vacationApply!=null){
            order.setTaskName(vacationApply.getName());
            order.setTaskId(vacationApply.getId());
        }
        logger.info(">>>>>>>>>>>>>>>>examinePurchaseOrderApprove   nextTaskName:{}",order.getTaskName());
        order.setPurchaseOperateUserIds(order.getPurchaseOperateUserIds()+","+user.getId());*/
        Task task = taskService.createTaskQuery().processInstanceId(order.getPurchaseProcessInstanceId()).taskAssignee(user.getId()).singleResult();
        flowableService.approveTask2(task,userApplyVo.getContent(),order.getId(),user, FormUtils.PURCHASE_ORDER_APPLICATION);
        order.setAuditRemark(userApplyVo.getContent());
        supplyOrderAuditDao.save(order);
        //保存过程信息
        deliverOrderMsgDao.saveOrderOpe(order.getId(),"同意，"+userApplyVo.getContent(),user.getUserName(),user.getId(),DeliverOrderConstants.OPT_AUDIT_APPROVE);
    }

    //驳回    根据流程设置，初级审批不通过时，打回到【采购分配】下重新分配，本条审批记录删除；(初审中,待审批)
    @Transactional(rollbackFor = Exception.class)
    public void rejectPurchaseOrderTask(UserApplyVo userApplyVo){
        logger.info(">>>>>>>>>>>>>rejectPurchaseOrderTask  id:{},task:{}",userApplyVo.getId(),userApplyVo.getTaskId());
        User user = UserUtils.getUser();
        CrmSupplyMaterialDeliverOrder order=supplyOrderAuditDao.get(userApplyVo.getId());
        order.setAuditRemark(userApplyVo.getContent());
       /* if(DeliverOrderConstants.PATTERN_SUPPLY.equals(order.getPattern())){
             order.setStatus(DeliverOrderConstants.STATUS_PROCUREMENT_ALLOCATION);//采购分配
        }*/
       /* flowableService.rejectTask(order.getTaskId(),userApplyVo.getContent(),userApplyVo.getId(),user,FormUtils.PURCHASE_ORDER_APPLICATION);
        Task vacationApply = taskService.createTaskQuery().processInstanceId(order.getPurchaseProcessInstanceId()).singleResult();
        if(vacationApply!=null){
            order.setTaskName(vacationApply.getName());
            order.setTaskId(vacationApply.getId());
        }*/
        order.setAuditRemark(userApplyVo.getContent());
        supplyOrderAuditDao.save(order);
        Task task = taskService.createTaskQuery().processInstanceId(order.getPurchaseProcessInstanceId()).taskAssignee(user.getId()).singleResult();
        flowableService.rejectTask2(task,userApplyVo.getContent(),order.getId(),user, FormUtils.PURCHASE_ORDER_APPLICATION,order.getCreateBy());
        //保存过程信息
        deliverOrderMsgDao.saveOrderOpe(order.getId(),"驳回："+userApplyVo.getContent(),user.getUserName(),user.getId(),DeliverOrderConstants.OPT_AUDIT_FAIL);
    }

    @Transactional(rollbackFor = Exception.class)
    public void deletePurchaseOrder(String id){
        logger.info(">>>>>>>>>>>deletePurchaseOrder id:{}",id);
        User user = UserUtils.getUser();
        String userName= user.getUserName();
        //修改申请状态
        CrmSupplyMaterialDeliverOrder order=supplyOrderAuditDao.get(id);
        if(!DeliverOrderConstants.TYPE_PURCHASE.equals(order.getType())){  //新增采购单
            throw new RuntimeException("只有新增的采购单可撤销采购!");
        }
        if(StringUtil.equalsAny(order.getPurchaseOrderExamineStatus(),BondApplyConstant.APPLYSTATUS_THREE)){
            throw new RuntimeException("审批状态不允许删除!");
        }
        order.setStatus(DeliverOrderConstants.STATUS_DELETED);
        order.setPurchaseOrderExamineStatus(BondApplyConstant.APPLYSTATUS_FOUR);
        supplyOrderAuditDao.save(order);
        //删除流程
        flowableService.deleteApplication(order.getId(),order.getPurchaseProcessInstanceId(),userName,order.getPurchaseOrderExamineStatus(),FormUtils.PURCHASE_ORDER_APPLICATION);
    }
    /**
     * 校验导入的物料
     */
    @SuppressWarnings("unchecked")
    public Map<String, Object> checkImportExcel(Map<String, String> params, InputStream in) {
        Map<String, Object> retMap = Maps.newHashMap();
        retMap.put("operType", "check");
        ExcelPurchaseImportMaterialHandler handler = new ExcelPurchaseImportMaterialHandler();
        handler.setStartSheet(1);
        handler.setStartRow(2);
        try {
            new ExcelReader().check(in, params.get("extName"), handler);
            Map<String, Object> map = (Map<String, Object>) handler.getHandlerResult();
            String templateError = (String) map.get("TemplateError");
            if(!handler.isCheckFlag()){
                handler.appendErrorDetail("<p>未填充数据</p>");
            }
            String hanl = handler.getErrorDetail();
            if (StrKit.notBlank(templateError)){
                retMap.put("errorDetail", templateError);
                retMap.put("errorMessage", "y");
            }else if (StringUtils.isNotBlank(hanl)) {
                retMap.put("errorDetail", hanl);
                retMap.put("errorMessage", "y");
            } else if ("overLimit".equalsIgnoreCase((String) map.get("overLimit"))) {
                retMap.put("overLimit", "y");
            } else {
                retMap.put("pass", "y");
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return retMap;
    }

    /**
     * 导入物料数据
     */
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> importInventoryData(Map<String, String> params, InputStream in) {
        Map<String, Object> retMap = Maps.newHashMap();
        retMap.put("operType", "import");
        ExcelPurchaseImportMaterialHandler handler = new ExcelPurchaseImportMaterialHandler();
        handler.setStartSheet(1);
        handler.setStartRow(3);
        try {
            new ExcelReader().readExcel(in, params.get("fileName"), handler);
            retMap.put("pass", "y");
            List<PurchaseImportMaterialVo> materialInfos = handler.getRetList();
            //获取零售价系数
            List<Record> applies = priceCoefficientApplyService.getEffectApply();
            ;
            Map<String, BigDecimal> map = applies.stream().collect(Collectors.toMap(p -> p.getStr("material_type_id"), p -> p.getBigDecimal("coefficient")));
            List<PurchaseImportMaterialVo> list = handler.getRetList();
            for (PurchaseImportMaterialVo materialVo : list) {
                BigDecimal xs = map.get(materialVo.getMaterialTypeId());
                if (xs == null) {
                    throw new BusinessException("请先设置该" + materialVo.getMaterialName() + "的零售价系数!");
                }
                materialVo.setSalesPrice(materialVo.getPurchasePrice().multiply(xs));
            }
            retMap.put("materialList", list);
        } catch (BusinessException b) {
            throw new BusinessException(b.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return retMap;
    }

}
