package com.yihu.hos.rest.services.crawler;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yihu.hos.core.datatype.CollectionUtil;
import com.yihu.hos.core.datatype.StringUtil;
import com.yihu.hos.core.log.Logger;
import com.yihu.hos.core.log.LoggerFactory;
import com.yihu.hos.rest.common.dao.CrawlerDatasetDao;
import com.yihu.hos.rest.common.dao.CrawlerFlowDao;
import com.yihu.hos.rest.common.dao.CrawlerFlowHeadDao;
import com.yihu.hos.rest.common.format.AdapterBase;
import com.yihu.hos.rest.models.crawler.adapter.AdapterDataSet;
import com.yihu.hos.rest.models.crawler.config.SysConfig;
import com.yihu.hos.rest.models.crawler.flow.CrawlerDataSetModel;
import com.yihu.hos.rest.models.crawler.flow.CrawlerFlowHeadModel;
import com.yihu.hos.rest.models.crawler.flow.CrawlerFlowModel;
import com.yihu.hos.rest.models.crawler.patient.Patient;
import com.yihu.hos.rest.models.standard.adapter.AdapterDatasetModel;
import com.yihu.hos.rest.models.standard.adapter.AdapterDictEntryModel;
import com.yihu.hos.rest.models.standard.adapter.AdapterSchemeVersionModel;
import com.yihu.hos.rest.models.standard.bo.AdapterVersion;
import com.yihu.hos.rest.services.standard.adapter.*;
import com.yihu.hos.web.framework.model.DictItem;
import com.yihu.hos.web.framework.model.Result;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.*;

@Service("CrawlerFlowManager")
public class CrawlerFlowManager {

    private static Logger logger = LoggerFactory.getLogger(CrawlerFlowManager.class);

    private static DataCollectDispatcher dispatch = DataCollectDispatcher.getInstance();
    private static SysConfig sysConfig = SysConfig.getInstance();
    private Map<String, AdapterDataSet> adapterDataSetMap;
    private List<CrawlerFlowHeadModel> crawlerFlowHeadModelList;
    private Map<String, List<CrawlerFlowModel>> crawlerFlowDatasetMap;
    private Map<String, List<CrawlerFlowModel>> crawlerFlowMetadataMap;
    private Boolean adapterFlg = false;
    private List<DictItem> datasetList;
    private String schemeVersion;
    @Resource
    private AdapterDatasetService adapterDatasetService;
    @Resource
    private AdapterMetadataService adapterMetadataService;
    @Resource
    private AdapterDictService adapterDictService;
    @Resource
    private AdapterSchemeVersionService adapterSchemeVersionService;
    @Resource
    CrawlerDatasetDao crawlerDatasetDao;
    @Resource
    CrawlerFlowHeadDao crawlerFlowHeadDao;
    @Resource
    CrawlerFlowDao crawlerFlowDao;

    public CrawlerFlowManager(List datasetList, String schemeVersion) {
        this.datasetList = datasetList;
        this.schemeVersion = schemeVersion;
    }

    public CrawlerFlowManager() {
    }

    public void finalize() throws Throwable {

    }

    public Result dataCrawler(Date beginDate, Date endDate) {
        Map<String, Object> condition = new HashMap<>();
        condition.put("beginDate", beginDate);
        condition.put("endDate", endDate);
        Integer count = 0;
        Integer totalCount = 0;
        String message;
        /**
         * 适配基本数据准备
         */
        if (!getDataForPrepare()) {
            message = "适配数据尚未准备";
            logger.error(message);
            return Result.error(message);
        }
        List<Patient> patientList = dispatch.getPatientList(condition, adapterDataSetMap);
        if (!CollectionUtil.isEmpty(patientList)) {
            totalCount = patientList.size();
            for (Patient patient : patientList) {
                boolean result = collectProcess(patient);
                if (result) {
                    count++;
                }
            }
        }
        message = "本次采集病人共" + totalCount + "条,成功采集信息" + count + "条";
        return Result.success(message);
    }

