package com.sagacloud.endpoints;


import com.sagacloud.dict.EqStaticInfo;
import com.sagacloud.dict.TypeToInfosMap;
import com.sagacloud.search.AllObjs;
import com.sagacloud.search.objs.SVEqObj;
import com.sagacloud.search.objs.SVSyObj;
import com.sagacloud.search.objs.SearchViewBaseObj;
import com.sagacloud.utils.CommonUtil;
import com.sagacloud.utils.Const;
import com.sagacloud.utils.DpUtils;
import com.sagacloud.utils.jsonHelper.infoPoint.InfoPoint;
import com.sagacloud.utils.jsonHelper.search.inforPointSearchResult.SearchResultObj;
import com.sagacloud.utils.jsonHelper.search.inforPointSearchResult.SearchResultType;
import com.sagacloud.utils.jsonHelper.search.searchInput.SearchInput;
import org.apache.htrace.fasterxml.jackson.databind.ObjectMapper;
import org.apache.htrace.fasterxml.jackson.databind.ObjectWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by wo on 8/22/17.
 */
@Path("")
public class InfoPointSearch {
    private static final Logger log = LoggerFactory.getLogger(InfoPointSearch.class);

    private AllObjs allObjs;

    @Path("info_point/search")
    @POST
    @Produces(MediaType.APPLICATION_JSON)
    public String search(@QueryParam(Const.PROJECT_ID) String projectId, String jsonStr){
        ObjectMapper mapper = new ObjectMapper();
        projectId = projectId.substring(2, projectId.length());
        SearchInput searchInput = null;
        try {
            searchInput = mapper.readValue(jsonStr, SearchInput.class);
            allObjs  = AllObjs.get(projectId);
            List resultList = new ArrayList();
            if(searchInput.getCategory().contains("Eq")){
                resultList.addAll(searchEqOrSyInfos(projectId, searchInput.getLimit(), true, searchInput.getKeywords()));
            }
            if(searchInput.getCategory().contains("Sy")){
                resultList.addAll(searchEqOrSyInfos(projectId, searchInput.getLimit() - resultList.size(), false, searchInput.getKeywords()));
            }
            if(searchInput.getCategory().contains("Eq")){
                resultList.addAll(searchEqOrSyClassName(projectId, searchInput.getLimit() - resultList.size(), true, searchInput.getKeywords()));
            }
            if(searchInput.getCategory().contains("Sy")){
                resultList.addAll(searchEqOrSyClassName(projectId, searchInput.getLimit() - resultList.size(), false, searchInput.getKeywords()));
            }
            if(searchInput.getCategory().contains("EqObj")){
                resultList.addAll(searchEqObjName(projectId, searchInput.getLimit() - resultList.size(), searchInput.getKeywords()));
            }
            if(searchInput.getCategory().contains("SyObj")){
                resultList.addAll(searchSyObjName(projectId, searchInput.getLimit() - resultList.size(), searchInput.getKeywords()));
            }
            Map map = new HashMap();
            map.put("Result","success");
            map.put("Count", resultList.size());
            map.put("Content", resultList);
            map.put("ResultMsg", "");

            ObjectWriter ow = new ObjectMapper().writer();
            String json = ow.writeValueAsString(map);
            return json;
        } catch (IOException e) {
            return DpUtils.errorJsonMsg(e.getMessage());
        }
    }

