package com.huigou.topsun.sap.costCenter.application.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.huigou.cache.DictUtil;
import com.huigou.cache.SystemCache;
import com.huigou.context.Operator;
import com.huigou.data.domain.model.CommonDomainConstants;
import com.huigou.data.query.model.QueryDescriptor;
import com.huigou.data.query.model.QueryModel;
import com.huigou.topsun.sap.common.HttpClient;
import com.huigou.topsun.sap.costCenter.application.CostCenterApplication;
import com.huigou.topsun.sap.costCenter.domain.CostCenter;
import com.huigou.topsun.sap.costCenter.domain.query.CostCenterQueryRequest;
import com.huigou.topsun.sap.costCenter.domain.vo.CostCenterMessageVo;
import com.huigou.topsun.sap.costCenter.domain.vo.CostCenterReturnVo;
import com.huigou.topsun.sap.costCenter.domain.vo.CostCenterVo;
import com.huigou.topsun.sap.costCenter.repository.CostCenterRepository;
import com.huigou.topsun.sap.exceptionReport.domain.ExceptionReport;
import com.huigou.topsun.sap.statsIndicators.domain.SapStatsIndicatorsResult;
import com.huigou.uasp.bmp.common.BizBillStatus;
import com.huigou.uasp.bpm.FlowBroker;
import com.huigou.util.ClassHelper;
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.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Auther: xin.lu
 * @Date: 2023/12/13/11:09
 * @Description:
 */
@Service("costCenterApplication")
public class CostCenterApplicationImpl extends FlowBroker implements CostCenterApplication {

    @Autowired
    private CostCenterRepository costCenterRepository;

    @Autowired
    private HttpClient httpClient;