    public boolean collectProcess(Patient patient) {
        if (!getDataForPrepare()) {
            logger.error("适配数据尚未准备完毕");
            return false;
        }
        patient.setReUploadFlg(StringUtil.toString(false));
        logger.trace("采集->注册->打包上传,任务ID：,patient_id:" + patient.getPatientId() + ", event_no:" + patient.getEventNo());
        try {
            /**
             * 获取token
             */
            if (!dispatch.getToken()) {
                logger.error("token获取失败");
                return false;
            }

            /**
             * 获取远程版本
             */
//            if (!dispatch.getRemoteVersion(patient.getOrgCode())) {
//                logger.error("远程版本获取失败");
//                return false;
//            }
            /**
             * 获取版本
             */
            if (StringUtil.isEmpty(sysConfig.getVersionMap().get(patient.getOrgCode()))) {
                logger.error("版本获取失败");
                return false;
            }
            Map<String, JsonNode> dataMap = new HashMap<>();
            for (CrawlerFlowHeadModel crawlerFlowHeadModel : crawlerFlowHeadModelList) {
                /**
                 * 采集信息
                 */
                String datasetCode = crawlerFlowHeadModel.getDatasetCode();
                AdapterDataSet adapterDataSet = adapterDataSetMap.get(datasetCode);
                JsonNode data = dispatch.fecthData(patient, adapterDataSet);
                if (StringUtil.isEmpty(data)) {
                    continue;
                }
                dataMap.put(datasetCode, data);
                /**
                 * 根据采集流程递归查询
                 */
                getDataByCrawlerFlow(datasetCode, patient, dataMap);

                if (sysConfig.getRegisterDataSet().equals(adapterDataSet.getAdapterDataSetT().getStdDatasetCode())) {
                    if (!StringUtil.isEmpty(data.get("data")) && !StringUtil.isEmpty(data.get("data").get(0))) {
                        if (!StringUtil.isEmpty(data.get("data").get(0).get(SysConfig.getInstance().getRegisterIdCardNo()))) {
                            logger.info("注册病人");
                            dispatch.register(patient, data.toString());
                        }
                    }
                }
            }
            logger.info("采集病人成功,patient_id:" + patient.getPatientId() + ", event_no:" + patient.getEventNo());
            /**
             * 上传档案
             */
            try {
                if (!CollectionUtil.isEmpty(dataMap.keySet())) {
                    if (!dispatch.upload(dataMap, patient, adapterDataSetMap)) {
                        logger.error("上传档案失败");
                        return false;
                    }
                }
            } catch (Exception e) {
                logger.error("档案上传失败,patient_id:" + patient.getPatientId() + ", event_no:" + patient.getEventNo());
                return false;
            }
        } catch (Exception e) {
            logger.error("采集病人失败,patient_id:" + patient.getPatientId() + ", event_no:" + patient.getEventNo(), e);
            return false;
        }
        return true;
    }

    public Boolean getDataByCrawlerFlow(String preDatasetCode, Patient patient, Map<String, JsonNode> dataMap) {
        try {
            JsonNode preData = dataMap.get(preDatasetCode);
            Map<String, String> relationValueMap = new HashMap<>();
            List<CrawlerFlowModel> crawlerFlowDatasetList = crawlerFlowDatasetMap.get(preDatasetCode);
            for (CrawlerFlowModel crawlerFlowDataset : crawlerFlowDatasetList) {
                List<CrawlerFlowModel> crawlerFlowMetadataList = crawlerFlowMetadataMap.get(crawlerFlowDataset.getDatasetCode());
                for (CrawlerFlowModel crawlerFlowMetadata : crawlerFlowMetadataList) {
                    String metadataCode = crawlerFlowMetadata.getMetadataCode();
                    metadataCode = StringUtil.substring(metadataCode, metadataCode.indexOf("-") + 1, metadataCode.length());
                    String inputMetadataCode = crawlerFlowMetadata.getInputMetadataCode();
                    inputMetadataCode = StringUtil.substring(inputMetadataCode, inputMetadataCode.indexOf("-") + 1, inputMetadataCode.length());
                    Iterator<JsonNode> array = preData.get("data").iterator();
                    while (array.hasNext()) {
                        JsonNode dataNode = array.next();
                        relationValueMap.put(metadataCode, dataNode.get(inputMetadataCode).asText());
                    }
                }
                String datasetCode = crawlerFlowDataset.getDatasetCode();
                AdapterDataSet adapterDataSet = adapterDataSetMap.get(datasetCode);
                String data = dispatch.fecthData(patient, adapterDataSet, relationValueMap);
                if (StringUtil.isEmpty(data)) {
                    continue;
                } else {
                    ObjectMapper objectMapper = new ObjectMapper();
                    JsonNode jsonObject = objectMapper.readTree(data);
                    dataMap.put(datasetCode, jsonObject);
                }
                getDataByCrawlerFlow(datasetCode, patient, dataMap);
            }
            return true;
        } catch (Exception e) {
            return false;
        }
    }