    private List searchEqObjName(String projectId, int limit, List<String> keyWords){
        String resultType = "EqObj";
        List subResultLst = new ArrayList();
        if(limit <= 0){
            return  subResultLst;
        }
        for(String key : allObjs.getIdToObjMap().keySet()){
            if(!key.startsWith("Eq")){
                continue;
            }
            SVEqObj svEqObj = (SVEqObj)allObjs.getIdToObjMap().get(key);
            if(CommonUtil.isSearchHit(svEqObj.getLocalName() == null? svEqObj.getSysName().getValue() : svEqObj.getLocalName().getValue(), keyWords)){
                String category = allObjs.getIdToSubtype().get(svEqObj.getId());
                List<InfoPoint> infoPointLst = TypeToInfosMap.get(projectId, category);
                if(infoPointLst == null){
                    continue;
                }
                infoPointLst.forEach(infoPoint -> {
                    SearchResultObj searchResultObj = new SearchResultObj();
                    searchResultObj.setType(resultType );
                    searchResultObj.setInfo(infoPoint.getInfoPointCode());
                    searchResultObj.setInfoName(infoPoint.getInfoPointName());
                    searchResultObj.setEqObj(svEqObj.getId());
                    searchResultObj.setEqObjName(svEqObj.getLocalName() == null? svEqObj.getSysName().getValue() : svEqObj.getLocalName().getValue());
                    searchResultObj.setEqObjLocalId(svEqObj.getLocalId().getValue());
                    searchResultObj.setInputMode(infoPoint.getInputMode());
                    searchResultObj.setDataSource(infoPoint.getDataSource());
                    searchResultObj.setUnit(infoPoint.getUnit());
                    if (svEqObj.getSy() != null) {
                        searchResultObj.setSysObj(svEqObj.getSy().getId());
                        searchResultObj.setSysObjName(svEqObj.getSy().getLocalName() == null ? svEqObj.getSy().getSysName().getValue() : svEqObj.getSy().getLocalName().getValue());
                        searchResultObj.setSysObjLocalId(svEqObj.getSy().getLocalId().getValue());
                        searchResultObj.setMajor(svEqObj.getSy().getMajorId());
                        searchResultObj.setMajorName(svEqObj.getSy().getMajorName());
                    }
                    if(svEqObj.getSp() != null){
                        searchResultObj.setSpObj(svEqObj.getSp().getId());
                        searchResultObj.setSpObjName(svEqObj.getSp().getLocalName()==null? svEqObj.getSp().getSysName().getValue() : svEqObj.getSp().getLocalName().getValue());
                        searchResultObj.setSpObjLocalId(svEqObj.getSp().getLocalId().getValue());
                        if(svEqObj.getSp().getFl() != null){
                            searchResultObj.setFlObj(svEqObj.getSp().getFl().getId());
                            searchResultObj.setFlObjName(svEqObj.getSp().getFl().getLocalName()==null? svEqObj.getSp().getFl().getSysName().getValue() : svEqObj.getSp().getFl().getLocalName().getValue());
                            searchResultObj.setFlObjLocalId(svEqObj.getSp().getFl().getLocalId().getValue());
                        }
                    }
                    if (svEqObj.getBd() != null) {           //数据异常时此处可能会空
                        searchResultObj.setBdObj(svEqObj.getBd().getId());
                        searchResultObj.setBdObjName(svEqObj.getBd().getLocalName() == null ? svEqObj.getBd().getSysName().getValue() : svEqObj.getBd().getLocalName().getValue());
                        searchResultObj.setBdObjLocalId(svEqObj.getBd().getLocalId().getValue());
                    }
                    subResultLst.add(searchResultObj);
                });
            }
            if(subResultLst.size() >= limit){
                subResultLst.subList(limit, subResultLst.size()).clear();
                return subResultLst;
            }
        }
        return subResultLst;
    }

