package com.yeejoin.amos.fas.business.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yeejoin.amos.component.rule.RuleTrigger;
import com.yeejoin.amos.fas.business.action.ContingencyAction;
import com.yeejoin.amos.fas.business.action.model.ContingencyEvent;
import com.yeejoin.amos.fas.business.action.model.ContingencyRo;
import com.yeejoin.amos.fas.business.action.util.ContingencyLogPublisher;
import com.yeejoin.amos.fas.business.dao.mapper.FireEquipPointMapper;
import com.yeejoin.amos.fas.business.dao.mapper.ImpAndFireEquipMapper;
import com.yeejoin.amos.fas.business.dao.mapper.PlanDetailMapper;
import com.yeejoin.amos.fas.business.dao.repository.IContingencyOriginalDataDao;
import com.yeejoin.amos.fas.business.dao.repository.IContingencyPlanInstanceRepository;
import com.yeejoin.amos.fas.business.service.intfc.IContingencyInstance;
import com.yeejoin.amos.fas.business.service.intfc.IEquipmentService;
import com.yeejoin.amos.fas.business.service.model.Operate;
import com.yeejoin.amos.fas.business.service.model.OperateGroup;
import com.yeejoin.amos.fas.dao.entity.ContingencyOriginalData;
import com.yeejoin.amos.fas.dao.entity.ContingencyPlanInstance;
import com.yeejoin.amos.fas.dao.entity.Equipment;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import java.util.*;

//import org.codehaus.jackson.map.ObjectMapper;

@Service
public class ContingencyInstanceImpl /*extends GenericManagerImpl<ContingencyPlanInstance, String>*/ implements IContingencyInstance {

    private static final Logger log = LoggerFactory.getLogger(ContingencyInstanceImpl.class);

    @Autowired
    private IContingencyPlanInstanceRepository repository;

    @Autowired
    IContingencyOriginalDataDao iContingencyOriginalDataDao;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ImpAndFireEquipMapper impAndFireEquipMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private FireEquipPointMapper fireEquipPointMapper;

    @Autowired
    private IContingencyInstance iContingencyInstance;

    @Autowired
    private IEquipmentService equipmentService;

    @Value("${station.name}")
    private String stationName;


    private static Map<String, String> stepMap = new HashMap<>();

    @Autowired
    private RuleTrigger ruleTrigger;

    @Value("${spring.application.name}")
    private String serviceName;

    /* public ContingencyInstanceImpl(IContingencyPlanInstanceRepository repository) {
         super(repository);
         this.repository = repository;
     }*/
    @Autowired
    ContingencyAction contingencyAction;

    @Autowired
    private ContingencyLogPublisher contingencyLogPublisher;
    @Autowired
    private PlanDetailMapper planDetailMapper;

    /**
     * 创建预案执行记录
     *
     * @param category    一级分类
     * @param subCategory 二级分类
     * @param content     信息内容
     * @param recordType  信息分类
     * @param icon        信息显示图标
     */
    public ContingencyPlanInstance createInstanceRecord(String instanceNo, String category, String subCategory, String content, String recordType, String icon) {
        ContingencyPlanInstance planInstance = new ContingencyPlanInstance();

        planInstance.setContent(content);
        planInstance.setIcon(icon);
        planInstance.setRecordType(recordType);
        planInstance.setCategory(category);
        planInstance.setBatchNo(instanceNo);
        planInstance.setCreateDate(new Date());
        //计算序号
        int count = repository.countByBatchNo(instanceNo);
        planInstance.setSort(++count);
        return this.repository.save(planInstance);
    }


    /**
     * 查询时间轴
     *
     * @param instanceNo
     * @return
     * @throws Exception
     */
    public List<ContingencyPlanInstance> queryForTimeLine(String instanceNo, String recordType) throws Exception {
        List<ContingencyPlanInstance> categorys = repository.queryForCategory(instanceNo, recordType);
        return categorys;
    }