    public Boolean getDataForPrepare() {
        if (adapterFlg) {
            return true;
        }
        AdapterBase.setAdapterMetadataService(adapterMetadataService);
        AdapterBase.setAdapterDictService(adapterDictService);
        AdapterBase.setAdapterSchemeVersionService(adapterSchemeVersionService);
        logger.info("适配基本相关数据准备");
        try {
            adapterDataSetMap = new HashMap<>();
            AdapterVersion adapterVersion;
            List<Integer> datasetIdList = new ArrayList<>();
            /**
             * 推模式接口调用，默认只使用最新版本的适配
             */
            AdapterSchemeVersionModel adapterSchemeVersionModel;
            if (datasetList.isEmpty()) {
                adapterSchemeVersionModel = adapterSchemeVersionService.getEhrAdapterVersionLasted();
                if (adapterSchemeVersionModel == null) {
                    logger.error("获取最新ehr适配版本错误");
                    return false;
                } else {
                    this.schemeVersion = adapterSchemeVersionModel.getVersion();
                    adapterVersion = new AdapterVersion(schemeVersion);
                }
                /**
                 * 获取该版本下数据集
                 */
                List<CrawlerDataSetModel> crawlerDataSetModelList = crawlerDatasetDao.getCrawlerDatasetList(adapterSchemeVersionModel.getId());
                if (CollectionUtil.isEmpty(crawlerDataSetModelList)) {
                    return false;
                }
                for (CrawlerDataSetModel crawlerDataSetModel : crawlerDataSetModelList) {
                    datasetIdList.add(crawlerDataSetModel.getDatasetId());
                }
            } else {
                /**
                 * 拉模式接口调用，由任务配置决定适配版本
                 */
                adapterSchemeVersionModel = adapterSchemeVersionService.getByVersion(schemeVersion);
                adapterVersion = new AdapterVersion(schemeVersion);
                for (DictItem dictItem : datasetList) {
                    datasetIdList.add(Integer.valueOf(dictItem.getCode()));
                }
            }
            /**
             * 字典项初始化
             */
            List<AdapterDictEntryModel> adapterDictEntryModelList = adapterDatasetService.getList(AdapterDictEntryModel.class, adapterVersion.getDictEntryTableName(), null, null, null, null);
            Map<Integer, List<AdapterDictEntryModel>> adapterDictEntryModelMap = new HashMap<>();
            for (AdapterDictEntryModel adapterDictEntryModel : adapterDictEntryModelList) {
                List<AdapterDictEntryModel> entryModelList = adapterDictEntryModelMap.get(adapterDictEntryModel.getStdDictId());
                if (CollectionUtil.isEmpty(entryModelList)) {
                    entryModelList = new ArrayList<>();
                }
                entryModelList.add(adapterDictEntryModel);
                adapterDictEntryModelMap.put(adapterDictEntryModel.getStdDictId(), entryModelList);
            }
            /**
             * 数据集初始化
             */

            List<AdapterDatasetModel> adapterDataSetModelList = adapterDatasetService.getListByAdapterDatasetIdList(adapterVersion, datasetIdList);
            for (AdapterDatasetModel adapterDatasetModel : adapterDataSetModelList) {
                adapterDataSetMap.put(adapterDatasetModel.getStdDatasetCode(), new AdapterDataSet(adapterDatasetModel, adapterVersion, adapterDictEntryModelMap));
            }

            /**
             * 获取采集流程表头
             */
            crawlerFlowHeadModelList = crawlerFlowHeadDao.getCrawlerFlowHeadList(adapterSchemeVersionModel.getId());
            List<CrawlerFlowModel> crawlerFlowModelList = crawlerFlowDao.getCrawlerFlowList(adapterSchemeVersionModel.getId());
            crawlerFlowDatasetMap = new HashMap<>();
            crawlerFlowMetadataMap = new HashMap<>();
            /**
             * 获取关联表
             */
            for (CrawlerFlowModel crawlerFlowModel : crawlerFlowModelList) {
                List<CrawlerFlowModel> datasetList = new ArrayList<>();
                List<CrawlerFlowModel> metadataList = new ArrayList<>();
                String inputDatasetCode = crawlerFlowModel.getInputDatasetCode();
                String datasetCode = crawlerFlowModel.getDatasetCode();
                if (StringUtil.isEmpty(inputDatasetCode)) {
                    continue;
                }
                if (crawlerFlowDatasetMap.containsKey(inputDatasetCode)) {
                    datasetList = crawlerFlowDatasetMap.get(inputDatasetCode);
                }
                datasetList.add(crawlerFlowModel);
                crawlerFlowDatasetMap.put(inputDatasetCode, datasetList);

                if (crawlerFlowMetadataMap.containsKey(datasetCode)) {
                    metadataList = crawlerFlowMetadataMap.get(datasetCode);
                }
                metadataList.add(crawlerFlowModel);
                crawlerFlowMetadataMap.put(datasetCode, metadataList);
            }
//            SysConfig.getInstance().setVersionMap(new HashMap<>());
            adapterFlg = true;
            return true;
        } catch (Exception e) {
            adapterFlg = false;
            return false;
        }
    }

    /**
     * 解析病人索引信息
     *
     * @param patientInfo 病人索引信息
     * @return
     */
    public Patient parsePatient(String patientInfo) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            Patient patient = mapper.readValue(patientInfo, Patient.class);
            return patient;
        } catch (Exception e) {
            logger.error("patient参数错误：" + patientInfo, e);
            return null;
        }
    }

    public void setAdapterFlg(Boolean adapterFlg) {
        this.adapterFlg = adapterFlg;
    }
}