    private List searchSyObjName(String projectId, int limit, List<String> keyWords){
        String resultType = "SyObj";
        List subResultLst = new ArrayList();
        if(limit <= 0){
            return  subResultLst;
        }
        for(String key : allObjs.getIdToObjMap().keySet()){
            if(!key.startsWith("Sy")){
                continue;
            }
            SVSyObj svSyObj = (SVSyObj)allObjs.getIdToObjMap().get(key);
            if(CommonUtil.isSearchHit(svSyObj.getLocalName() == null? svSyObj.getSysName().getValue() : svSyObj.getLocalName().getValue(), keyWords)){
                String category = allObjs.getIdToSubtype().get(svSyObj.getId());
                List<InfoPoint> infoPointLst = TypeToInfosMap.get(projectId, category);
                if(infoPointLst == null){
                    continue;
                }
                infoPointLst.forEach(infoPoint -> {
                    SearchResultObj searchResultObj = new SearchResultObj();
                    searchResultObj.setType(resultType );
                    searchResultObj.setInfo(infoPoint.getInfoPointCode());
                    searchResultObj.setInfoName(infoPoint.getInfoPointName());

                    searchResultObj.setSysObj(svSyObj.getId());
                    searchResultObj.setSysObjName(svSyObj.getLocalName() == null ? svSyObj.getSysName().getValue() : svSyObj.getLocalName().getValue());
                    searchResultObj.setSysObjLocalId(svSyObj.getLocalId().getValue());
                    searchResultObj.setMajor(svSyObj.getMajorId());
                    searchResultObj.setMajorName(svSyObj.getMajorName());
                    searchResultObj.setInputMode(infoPoint.getInputMode());

                    if(svSyObj.getSp() != null){
                        searchResultObj.setSpObj(svSyObj.getSp().getId());
                        searchResultObj.setSpObjName(svSyObj.getSp().getLocalName()==null? svSyObj.getSp().getSysName().getValue() : svSyObj.getSp().getLocalName().getValue());
                        searchResultObj.setSpObjLocalId(svSyObj.getSp().getLocalId().getValue());
                        if(svSyObj.getSp().getFl() != null){
                            searchResultObj.setFlObj(svSyObj.getSp().getFl().getId());
                            searchResultObj.setFlObjName(svSyObj.getSp().getFl().getLocalName()==null? svSyObj.getSp().getFl().getSysName().getValue() : svSyObj.getSp().getFl().getLocalName().getValue());
                            searchResultObj.setFlObjLocalId(svSyObj.getSp().getFl().getLocalId().getValue());
                        }
                    }
                    if (svSyObj.getBd() != null) {           //数据异常时此处可能会空
                        searchResultObj.setBdObj(svSyObj.getBd().getId());
                        searchResultObj.setBdObjName(svSyObj.getBd().getLocalName() == null ? svSyObj.getBd().getSysName().getValue() : svSyObj.getBd().getLocalName().getValue());
                        searchResultObj.setBdObjLocalId(svSyObj.getBd().getLocalId().getValue());
                    }
                    subResultLst.add(searchResultObj);
                });
            }
            if(subResultLst.size() >= limit){
                subResultLst.subList(limit, subResultLst.size()).clear();
                return subResultLst;
            }
        }
        return subResultLst;
    }

    private List searchEqOrSyClassName(String pjId, int limit, boolean searchEq, List<String> keyWords){
        EqStaticInfo eqStaticInfo = new EqStaticInfo(pjId);
        List resultLst = new ArrayList();
        if(limit <= 0){
            return  resultLst;
        }
        int keyLenth = 2;
        String resultType = "Sy";
        if(searchEq){
            keyLenth = 4;
            resultType = "Eq";
        }
        for(String key : eqStaticInfo.getCateToNameMap().keySet()){
            if(key.length() != keyLenth){
                continue;
            }
            if(CommonUtil.isSearchHit(eqStaticInfo.getCateToNameMap().get(key), keyWords)){
                List<InfoPoint> infoPointLst = TypeToInfosMap.get(pjId, key);
                if(infoPointLst == null){
                    continue;
                }
                for(InfoPoint infoPoint : infoPointLst){

                    if(keyLenth == 2){
                        resultLst.addAll(buildSyResults(pjId, resultType, key, infoPoint, false, eqStaticInfo));
                    }else {
                        resultLst.addAll(buildEqResults(pjId, resultType, key, infoPoint, false, eqStaticInfo));
                    }

                    if(resultLst.size() >= limit){
                        resultLst.subList(limit, resultLst.size()).clear();
                        return resultLst;
                    }
                }
            }
        }
        return resultLst;
    }

    private  List searchEqOrSyInfos(String pjId, int limit, boolean searchEq, List<String> keyWords){
        List resultLst = new ArrayList();
        if(limit <= 0){
            return  resultLst;
        }
        int keyLenth = 2;
        String resultType = "Sy";
        if(searchEq){
            keyLenth = 4;
            resultType = "Eq";
        }
        EqStaticInfo eqStaticInfo = new EqStaticInfo(pjId);
        for(String key : eqStaticInfo.getCateToMajorMap().keySet()){
           if(key.length() != keyLenth){
               continue;
           }
           List<InfoPoint> infoPointLst = TypeToInfosMap.get(pjId, key);
           if(infoPointLst == null){
               continue;
           }
           for(InfoPoint infoPoint : infoPointLst){
               if(CommonUtil.isSearchHit(infoPoint.getInfoPointName(),keyWords)){
                   if(keyLenth == 2){
                       resultLst.addAll(buildSyResults(pjId, resultType, key, infoPoint, true, eqStaticInfo));
                   }else {
                       resultLst.addAll(buildEqResults(pjId, resultType, key, infoPoint, true, eqStaticInfo));
                   }
               }
               if(resultLst.size() >= limit){
                   resultLst.subList(limit, resultLst.size()).clear();
                   return resultLst;
               }
           }
        }
        return resultLst;
    }

