package com.huigou.topsun.proofing.application.impl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huigou.data.query.model.QueryDescriptor;
import com.huigou.topsun.product.domain.ProductPublishedConf;
import com.huigou.topsun.product.repository.ProductPublishedConfRepository;
import com.huigou.topsun.proofing.application.ProofingApplyApplication;
import com.huigou.topsun.proofing.domain.proofingApply.model.*;
import com.huigou.topsun.proofing.domain.proofingApply.query.ProofingApplyQuery;
import com.huigou.topsun.proofing.domain.vo.ProofingApplyAndLookedVo;
import com.huigou.topsun.proofing.repository.proofingApply.*;
import com.huigou.uasp.bmp.common.BizBillStatus;
import com.huigou.uasp.bpm.FlowBroker;
import com.huigou.util.ClassHelper;
import com.huigou.util.SDO;
import com.huigou.util.StringUtil;
import lombok.SneakyThrows;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.DelegateTask;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.Map;

/**
 * @author yonghuan
 */
@Service("proofingApplyApplication")
public class ProofingApplyApplicationImpl extends FlowBroker implements ProofingApplyApplication {

    @Autowired
    private ProofingApplyRepository proofingApplyRepository;
    @Autowired
    private ProductPublishedConfRepository productPublishedConfRepository;
    @Autowired
    private ProofingApplyLookedRepository proofingApplyLookedRepository;
    @Autowired
    private ProofingApplyTechnologyRepository proofingTechnologyRepository;
    @Autowired
    private ProofingApplyProcessRepository proofingApplyProcessRepository;
    @Autowired
    private ProofingApplyProcessMaterialRepository proofingApplyProcessMaterialRepository;

    @Autowired
    private ProofingApplyBomRepository proofingApplyBomRepository;


    @Override
    public ProofingApplyBaseInfo loadProofingApplyById(String id) {
        return proofingApplyRepository.findOne(id);
    }

    @Override
    public Map<String, Object> slicedQuery(ProofingApplyQuery query) {
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "slicedQuery");
        return this.sqlExecutorDao.executeSlicedQuery(queryDescriptor, query);
    }

    @SneakyThrows
    @Transactional(propagation = Propagation.REQUIRES_NEW)