    public Optional<Equipment> fire(String batchNo, String stepCode, String contingencyPlanId, String buttonCode, String buttonState, String stepStateOnbutton) throws Exception {
        //火灾误报
        ContingencyOriginalData contingencyOriginalData = iContingencyOriginalDataDao.findByBatchNo(batchNo);

        String stepKey = batchNo + "_" + stepCode;
        if (stepMap.get(stepKey) == null)
            stepMap.put(stepKey, "");
        Equipment equipment;
        if (contingencyOriginalData != null) {
            log.info("数据库中的stepcode:" + contingencyOriginalData.getStep());
            contingencyOriginalData.setConfirm(buttonState);
            contingencyOriginalData.setRunstep(false);
            if (contingencyOriginalData.getStepState() == null)
                contingencyOriginalData.setStepState("");

            if ("CONFIRM".equals(buttonState)
                    && !contingencyOriginalData.getStepState().contains(stepStateOnbutton)
                    && stepCode.equals(contingencyOriginalData.getStep()))
                contingencyOriginalData.setStepState(contingencyOriginalData.getStepState() + stepStateOnbutton);

            //请求中的步骤小于以保存的步骤
            if (Integer.parseInt(stepCode) < Integer.parseInt(contingencyOriginalData.getStep())) {
                contingencyOriginalData.setRunstep(true);
            }

            if (Integer.parseInt(stepCode) > Integer.parseInt(contingencyOriginalData.getStep())) {
                contingencyOriginalData.setStepState(stepStateOnbutton);
            }

            iContingencyOriginalDataDao.updateByButton(
                    contingencyOriginalData.getConfirm(),
                    contingencyOriginalData.getRunstep(),
                    contingencyOriginalData.getStepState(),
                    contingencyOriginalData.getBatchNo());

            //使用原始数据触发规则
            if ("CONFIRM".equals(buttonState)
                    && !stepMap.get(stepKey).contains(stepStateOnbutton))
                stepMap.put(stepKey, stepMap.get(stepKey) + stepStateOnbutton);

            ContingencyRo contingencyRo = new ContingencyRo();
            contingencyRo.setButtonCode(buttonCode);
            contingencyRo.setButtonState(buttonState);
            BeanUtils.copyProperties(contingencyOriginalData, contingencyRo);
//            SetpEnum step = SetpEnum.getStepByCode(stepCode);
            contingencyRo.setStep(stepCode);
            contingencyRo.setStepState(stepMap.get(stepKey));
//            contingencyRo.setStep(stepCode);
            log.info("stepstate:" + contingencyRo.getStepState());
            log.info("stepCode:" + stepCode);
            equipment = impAndFireEquipMapper.queryImpEqumtByFireEquipmt(Long.parseLong(contingencyRo.getFireEquipmentId()));
            if (equipment != null) {
                // 获取重点设备胚胎指标
                // 获取遥信指标
                List<Map> points = fireEquipPointMapper.getPointsByEquipmentIdAndType(equipment.getId(), "SWITCH");
                HashMap<String, Integer> telesignallingMap = new HashMap<>();
                for (Map map : points) {
                    telesignallingMap.put(map.get("code") + "", (ObjectUtils.isEmpty(map.get("value")) || "false".equals(map.get("value").toString())) ? 0 : 1);
                }
                contingencyRo.setTelesignallingMap(telesignallingMap);
                //获取遥测指标
                points = fireEquipPointMapper.getPointsByEquipmentIdAndType(equipment.getId(), "ANALOGUE");
                HashMap<String, Double> telemetryMap = new HashMap<>();
                for (Map map : points) {
                    telemetryMap.put(map.get("code") + "", Double.valueOf(ObjectUtils.isEmpty(map.get("value")) ? "0" : map.get("value").toString()));

                }
                contingencyRo.setTelemetryMap(telemetryMap);

                contingencyRo.setEquipmentCode(equipment.getCode());

                List<String> plan = this.getNumberPlan(Long.parseLong(contingencyRo.getEquipmentId()));

                ruleTrigger.publish(contingencyRo, "换流站消防专项预案/" + plan.get(0), ArrayUtils.toArray(equipment.getName()));

                publisherPlanLog(stepCode, buttonCode, batchNo);
            }
        } else {
            throw new Exception("数据异常,请联系管理员.");
        }
        return Optional.ofNullable(equipment);
    }