    private List buildEqResults(String pjId, String resultType, String key, InfoPoint infoPoint, boolean needObj, EqStaticInfo eqStaticInfo){
        List subResultLst = new ArrayList();
        SearchResultType searchResultType = new SearchResultType();
        searchResultType.setType(resultType);
        searchResultType.setEq(key);
        searchResultType.setEqName(eqStaticInfo.getCateToNameMap().get(key));
        searchResultType.setInfo(infoPoint.getInfoPointCode());
        searchResultType.setInfoName(infoPoint.getInfoPointName());
        searchResultType.setSys(key.substring(0,2));
        searchResultType.setSysName(eqStaticInfo.getCateToNameMap().get(key.substring(0,2)));
        searchResultType.setMajor(eqStaticInfo.getCateToMajorMap().get(key));
        searchResultType.setMajorName(eqStaticInfo.getMajorCodeToNameMap().get(searchResultType.getMajor()));
        searchResultType.setInputMode(infoPoint.getInputMode());
        searchResultType.setDataSource(infoPoint.getDataSource());
        searchResultType.setUnit(infoPoint.getUnit());
        subResultLst.add(searchResultType);
        if(!needObj){
            return subResultLst;
        }

        List<SearchViewBaseObj> searchViewEqs = allObjs.getCateToObjs().get(key);
        if(searchViewEqs == null){
            return subResultLst;
        }
        searchViewEqs.forEach(searchViewBaseObj -> {
            SVEqObj svEqObj = (SVEqObj)searchViewBaseObj;
            SearchResultObj searchResultObj = new SearchResultObj();
            searchResultObj.setType(resultType + "Obj");
            searchResultObj.setInfo(infoPoint.getInfoPointCode());
            searchResultObj.setInfoName(infoPoint.getInfoPointName());
            searchResultObj.setEqObj(svEqObj.getId());
            searchResultObj.setEqObjName(svEqObj.getLocalName() == null? svEqObj.getSysName().getValue() : svEqObj.getLocalName().getValue());
            searchResultObj.setEqObjLocalId(svEqObj.getLocalId().getValue());
            searchResultObj.setInputMode(infoPoint.getInputMode());
            searchResultType.setDataSource(infoPoint.getDataSource());
            searchResultType.setUnit(infoPoint.getUnit());
            if (svEqObj.getSy() != null) {
                searchResultObj.setSysObj(svEqObj.getSy().getId());
                searchResultObj.setSysObjName(svEqObj.getSy().getLocalName() == null ? svEqObj.getSy().getSysName().getValue() : svEqObj.getSy().getLocalName().getValue());
                searchResultObj.setSysObjLocalId(svEqObj.getSy().getLocalId().getValue());
                searchResultObj.setMajor(svEqObj.getSy().getMajorId());
                searchResultObj.setMajorName(svEqObj.getSy().getMajorName());
            }
            if(svEqObj.getSp() != null){
                searchResultObj.setSpObj(svEqObj.getSp().getId());
                searchResultObj.setSpObjName(svEqObj.getSp().getLocalName()==null? svEqObj.getSp().getSysName().getValue() : svEqObj.getSp().getLocalName().getValue());
                searchResultObj.setSpObjLocalId(svEqObj.getSp().getLocalId().getValue());
                if(svEqObj.getSp().getFl() != null){
                    searchResultObj.setFlObj(svEqObj.getSp().getFl().getId());
                    searchResultObj.setFlObjName(svEqObj.getSp().getFl().getLocalName()==null? svEqObj.getSp().getFl().getSysName().getValue() : svEqObj.getSp().getFl().getLocalName().getValue());
                    searchResultObj.setFlObjLocalId(svEqObj.getSp().getFl().getLocalId().getValue());
                }
            }
            if (svEqObj.getBd() != null) {           //数据异常时此处可能会空
                searchResultObj.setBdObj(svEqObj.getBd().getId());
                searchResultObj.setBdObjName(svEqObj.getBd().getLocalName() == null ? svEqObj.getBd().getSysName().getValue() : svEqObj.getBd().getLocalName().getValue());
                searchResultObj.setBdObjLocalId(svEqObj.getBd().getLocalId().getValue());
            }
            subResultLst.add(searchResultObj);
        });
        return  subResultLst;
    }