    @Override
    public Map<String, Object> getCostCenterList(CostCenterQueryRequest costCenterQueryRequest) {
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "costCenter");
        QueryModel queryModel = this.sqlExecutorDao.getQueryModel(queryDescriptor, costCenterQueryRequest);
        queryModel.putDictionary("kosar", DictUtil.getDictionary("KOSAR"));
        queryModel.putDictionary("prctr", DictUtil.getDictionary("PRCTR"));
        queryModel.putDictionary("TYPE", DictUtil.getDictionary("TYPE"));
        queryModel.putDictionary("isCostCenterHis",DictUtil.getDictionary("isCostCenterHis"));
        queryModel.putDictionary("status",BizBillStatus.getMap());
        Map<String, Object> map = this.sqlExecutorDao.executeSlicedQuery(queryModel);
        return map;
    }

    @Override
    public CostCenterVo findCostCenterById(String id) {
        CostCenter costCenter = costCenterRepository.findOne(id);
        return CostCenterVo.getCostCenterVo(costCenter);
    }

    @Override
    public void deleteCostCenterById(List<String> ids) {
        for (String id : ids) {
            costCenterRepository.delete(id);
        }
    }

    @Override
    public void updateCostCenter(CostCenter costCenter) {
        costCenterRepository.saveAndFlush(costCenter);
    }

    @Override
    public void saveCostCenter(CostCenter costCenter) {
        costCenterRepository.save(costCenter);
    }

    @Override
    public CostCenterVo saveAndUpdate(CostCenter costCenter) {
        return CostCenterVo.getCostCenterVo(costCenterRepository.saveAndFlush(costCenter));

    }

    @Override
    public Map<String, Object> slicedCostCenterList(CostCenterQueryRequest queryRequest) {
        QueryDescriptor queryDescriptor = this.sqlExecutorDao.getQuery(QUERY_XML_FILE_PATH, "slicedCostCenterList");
        QueryModel queryModel = sqlExecutorDao.getQueryModel(queryDescriptor, queryRequest);
        return this.sqlExecutorDao.executeSlicedQuery(queryModel);
    }

    @Override
    public int updateCostCenterStatus(List<String> ids) {
        HashMap<String, Object> FREEZEReturnMap = new HashMap<>();
        FREEZEReturnMap.put("MODE", "FREEZE");
        ArrayList<HashMap<String, String>> FREEZEList = new ArrayList<>();
        int flog = 0;
        for (String id : ids) {
            CostCenter costCenter = costCenterRepository.findOne(id);
            HashMap<String, String> map = new HashMap<>();
            map.put("KOSTL", costCenter.getKostl());
            map.put("KOKRS", "BSNG");
            map.put("BKZKP", "X");
            map.put("PKZKP", "X");
            map.put("BKZKS", "X");
            map.put("PKZKS", "X");
            FREEZEList.add(map);
        }
        FREEZEReturnMap.put("FREEZE", FREEZEList);

        // TODO 列表发送,SAP返回消息怎么匹配
        String execute = send(FREEZEReturnMap);
        List<CostCenterMessageVo> costCenterMessageVos;
        try {
            costCenterMessageVos = new ObjectMapper().readValue(execute, new TypeReference<List<CostCenterMessageVo>>() {
            });
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        String[] id = (String[]) ids.toArray();
        for (CostCenterMessageVo costCenterMessageVo : costCenterMessageVos) {
            int row = Integer.parseInt(costCenterMessageVo.getROW());
            CostCenter costCenter = costCenterRepository.findOne(id[row]);
            if (!ObjectUtil.isEmpty(costCenterMessageVo) || costCenterMessageVo.getTYPE() == "S") {
                // 冻结成功,修改状态
                costCenter.setIsEnable(0);
                flog++;
            }
            BeanUtils.copyProperties(costCenterMessageVo, costCenter);
            costCenterRepository.save(costCenter);
        }
        if (ids.size() == flog)
            return 1;
        return 0;
    }

    /**
     * 流程结束事件
     */
    @Override
    protected void onEnd(DelegateExecution delegateExecution) {
        super.onEnd(delegateExecution);
        String bizId = delegateExecution.getProcessBusinessKey();
        BizBillStatus status = approvePassed() ? BizBillStatus.COMPLETED : BizBillStatus.ABORTED;
        CostCenter costCenter = costCenterRepository.findOne(bizId);
        costCenter.setStatusId(status.getId());
        this.sendSapCenterData(costCenter);
        costCenterRepository.save(costCenter);

        //基于正常的成本中心生成的冻结数据，冻结完成后删除原来正常的成本中心
        if (costCenter.getIsEnable() == 0){
            List<CostCenter> costCenterList = costCenterRepository.findByKostl(costCenter.getKostl());
            costCenterList.forEach(costCenterDb -> {
                if (!costCenterDb.getId().equals(costCenter.getId())){
                    costCenterDb.setIsDelete(1);
                    costCenterRepository.save(costCenterDb);
                }
            });
        }
    }



    @Override
    public CostCenter sendSapCenterData(CostCenter costCenter){
        // 向SAP发送新增数据
        CostCenterReturnVo costCenterReturnVo = new CostCenterReturnVo();
        BeanUtils.copyProperties(costCenter, costCenterReturnVo);

        // 封装新增返回数据
        Map<String, Object> CREATEReturnMap = new HashMap<>();
        ObjectMapper objectMapper = new ObjectMapper();
        List<Map<String,Object>> mapList = new ArrayList<>();
        if (costCenter.getIsEnable() == 1){
            CREATEReturnMap.put("MODE", "CREATE");
            HashMap data = objectMapper.convertValue(costCenterReturnVo, HashMap.class);
            mapList.add(data);
            CREATEReturnMap.put("DATA", mapList);
        }else if (costCenter.getIsEnable() == 0){
            Map<String,Object> map = new HashMap<>();
            map.put("KOSTL",costCenter.getKostl());
            mapList.add(map);
            CREATEReturnMap.put("MODE", "FREEZE");
            CREATEReturnMap.put("FREEZE", mapList);
        }
        String execute = send(CREATEReturnMap);
        CostCenterMessageVo costCenterMessageVo = null;
        List<CostCenterMessageVo> resultList = JSONObject.parseArray(execute,CostCenterMessageVo.class);
        costCenterMessageVo = resultList.get(0);
        if (!"S".equals(costCenterMessageVo.getTYPE())) {
            throw new RuntimeException("数据传输失败，"+costCenterMessageVo.getMESSAGE());
        }
        BeanUtils.copyProperties(costCenterMessageVo, costCenter);
        return costCenter;
    }

    /**
     * 向SAP发送数据
     *
     * @param o
     * @return 返回的消息
     */
    private String send(Object o) {
        String url = SystemCache.getParameter("sap.service.costCent.url", String.class);
        String execute;
        try {
            execute = httpClient.execute(o, url);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return execute;
    }

    /**
     * 封装返回JSON
     */
    private String getReturnVo(CostCenter costCenter) {
        CostCenterReturnVo costCenterReturnVo = new CostCenterReturnVo();
        BeanUtils.copyProperties(costCenter, costCenterReturnVo);
        // 转换为JSON
        ObjectMapper objectMapper = new ObjectMapper();
        String returnJson = null;
        try {
            returnJson = objectMapper.writeValueAsString(costCenterReturnVo);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
        return returnJson;
    }

    /**
     * 流程撤销事件
     **/
    @Override
    protected void onRecallProcessInstance(DelegateExecution delegateExecution) {
        String bizId = delegateExecution.getProcessBusinessKey();
        // 修改单据状态为申请
        updateStatus(bizId, BizBillStatus.APPLYING);
    }

    /**
     * 任务完成前执行
     */
    @Override
    protected void onBeforeComplete(DelegateTask delegateTask) {
        super.onBeforeComplete(delegateTask);
        String bizId = delegateTask.getExecution().getProcessBusinessKey();
        if (this.isApplyProcUnit(delegateTask) && this.getApprovalParameter().isAdvanceProcessAction()) {
            updateStatus(bizId, BizBillStatus.APPROVING);
        }
    }

    /**
     * 回收事件
     **/
    @Override
    protected void onWithdraw(DelegateTask delegateTask, String destActivityId) {
        super.onWithdraw(delegateTask, destActivityId);
        String bizId = delegateTask.getExecution().getProcessBusinessKey();
        if (destActivityId.equalsIgnoreCase("apply")) {
            updateStatus(bizId, BizBillStatus.APPLYING);
        }
    }

    @Transactional
    private void updateStatus(String bizId, BizBillStatus status) {
        Assert.hasText(bizId, CommonDomainConstants.ID_NOT_BLANK);
        this.commonDomainService.updateStatus(ExceptionReport.class, bizId, status.getId());
    }

    /**
     * 终止流程事件
     */
    @Override
    protected void onAbortProcessInstance(DelegateExecution delegateExecution) {
        super.onAbortProcessInstance(delegateExecution);
        String bizId = delegateExecution.getProcessBusinessKey();
        CostCenter costCenter = costCenterRepository.findOne(bizId);
        costCenter.setStatusId(BizBillStatus.ABORTED.getId());
        costCenterRepository.save(costCenter);
    }

    /**
     * 回退流程事件
     */
    @Override
    protected void onBack(DelegateTask delegateTask, String destActivityId) {
        super.onBack(delegateTask, destActivityId);
        if ("Apply".equalsIgnoreCase(destActivityId)) {
            String bizId = delegateTask.getExecution().getProcessBusinessKey();
            CostCenter costCenter = costCenterRepository.findOne(bizId);
            costCenter.setStatusId(BizBillStatus.APPLYING.getId());
            costCenterRepository.save(costCenter);
        }
    }

    /**
     * 获取流程参数
     * @param bizId
     * @return
     */
    @Override
    protected Map<String, Object> getProcessBizParams(String bizId) {
        return ClassHelper.toMap(costCenterRepository.getOne(bizId));
    }

    @Override
    protected String saveBizAndApprovalData() {
        super.saveBizAndApprovalData();
        CostCenter costCenter = getBizEntity(CostCenter.class);
        if (costCenter.isNew()) {
            Operator operator = this.getOperator();
            BeanUtils.copyProperties(operator, costCenter);
            costCenter.setStatusId(BizBillStatus.APPLYING.getId());

        } else {
            costCenter = (CostCenter) commonDomainService.loadAndFillinProperties(costCenter);
        }
        costCenter = costCenterRepository.save(costCenter);
        return costCenter.getId();
    }
}
