package com.yihu.hos.standard.service.standard;

import com.fasterxml.jackson.databind.JsonNode;
import com.yihu.hos.web.framework.dao.SQLGeneralDAO;
import com.yihu.hos.web.framework.constant.ErrorCode;
import com.yihu.hos.web.framework.constant.SqlConstants;
import com.yihu.hos.web.framework.exception.ApiException;
import com.yihu.hos.web.framework.model.DetailModelResult;
import com.yihu.hos.web.framework.model.DictItem;
import com.yihu.hos.web.framework.model.DictionaryResult;
import com.yihu.hos.web.framework.model.Result;
import com.yihu.hos.core.datatype.CollectionUtil;
import com.yihu.hos.core.datatype.StringUtil;
import com.yihu.hos.web.framework.util.sql.RequestParamTransformer;
import com.yihu.hos.standard.model.standard.StandardModel;
import com.yihu.hos.standard.model.standard.StandardVersionModel;
import com.yihu.hos.standard.model.standard.resultModel.StandardParamResultModel;
import com.yihu.hos.standard.model.standard.resultModel.StandardResultDetailModel;
import com.yihu.hos.system.model.SystemOrganization;
import com.yihu.hos.system.model.SystemParam;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * @created Airhead 2015/12/23.
 */
@Transactional
@Service("StandardService")
public class StandardService extends SQLGeneralDAO {

    public static final String BEAN_ID = "StandardService";

    public DictionaryResult getDictionaryResult(String condition,String order, Integer limit, Integer offset) {
        try {
            DictionaryResult dictionaryResult = DictionaryResult.success("获取标准列表成功");
            List<DictItem> detailModelList = new ArrayList<DictItem>();
            List<StandardModel> standardModelList = getList(condition, order, limit, offset);
            for (StandardModel standardModel : standardModelList) {
                DictItem items = new DictItem();
                Integer id = standardModel.getId();
                items.setCode(id.toString());
                items.setValue(standardModel.getName());
                detailModelList.add(items);
            }
            dictionaryResult.setDetailModelList(detailModelList);
            return dictionaryResult;
        } catch (Exception e) {
            return DictionaryResult.error("获取适配列表失败");
        }

    }

    public List<StandardModel> getList(String condition, String order, Integer limit, Integer offset) {
        Map queryMap = RequestParamTransformer.parseJsonToMap(condition);
        Map orderMap = RequestParamTransformer.parseJsonToMap(order);
        return this.getList(queryMap, orderMap, limit, offset);
    }