    private List buildSyResults(String pjId, String resultType, String key, InfoPoint infoPoint, boolean needObj, EqStaticInfo eqStaticInfo){
        List subResultLst = new ArrayList();
        SearchResultType searchResultType = new SearchResultType();
        searchResultType.setType(resultType);
        searchResultType.setInfo(infoPoint.getInfoPointCode());
        searchResultType.setInfoName(infoPoint.getInfoPointName());
        searchResultType.setSys(key);
        searchResultType.setSysName(eqStaticInfo.getCateToNameMap().get(key));
        searchResultType.setMajor(eqStaticInfo.getCateToMajorMap().get(key));
        searchResultType.setMajorName(eqStaticInfo.getMajorCodeToNameMap().get(searchResultType.getMajor()));
        searchResultType.setInputMode(infoPoint.getInputMode());
        searchResultType.setDataSource(infoPoint.getDataSource());
        searchResultType.setUnit(infoPoint.getUnit());
        subResultLst.add(searchResultType);
        if(!needObj){
            return subResultLst;
        }

        List<SearchViewBaseObj> searchViewEqs = allObjs.getCateToObjs().get(key);
        if(searchViewEqs == null){
            return subResultLst;
        }
        searchViewEqs.forEach(searchViewBaseObj -> {
            SVSyObj svSyObj = (SVSyObj)searchViewBaseObj;
            SearchResultObj searchResultObj = new SearchResultObj();
            searchResultObj.setType(resultType + "Obj");
            searchResultObj.setInfo(infoPoint.getInfoPointCode());
            searchResultObj.setInfoName(infoPoint.getInfoPointName());

            searchResultObj.setSysObj(svSyObj.getId());
            searchResultObj.setSysObjName(svSyObj.getLocalName() == null ? svSyObj.getSysName().getValue() : svSyObj.getLocalName().getValue());
            searchResultObj.setSysObjLocalId(svSyObj.getLocalId().getValue());
            searchResultObj.setMajor(svSyObj.getMajorId());
            searchResultObj.setMajorName(svSyObj.getMajorName());
            searchResultObj.setInputMode(infoPoint.getInputMode());
            searchResultType.setDataSource(infoPoint.getDataSource());
            searchResultType.setUnit(infoPoint.getUnit());

            if(svSyObj.getSp() != null){
                searchResultObj.setSpObj(svSyObj.getSp().getId());
                searchResultObj.setSpObjName(svSyObj.getSp().getLocalName()==null? svSyObj.getSp().getSysName().getValue() : svSyObj.getSp().getLocalName().getValue());
                searchResultObj.setSpObjLocalId(svSyObj.getSp().getLocalId().getValue());
                if(svSyObj.getSp().getFl() != null){
                    searchResultObj.setFlObj(svSyObj.getSp().getFl().getId());
                    searchResultObj.setFlObjName(svSyObj.getSp().getFl().getLocalName()==null? svSyObj.getSp().getFl().getSysName().getValue() : svSyObj.getSp().getFl().getLocalName().getValue());
                    searchResultObj.setFlObjLocalId(svSyObj.getSp().getFl().getLocalId().getValue());
                }
            }
            if (svSyObj.getBd() != null) {           //数据异常时此处可能会空
                searchResultObj.setBdObj(svSyObj.getBd().getId());
                searchResultObj.setBdObjName(svSyObj.getBd().getLocalName() == null ? svSyObj.getBd().getSysName().getValue() : svSyObj.getBd().getLocalName().getValue());
                searchResultObj.setBdObjLocalId(svSyObj.getBd().getLocalId().getValue());
            }
            subResultLst.add(searchResultObj);
        });
        return  subResultLst;
    }


}