    private void publisherPlanLog(String stepCode, String buttonCode, String batchNo) {
        ContingencyEvent event = new ContingencyEvent(this);
        JSONObject json = new JSONObject();
        JSONObject msgContext = new JSONObject();
        JSONObject content = new JSONObject();
        content.put("stepCode", stepCode);
        content.put("buttonCode", buttonCode);
        msgContext.put("type", "clickEvent");
        msgContext.put("content", content);
        json.put("msgType", "message");
        json.put("msgContext", msgContext);
        event.setMsgBody(json.toJSONString());
        String topic = String.format("/%s/%s/%s", serviceName, stationName, "plan");
        event.setTopic(topic);
        event.setMsgType("clickEvent");
        event.setContingency(batchNo);
        contingencyLogPublisher.publish(event);
    }


    public void setButtonExecuted(String batchNo, String contingencyPlanId, String code, String buttonState) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        Optional<ContingencyPlanInstance> contingencyPlanInstance1 = repository.findById(contingencyPlanId);

        ContingencyPlanInstance contingencyPlanInstance = contingencyPlanInstance1.get();

        if (contingencyPlanInstance1.isPresent()) {
            if (contingencyPlanInstance != null && "OPERATE".equals(contingencyPlanInstance.getRecordType())) {
                String operateJson = contingencyPlanInstance.getContent();
                OperateGroup operateGroup = objectMapper.readValue(operateJson, OperateGroup.class);

                List<Operate> operates = operateGroup.getOperate();
                if (!CollectionUtils.isEmpty(operates)) {
                    for (Operate operate : operates) {

                        if (code.equals(operate.getCode()) && ("executed".equals(operate.getState()) || "disable".equals(operate.getState()))) {
                            if ("FIRE_CANCEL".equals(code) || "END_EMERGENCY".equals(code)) {
                                redisTemplate.delete(RiskSourceServiceImpl.cacheKeyForCanBeRunning());
                            }
                            throw new Exception("请勿重复操作.");
                        }


                        if ("CONFIRM".equals(buttonState)) {
                            if (code.equals(operate.getCode())) {
                                operate.setState("executed");
                                if ("FIRE_CANCEL".equals(code) || "END_EMERGENCY".equals(code))
                                    redisTemplate.delete(RiskSourceServiceImpl.cacheKeyForCanBeRunning());
                            } else {
                                operate.setState("disable");
                            }
                        }
                    }
                }


                if (buttonState.equals("CONFIRM"))
                    contingencyPlanInstance.setRunstate(true);
                operateJson = objectMapper.writeValueAsString(operateGroup);
                contingencyPlanInstance.setContent(operateJson);
                repository.save(contingencyPlanInstance);
            }
        }

    }

    public void setButtonWait(String batchNo, String contingencyPlanId, String buttonState) throws Exception {
        ObjectMapper objectMapper = new ObjectMapper();
        Optional<ContingencyPlanInstance> contingencyPlanInstance1 = repository.findById(contingencyPlanId);
        ContingencyPlanInstance contingencyPlanInstance = null;
        if (contingencyPlanInstance1.isPresent()) {
            contingencyPlanInstance = contingencyPlanInstance1.get();
        }

        if (contingencyPlanInstance != null && "OPERATE".equals(contingencyPlanInstance.getRecordType())) {
            String operateJson = contingencyPlanInstance.getContent();
            OperateGroup operateGroup = objectMapper.readValue(operateJson, OperateGroup.class);

            List<Operate> operates = operateGroup.getOperate();
            if (!CollectionUtils.isEmpty(operates)) {
                for (Operate operate : operates) {

                    if ("CONFIRM".equals(buttonState)) {
                        operate.setState("executed");
                    }
                }
            }

            if (buttonState.equals("CONFIRM"))
                contingencyPlanInstance.setRunstate(true);
            operateJson = objectMapper.writeValueAsString(operateGroup);
            contingencyPlanInstance.setContent(operateJson);
            repository.save(contingencyPlanInstance);
        }
    }


    @Override
    public void updateStep(String step, String batchNo) {
        iContingencyOriginalDataDao.updateByButtonStep(step, batchNo);
    }

    public List<String>  getNumberPlan(Long id) {
        List<String> ruleId = planDetailMapper.getRuleIdByEquipment(id);
        return ruleId;
    }
}