    public Result add(String standard) {
        Boolean existCodeFlg = false;
        Boolean existNameFlg = false;
        try {
            StandardModel standardModel = objectMapper.readValue(standard, StandardModel.class);
            existCodeFlg = standardCodeValidate(standardModel.getCode());
            existNameFlg = standardNameValidate(standardModel.getName());
            if (!existCodeFlg && !existNameFlg) {
                this.add(standardModel);
                standardModel.setSuccessFlg(true);
                standardModel.setMessage("保存标准成功");
                return standardModel;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (existCodeFlg) {
            return Result.error("已存在标准编码");
        } else if (existNameFlg) {
            return Result.error("已存在标准名称");
        } else {
            return Result.error("保存标准失败");
        }
    }

    public Boolean standardCodeValidate(String code) {
        Map<String, Object> query = new HashMap<>();
        Map<String, String> order = new HashMap<>();
        query.put("code", code);

        List<StandardModel> list = getList(query, order, 1, 0);
        if (!CollectionUtil.isEmpty(list)) {
            return true;
        }
        return false;
    }

    public Boolean standardNameValidate(String name) {
        Map<String, Object> query = new HashMap<>();
        Map<String, String> order = new HashMap<>();
        query.put("name", name);

        List<StandardModel> list = getList(query, order, 1, 0);
        if (!CollectionUtil.isEmpty(list)) {
            return true;
        }
        return false;
    }

    public Result delete(Integer standardId) {
        Boolean publishedFlg = false;
        Boolean existFlg = false;
        try {
            StandardModel standardModel = (StandardModel) get(standardId);
            if (standardModel == null) {
                return Result.error("删除标准失败");
            }
            if (standardModel.getVersionStatus().equals(1)) {
                publishedFlg = true;
            }
            existFlg = existStandardVersionValid(standardModel.getId());
            if (!publishedFlg && !existFlg) {
                deleteEntity(StandardModel.class, standardId);
                return Result.success("删除标准成功");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (publishedFlg) {
            return Result.error("该标准下已有标准版本");
        } else if (existFlg) {
            return Result.error("已存在标准版本");
        } else {
            return Result.error("删除标准失败");
        }
    }

    public Boolean standardNameValidate(Integer standardId, String name) {
        String sql = "FROM StandardModel WHERE name = :name and id != :standardId";
        Query query = getCurrentSession().createQuery(sql);
        query.setParameter("standardId", standardId);
        query.setParameter("name", name);
        List<StandardModel> list = query.list();
        if (!CollectionUtil.isEmpty(list)) {
            return true;
        }
        return false;
    }

    public Boolean standardCodeValidate(Integer standardId, String code) {
        String sql = "FROM StandardModel WHERE code = :code and id != :standardId";
        Query query = getCurrentSession().createQuery(sql);
        query.setParameter("standardId", standardId);
        query.setParameter("code", code);
        List<StandardModel> list = query.list();
        if (!CollectionUtil.isEmpty(list)) {
            return true;
        }
        return false;
    }


    public Result update(String standard) {
        Boolean existCodeFlg = false;
        Boolean existNameFlg = false;
        try {
            StandardModel standardModel = objectMapper.readValue(standard, StandardModel.class);
            existCodeFlg = standardCodeValidate(standardModel.getId(), standardModel.getCode());
            existNameFlg = standardNameValidate(standardModel.getId(), standardModel.getName());
            if (!existCodeFlg && !existNameFlg) {
                this.update(standardModel);
                standardModel.setSuccessFlg(true);
                standardModel.setMessage("修改标准成功");
                return standardModel;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (existCodeFlg) {
            return Result.error("已存在标准编码");
        } else if (existNameFlg) {
            return Result.error("已存在标准名称");
        } else {
            return Result.error("修改标准失败");
        }
    }

    public Result get(Integer standardId) {
        try {
            StandardModel standardModel = getEntity(StandardModel.class, standardId);
            standardModel.setSuccessFlg(true);
            standardModel.setMessage("获取标准成功");
            return standardModel;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return Result.error("获取标准失败");
    }

    public StandardParamResultModel getStandardParam(String paramKey) {
        Criteria criteria = getCurrentSession().createCriteria(SystemParam.class);
        criteria.add(Restrictions.eq("paramKey", paramKey));
        SystemParam systemParam = (SystemParam) criteria.uniqueResult();

        Criteria criteria1 = getCurrentSession().createCriteria(SystemParam.class);
        criteria1.add(Restrictions.eq("paramKey", SqlConstants.STANDARD_ORG));
        SystemParam systemParam1 = (SystemParam) criteria1.uniqueResult();

        if (systemParam != null) {
            StandardParamResultModel standardParamResultModel = new StandardParamResultModel();
            standardParamResultModel.setSuccessFlg(true);
            standardParamResultModel.setMessage("获取参数成功");
            standardParamResultModel.setCode(systemParam.getParamValue());
            standardParamResultModel.setOrgCode(systemParam1.getParamValue());
            return standardParamResultModel;
        } else {
            StandardParamResultModel standardParamResultModel = new StandardParamResultModel();
            standardParamResultModel.setSuccessFlg(false);
            standardParamResultModel.setMessage("获取参数失败");
            return standardParamResultModel;
        }
    }

    public List<StandardResultDetailModel> getStandardListFormat(List<SystemOrganization> publisherModelList,
                                                                 List<StandardModel> standardModelList,
                                                                 List<StandardVersionModel> versionModelList,
                                                                 Map<String, String> codeToIdMap,
                                                                 String name) {
        List<StandardResultDetailModel> resultDetailModelList = new ArrayList<>();
        Map<String, StandardResultDetailModel> resultDetailModelMap = new HashMap<>();
        Map<String, StandardResultDetailModel> resultDetailModelCheckMap = new HashMap<>();
        Map<String, StandardResultDetailModel> resultDetailModelAddMap = new HashMap<>();
        for (SystemOrganization publisherModel : publisherModelList) {
            StandardResultDetailModel resultDetailModel = new StandardResultDetailModel();
            String id = "publisher" + publisherModel.getId();
            resultDetailModel.setId(id);
            resultDetailModel.setName(publisherModel.getFullName());
            resultDetailModel.setType(0);
            resultDetailModel.setCode(publisherModel.getCode());
            codeToIdMap.put(publisherModel.getCode(), id);
            if (StringUtil.isEmpty(name) || publisherModel.getFullName().contains(name)) {
                resultDetailModelCheckMap.put(id, resultDetailModel);
                resultDetailModelAddMap.put(id, resultDetailModel);
                resultDetailModelList.add(resultDetailModel);
            }
            resultDetailModelMap.put(id, resultDetailModel);
        }

        for (StandardModel standardModel : standardModelList) {
            String pid = codeToIdMap.get(standardModel.getPublisherOrgCode());
            if (StringUtil.isEmpty(pid)) {
                continue;
            }
            String id = "standard" + standardModel.getId();
            StandardResultDetailModel resultDetailModel = new StandardResultDetailModel();
            resultDetailModel.setId(id);
            resultDetailModel.setPid(codeToIdMap.get(standardModel.getPublisherOrgCode()));
            resultDetailModel.setType(1);
            resultDetailModel.setName(standardModel.getName());
            resultDetailModel.setCode(standardModel.getCode());
            if (resultDetailModelCheckMap.containsKey(pid)) {
                resultDetailModelCheckMap.put(id, resultDetailModel);
                resultDetailModelList.add(resultDetailModel);
                resultDetailModelAddMap.put(id, resultDetailModel);
            } else if (StringUtil.isEmpty(name) || standardModel.getName().contains(name)) {
                resultDetailModelCheckMap.put(id, resultDetailModel);
                resultDetailModelList.add(resultDetailModel);
                if (!resultDetailModelAddMap.containsKey(pid)) {
                    resultDetailModelAddMap.put(pid, resultDetailModel);
                    resultDetailModelList.add(resultDetailModelMap.get(pid));
                }
            }
            resultDetailModelMap.put(id, resultDetailModel);
        }

        for (StandardVersionModel versionModel : versionModelList) {
            String pid = "standard" + versionModel.getStandardId();
            String id = "version" + versionModel.getId();
            StandardResultDetailModel resultDetailModel = new StandardResultDetailModel();
            resultDetailModel.setId(id);
            resultDetailModel.setPid(pid);
            resultDetailModel.setPublisher(versionModel.getPublishUser());
            resultDetailModel.setStatus(versionModel.getPublishStatus());
            resultDetailModel.setName(versionModel.getName());
            resultDetailModel.setCode(versionModel.getVersion());
            resultDetailModel.setDate(StringUtil.toString(versionModel.getPublishTime()));
            resultDetailModel.setType(2);
            if (resultDetailModelCheckMap.containsKey(pid)) {
                resultDetailModelList.add(resultDetailModel);
            } else if (StringUtil.isEmpty(name) || versionModel.getName().contains(name)) {
                resultDetailModelList.add(resultDetailModel);
                if (!resultDetailModelAddMap.containsKey(pid)) {
                    resultDetailModelAddMap.put(resultDetailModel.getPid(), resultDetailModelMap.get(resultDetailModel.getPid()));
                    if (resultDetailModelMap.get(pid) != null && resultDetailModelMap.get(resultDetailModel.getPid()) != null) {
                        resultDetailModelAddMap.put(resultDetailModelMap.get(pid).getPid(), resultDetailModelMap.get(resultDetailModelMap.get(resultDetailModel.getPid()).getPid()));
                        resultDetailModelList.add(resultDetailModelMap.get(resultDetailModel.getPid()));
                        resultDetailModelList.add(resultDetailModelMap.get(resultDetailModelMap.get(resultDetailModel.getPid()).getPid()));
                    }
                }
            }
        }
        return resultDetailModelList;
    }

    public DetailModelResult getDetailModelResult(String condition) {
        try {
            List<StandardResultDetailModel> standardResultDetailModelList = getStandardList(condition);
            DetailModelResult detailModelResult = DetailModelResult.success("获取标准列表成功");
            detailModelResult.setDetailModelList(standardResultDetailModelList);
            return detailModelResult;
        } catch (Exception e) {
            return DetailModelResult.error("获取标准列表失败");
        }
    }

    public List<StandardResultDetailModel> getStandardList(String condition) {
        String name = SqlConstants.EMPTY;
        Integer type = null;
        if (!StringUtil.isEmpty(condition)) {
            try {
                JsonNode jsonNode = objectMapper.readTree(condition);
                if (jsonNode.get("type") != null) {
                    type = jsonNode.get("type").asInt();
                }
                if (jsonNode.get("name") != null) {
                    name = jsonNode.get("name").asText();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        StandardParamResultModel standardParam = getStandardParam(SqlConstants.STANDARD);
        StandardParamResultModel standardParam1 = getStandardParam(SqlConstants.STANDARD_ORG);
        String code = standardParam.getCode();
        String orgCode = standardParam1.getCode();
        List<SystemOrganization> publisherModelList = new ArrayList<>();

        Criteria criteria = getCurrentSession().createCriteria(StandardModel.class);
        if (type == 0) {
            criteria.add(Restrictions.eq("code", code));
            String publisherHql = "FROM SystemOrganization WHERE code =:orgCode";
            Query query = getCurrentSession().createQuery(publisherHql);
            query.setParameter("orgCode", orgCode);
            publisherModelList = query.list();
        } else if (type == 1) {
            criteria.add(Restrictions.ne("code", code));
            String publisherHql = "FROM SystemOrganization";
            Query query = getCurrentSession().createQuery(publisherHql);
            publisherModelList = query.list();
        }

        List<StandardModel> standardModelList = criteria.list();
        Map<String, String> codeToIdMap = new HashMap<>();
        List<Integer> idList = new ArrayList<>();
        for (StandardModel standardModel : standardModelList) {
            idList.add(standardModel.getId());
        }
        List<StandardVersionModel> versionModelList = new ArrayList<>();
        if (!CollectionUtil.isEmpty(idList)) {
            String versionHql = "FROM StandardVersionModel WHERE standardId IN :idList";
            Query query = getCurrentSession().createQuery(versionHql);
            query.setParameterList("idList", idList);
            versionModelList = query.list();
        }

        List<StandardResultDetailModel> resultDetailModelList = getStandardListFormat(publisherModelList,
                standardModelList,
                versionModelList,
                codeToIdMap,
                name);
        return resultDetailModelList;
    }

    //TODO:TEST
    public StandardModel fork(Integer standardId) {
        try {
            StandardModel baseStandard = (StandardModel) get(standardId);

            StandardModel newStandard = new StandardModel(baseStandard);
            newStandard.setId(null);
            newStandard.setName(baseStandard.getName() + "-副本");
            newStandard.setCode(baseStandard.getCode() + "-副本");
            newStandard.setVersionStatus(0);

            saveEntity(newStandard);

            return newStandard;
        } catch (Exception e) {
            e.printStackTrace();
        }

        throw new ApiException(ErrorCode.StandardForkFailed);
    }

    public boolean existStandardVersionValid(Integer standardId) {
        String hql = "FROM StandardVersionModel WHERE standardId = :standardId";
        Query query = getCurrentSession().createQuery(hql);
        query.setParameter("standardId", standardId);
        List<StandardVersionModel> standardModelList = query.list();
        if (!CollectionUtil.isEmpty(standardModelList)) {
            return true;
        }
        return false;
    }

    private void update(StandardModel standardModel) throws Exception {
        updateEntity(standardModel);
    }

    private void add(StandardModel standardModel) throws Exception {
        saveEntity(standardModel);
    }

    private List<StandardModel> getList(Map<String, Object> query, Map<String, String> order, Integer limit, Integer offset) {

        Session session = getCurrentSession();
        Criteria criteria = session.createCriteria(StandardModel.class);
        if (query!=null) {
            for (String key : query.keySet()) {
                if (key.equals("type")) {
                    Integer type = (Integer) query.get(key);
                    String code = getStandardParam(SqlConstants.STANDARD).getCode();
                    if (type == 0) {
                        criteria.add(Restrictions.eq("code", code));
                    } else if (type == 1) {
                        criteria.add(Restrictions.ne("code", code));
                    }
                } else {
                    criteria.add(Restrictions.eq(key, query.get(key)));
                }
            }
        }
        if (limit != null) {
            criteria.setMaxResults(limit);
            if (offset != null) {
                criteria.setFirstResult((offset - 1) * limit);
            }
        }
        if (order != null) {
            for (String key : order.keySet()) {
                if (order.get(key).equals(SqlConstants.ASC)) {
                    criteria.addOrder(Order.asc(key));
                } else if (order.get(key).equals(SqlConstants.DESC)) {
                    criteria.addOrder(Order.desc(key));
                }
            }
        }
        return (List<StandardModel>) criteria.list();
    }
}