//    @Transactional(propagation = Propagation.NEVER)
    @Override
    protected String saveBizAndApprovalData() {
        super.saveBizAndApprovalData();
        ProofingApplyBaseInfo proofingApply = getBizEntity(ProofingApplyBaseInfo.class);
        if (proofingApply.isNew()) {
            proofingApply.setStatusId(BizBillStatus.APPLYING.getId());
        } else {
            proofingApply = (ProofingApplyBaseInfo) commonDomainService.loadAndFillinProperties(proofingApply);
        }

        //如果录入了ng重新打样原因，则更改状态为不通过
        if (!StringUtil.isBlank(proofingApply.getProofingApplyNgReReason())) {
            proofingApply.setProofingApplyApplicationStatus("2");
        }
        proofingApply = proofingApplyRepository.save(proofingApply);


        SDO sdo = this.getBizAndApprovalData();
        String technologyJSON = sdo.getString("technology");
        String processJSON = sdo.getString("process");
        String processMaterialJSON = sdo.getString("processMaterial");

        ObjectMapper objectMapper = new ObjectMapper();
        ProofingApplyTechnology proofingTechnology = objectMapper.readValue(technologyJSON, ProofingApplyTechnology.class);
        List<ProofingApplyProcess> processList = objectMapper.readValue(processJSON, new TypeReference<List<ProofingApplyProcess>>() {
        });
        List<ProofingApplyProcessMaterial> processMaterialList = objectMapper.readValue(processMaterialJSON, new TypeReference<List<ProofingApplyProcessMaterial>>() {
        });

        ProofingApplyLooked proofingApplyLooked = getBizEntity(ProofingApplyLooked.class);


        ProofingApplyLooked looked = proofingApplyLookedRepository.findByProofingApplyId(proofingApply.getProofingApplyId());
        //录入ProofingApplyLooked是先判断是需要新增还是修改
        proofingApplyLooked.setProofingApplyLookedId(looked != null ? looked.getProofingApplyLookedId() : null);
        proofingApplyLooked.setProofingApplyId(proofingApply.getProofingApplyId());
        proofingApplyLookedRepository.save(proofingApplyLooked);

        /*
         * 将样品的相关工艺工序等删除
         */
        List<ProofingApplyTechnology> technologiesToDelete = proofingTechnologyRepository.findAllByProofingApplyId(proofingApply.getProofingApplyId());
        if (!technologiesToDelete.isEmpty()) {
            ProofingApplyTechnology technologyToDelete = technologiesToDelete.get(0);
            String proofingApplyTechnologyId = technologyToDelete.getProofingApplyTechnologyId();
            proofingTechnologyRepository.delete(technologyToDelete);
            List<ProofingApplyProcess> processesToDelete = proofingApplyProcessRepository.findAllByProofingApplyTechnologyId(proofingApplyTechnologyId);
            proofingApplyProcessRepository.deleteInBatch(processesToDelete);

            List<ProofingApplyProcessMaterial> ProofingApplyTechnologyList = proofingApplyProcessMaterialRepository.findByProofingApplyTechnologyId(proofingApplyTechnologyId);
            proofingApplyProcessMaterialRepository.deleteInBatch(ProofingApplyTechnologyList);
        }
        //添加样品及工艺
        proofingTechnology.setProofingApplyId(proofingApply.getProofingApplyId());
        proofingTechnology.setProofingApplyTechnologyId(null);
        proofingTechnology = proofingTechnologyRepository.save(proofingTechnology);

        for (ProofingApplyProcess proofingApplyProcess : processList) {
            proofingApplyProcess.setProofingApplyProcessId(null);
            proofingApplyProcess.setProofingApplyTechnologyId(proofingTechnology.getProofingApplyTechnologyId());
            proofingApplyProcessRepository.saveAndFlush(proofingApplyProcess);
        }

        for (ProofingApplyProcessMaterial proofingApplyProcessMaterial : processMaterialList) {
            proofingApplyProcessMaterial.setProofingApplyProcessMaterialId(null);
            proofingApplyProcessMaterial.setProofingApplyTechnologyId(proofingTechnology.getProofingApplyTechnologyId());
            proofingApplyProcessMaterialRepository.saveAndFlush(proofingApplyProcessMaterial);
        }

        // 保存BOM信息
        String bomJson = sdo.getString("bom");
        if (StringUtil.isNotBlank(bomJson)) {
            // 获取前端传来的BOM列表
            // 判断是否为新增还是修改
            ProofingApplyBom proofingApplyBom1 = new ProofingApplyBom();
            proofingApplyBom1.setProofingApplyId(proofingApply.getProofingApplyId());
            List<ProofingApplyBom> applyBomList = proofingApplyBomRepository.findAll(Example.of(proofingApplyBom1));
            if (!applyBomList.isEmpty()) {
                // 修改 -- 删除
                applyBomList.forEach(proofingApplyBom -> proofingApplyBomRepository.delete(proofingApplyBom.getProofingApplyBomId()));
            }

            List<ProofingApplyBom> proofingApplyBomList = objectMapper.readValue(bomJson, new TypeReference<List<ProofingApplyBom>>() {
            });
            // 新增
            for (ProofingApplyBom proofingApplyBom : proofingApplyBomList) {
                proofingApplyBom.setProofingApplyId(proofingApply.getProofingApplyId());
                // 保存
                proofingApplyBomRepository.save(proofingApplyBom);
            }
        }
        // 封装保存
        return proofingApply.getId();
    }


    @Override
    protected Map<String, Object> getProcessBizParams(String bizId) {
        // 返回业务数据给流程实例，
        return ClassHelper.toMap(proofingApplyRepository.getOne(bizId));
    }

    @Override
    protected void onEnd(DelegateExecution delegateExecution) {
        super.onEnd(delegateExecution);
        String bizId = delegateExecution.getProcessBusinessKey();
        BizBillStatus status = approvePassed() ? BizBillStatus.COMPLETED : BizBillStatus.ABORTED;
        ProofingApplyBaseInfo proofingApply = proofingApplyRepository.findOne(bizId);
        proofingApply.setStatusId(status.getId());
        proofingApplyRepository.save(proofingApply);
    }

    @Override
    protected void onAbortProcessInstance(DelegateExecution delegateExecution) {
        super.onAbortProcessInstance(delegateExecution);
        String bizId = delegateExecution.getProcessBusinessKey();
        ProofingApplyBaseInfo proofingApply = proofingApplyRepository.findOne(bizId);
        proofingApply.setStatusId(BizBillStatus.ABORTED.getId());
        proofingApplyRepository.save(proofingApply);
    }

    /**
     * @param delegateTask
     * @param destActivityId 回退到的目标节点id
     */
    @Override
    protected void onBack(DelegateTask delegateTask, String destActivityId) {
        super.onBack(delegateTask, destActivityId);
        if ("Apply".equalsIgnoreCase(destActivityId)) {
            String bizId = delegateTask.getExecution().getProcessBusinessKey();
            ProofingApplyBaseInfo proofingApply = proofingApplyRepository.findOne(bizId);
            proofingApply.setStatusId(BizBillStatus.APPLYING.getId());
            proofingApplyRepository.save(proofingApply);
        }
    }


    public ProofingApplyAndLookedVo getProofingApplyByProofingApplyNo(String proofingApplyNo) {
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "queryProofingApplyAndProductQuery");
        ProofingApplyAndLookedVo proofingApplyAndLookedVo = this.sqlExecutorDao.queryToObject(queryDescriptor.getSql(), ProofingApplyAndLookedVo.class, proofingApplyNo);
        ProductPublishedConf productPublishedConf = productPublishedConfRepository.findByProductId(new BigDecimal(proofingApplyAndLookedVo.getProductId()));
        if (productPublishedConf != null) {
            BeanUtils.copyProperties(productPublishedConf, proofingApplyAndLookedVo);
        }
        return proofingApplyAndLookedVo;
    }


    @Override
    public ProofingApplyBaseInfo selectProofingApplyByProofingApplyNo(String proofingApplyNo) {
        return proofingApplyRepository.findByProofingApplyNo(proofingApplyNo);
    }

}