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

import com.fasterxml.jackson.databind.ObjectMapper;
import com.yihu.hos.standard.model.standard.*;
import com.yihu.hos.standard.util.ExcelUtilBigData;
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.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.adapter.AdapterSchemeModel;
import com.yihu.hos.standard.service.bo.StandardVersion;
import org.hibernate.Criteria;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.*;

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

    public static final String BEAN_ID = "StandardVersionService";
    @Autowired
    private ObjectMapper objectMapper;

    @Autowired
    private StdDatasetService stdDatasetService;

    @Autowired
    private StdMetadataService stdMetadataService;

    @Autowired
    private StdDictService stdDictService;

    @Autowired
    private StdDictEntryService stdDictEntryService;

    public DictionaryResult getDictionaryResult(Integer standardId, String condition, String order, Integer rows, Integer page) {
        try {
            DictionaryResult dictionaryResult = DictionaryResult.success("获取标准版本成功");
            List<DictItem> detailModelList = new ArrayList<>();
            List<StandardVersionModel> standardVersionModelList = getVersionList(standardId, condition, order, rows, page);

            for(StandardVersionModel standardVersionModel : standardVersionModelList){
                DictItem items = new DictItem();
                String id = standardVersionModel.getVersion();
                String name = standardVersionModel.getName();
                items.setCode(id.toString());
                items.setValue(name);
                detailModelList.add(items);
            }
            dictionaryResult.setDetailModelList(detailModelList);
            return dictionaryResult;
        } catch (Exception e) {
            return DictionaryResult.error("获取标准版本失败");
        }
    }

    public DictionaryResult getDetailResultModelList(Integer standardId, String condition, String order, Integer rows, Integer page) {
        try {
            List<StandardVersionModel> standardVersionModelList = getVersionList(standardId, condition, order, rows, page);
            DictionaryResult dictionaryResult = new DictionaryResult();
            List<DictItem> detailModelList = new ArrayList<DictItem>();
            DictItem item = new DictItem();
            item.setCode("");
            item.setValue("-无-");
            detailModelList.add(item);
            for (StandardVersionModel standardVersionModel : standardVersionModelList) {
                DictItem items = new DictItem();
                String  id = standardVersionModel.getVersion();
                String name = standardVersionModel.getName();
                items.setCode(id.toString());
                items.setValue(name);
                detailModelList.add(items);
            }
            dictionaryResult.setDetailModelList(detailModelList);
            dictionaryResult.setSuccessFlg(true);
            dictionaryResult.setMessage("获取标准版本列表成功");
            return dictionaryResult;
        } catch (Exception e) {
            return DictionaryResult.error("获取标准版本列表失败");
        }
    }

    public List<StandardVersionModel> getVersionList(Integer standardId, String condition, String order, Integer limit, Integer offset) {
        try {
            Map queryMap = RequestParamTransformer.parseJsonToMap(condition);
            Map orderMap = RequestParamTransformer.parseJsonToMap(order);
            return this.getList(standardId, queryMap, orderMap, limit, offset);
        } catch (Exception e) {
            e.printStackTrace();
        }

        throw new ApiException(ErrorCode.StandardVersionGetListFailed);
    }

    public Result add(String version) throws Exception {
        Boolean existFlg = false;
        try {
            StandardVersionModel versionModel = objectMapper.readValue(version, StandardVersionModel.class);
            existFlg = versionNameValidate(versionModel.getStandardId(), versionModel.getName());
            if (!existFlg) {
                this.add(versionModel);
                versionModel.setSuccessFlg(true);
                versionModel.setMessage("保存标准版本成功");
                return versionModel;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (existFlg) {
            return Result.error("已存在标准版本名称");
        } else {
            return Result.error("保存标准版本失败");
        }
    }

    public Boolean versionNameValidate(Integer standardId, String versionName) {
            Map<String, Object> query = new HashMap<>();
            Map<String, String> order = new HashMap<>();
            query.put("name", versionName);
            List<StandardVersionModel> list = getList(standardId, query, order, 1, 0);
            if (!CollectionUtil.isEmpty(list)) {
                return true;
            }
            return false;
    }

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

    public Result delete(Integer versionId,String version) throws Exception {
        Boolean existFlg = false;
        Boolean useredFlg = false;
        try {
            StandardVersionModel versionModel = (StandardVersionModel) get(versionId);
            if (versionModel.getPublishStatus() == 1) {
                existFlg = true;
            } else {
                String sql = "FROM AdapterSchemeModel WHERE stdVersion = :stdVersion or adapterStdVersion =  :adapterStdVersion";
                Query query = getCurrentSession().createQuery(sql);
                query.setParameter("stdVersion", version);
                query.setParameter("adapterStdVersion", version);
                List<AdapterSchemeModel> list = query.list();
                if (!CollectionUtil.isEmpty(list)) {
                    useredFlg = true;
                }else{
                    this.delete(versionModel);
                    deleteVersionTables(new StandardVersion(versionModel.getVersion()));
                    return Result.success("删除标准版本成功");
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (existFlg) {
            return Result.error("该标准版本已发布");
        } else if(useredFlg){
            return Result.error("该标准版本已被适配使用");
        } else {
            return Result.error("删除标准版本失败");
        }
    }

    public Result update(String version) throws Exception {
        Boolean existFlg = false;
        try {
            StandardVersionModel versionModel = objectMapper.readValue(version, StandardVersionModel.class);
            existFlg = versionNameValidate(versionModel.getStandardId(), versionModel.getId(), versionModel.getName());
            if (!existFlg) {
                this.update(versionModel);
                versionModel.setSuccessFlg(true);
                versionModel.setMessage("修改标准版本成功");
                return versionModel;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        if (existFlg) {
            return Result.error("已存在标准版本名称");
        } else {
            return Result.error("修改标准版本失败");
        }
    }

    public Result get(Integer versionId) {
        try {
            StandardVersionModel versionModel = this.myGet(versionId);
            versionModel.setSuccessFlg(true);
            versionModel.setMessage("获取标准版本信息成功");
            return versionModel;
        } catch (DataAccessException e) {
            return Result.error("获取标准版本信息失败");
        }
    }

    public StandardVersionModel fork(Integer versionId) throws Exception {
        try {
            return this.myFork(versionId);

        } catch (DataAccessException | IOException e) {
            throw new ApiException(ErrorCode.StandardVersionForkFailed);
        }
    }

    public Result publish(Integer versionId, String publisher) throws Exception {
        try {
            StandardVersionModel standardVersionModel = this.myPublish(versionId, publisher);
            standardVersionModel.setSuccessFlg(true);
            standardVersionModel.setMessage("发布标准版本成功");
            return standardVersionModel;
        } catch (DataAccessException e) {
            return Result.error("发布标准版本失败");
        }
    }

    public StandardVersionModel getLastestVersion(Integer standardId) {
        Map<String, Object> query = new HashMap<>();
        Map<String, String> order = new HashMap<>();
        order.put("publisher", SqlConstants.DESC);

        List<StandardVersionModel> list = getList(standardId, query, order, 1, 0);
        if (list != null && list.size() != 0) {
            return list.get(0);
        }

        return null;
    }

    public StandardVersionModel myPublish(Integer versionId, String publisher) throws Exception {
        StandardVersionModel standardVersionModel = myGet(versionId);
        //TODO:generate standard version file;
        String path = "";
        standardVersionModel.setPath(path);
        standardVersionModel.setPublishTime(new Date());
        standardVersionModel.setPublishUser(publisher);
        standardVersionModel.setPublishStatus(1);

        this.update(standardVersionModel);

        return standardVersionModel;
    }

    private StandardVersionModel myFork(Integer versionId) throws Exception {
        StandardVersionModel baseVersionModel = myGet(versionId);
        StandardVersionModel newVersionModel = new StandardVersionModel();
        newVersionModel.setBaseVersion(baseVersionModel.getVersion());
        newVersionModel.setName(baseVersionModel.getName() + " Copy");
        newVersionModel.setPrimaryVersion(baseVersionModel.getPrimaryVersion());
        newVersionModel.setPublishTime(new Date());
        this.add(newVersionModel);

        StandardVersion baseVersion = new StandardVersion(baseVersionModel.getVersion());
        StandardVersion newVersion = new StandardVersion(newVersionModel.getVersion());
        buildVersionTables(baseVersion, newVersion, baseVersionModel.getStandardId());

        return newVersionModel;
    }

    private StandardVersionModel myGet(Integer versionId) {
        try {
            return (StandardVersionModel) getEntity(StandardVersionModel.class, versionId);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private void delete(StandardVersionModel standardVersionModel) throws Exception {
        deleteEntity(standardVersionModel);
    }

    private void update(StandardVersionModel standardVersionModel) throws Exception {
        try {
            updateEntity(standardVersionModel);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void  add(StandardVersionModel standardVersionModel) throws Exception {
        StandardVersion standardVersion = StandardVersion.generateVersion();
        standardVersionModel.setVersion(standardVersion.getVersion());
        standardVersionModel.setPublishTime(null);
        standardVersionModel.setPublishStatus(0);
        saveEntity(standardVersionModel);

        String baseVer = standardVersionModel.getBaseVersion();
        StandardVersion baseVersion = StringUtil.isEmpty(baseVer) ? null : new StandardVersion(baseVer);
        StandardVersion newVersion = new StandardVersion(standardVersionModel.getVersion());
        buildVersionTables(baseVersion, newVersion, standardVersionModel.getStandardId());
    }

    private List<StandardVersionModel> getList(Integer standardId, Map<String, Object> query, Map<String, String> order, Integer limit, Integer offset) {
        Session session = getCurrentSession();
        Criteria criteria = session.createCriteria(StandardVersionModel.class);
        criteria.add(Restrictions.eq("standardId", standardId));
        if (query != null) {
            for (String key : query.keySet()) {
                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<StandardVersionModel>) criteria.list();
    }

    private void deleteVersionTables(StandardVersion version) {
        String[] tables = {version.getDataSetTableName(),
                version.getMetaDataTableName(),
                version.getDictTableName(),
                version.getDictEntryTableName()
                /*version.getCDATableName(),
               /* version.getCDADatasetTableName()*/};
        List<String> deleteSql = new ArrayList<>();
        for (int i = 0; i < tables.length; ++i) {
            String table = tables[i];
            deleteSql.add(SqlConstants.DROP_TABLE + table);
        }
        insertBatch(deleteSql);
    }

    private void buildVersionTables(StandardVersion baseVersion, StandardVersion newVersion, Integer standardId) {

        String[] newTables = {newVersion.getDataSetTableName(),
                newVersion.getMetaDataTableName(),
                newVersion.getDictTableName(),
                newVersion.getDictEntryTableName()
               /* newVersion.getCDATableName(),
                newVersion.getCDADatasetTableName()*/};

        String[] baseTables;
        if (baseVersion == null) {
            String[] templateTables = {StandardVersion.DataSetTable,
                    StandardVersion.MetaDataTable,
                    StandardVersion.DictTable,
                    StandardVersion.DictEntryTable
                   /* StandardVersion.CDADocumentTable,
                    StandardVersion.CDADatasetTable*/};
            baseTables = templateTables;
        } else {
            String[] templateTables = {baseVersion.getDataSetTableName(),
                    baseVersion.getMetaDataTableName(),
                    baseVersion.getDictTableName(),
                    baseVersion.getDictEntryTableName()
                    /*baseVersion.getCDATableName(),
                    baseVersion.getCDADatasetTableName()*/};
            baseTables = templateTables;
        }

        List<String> createSql = new ArrayList<>();
        List<String> insertSql = new ArrayList<>();
        List<String> updateSql = new ArrayList<>();
        for (int i = 0; i < baseTables.length; ++i) {
            String baseTable = baseTables[i];
            String newTable = newTables[i];
            createSql.add(SqlConstants.CREATE_TABLE + newTable + SqlConstants.LIKE + baseTable);
        }

        for (int i = 0; i < baseTables.length; ++i) {
            String baseTable = baseTables[i];
            String newTable = newTables[i];
            insertSql.add(SqlConstants.INSERT_INTO + newTable + SqlConstants.SELECT + SqlConstants.ASTERISK + SqlConstants.FROM + baseTable);
        }

        for (int i = 0; i < baseTables.length; ++i) {
            String newTable = newTables[i];
            updateSql.add(SqlConstants.UPDATE + newTable + SqlConstants.SET + " STD_ID = " + standardId);
        }
        insertBatch(createSql);
        insertBatch(insertSql);
        insertBatch(updateSql);
    }

    @Transactional
    public String saveDatasetExcel(MultipartFile file, String version,Integer standardId) throws Exception {
        List<List<String[]>> list = ExcelUtilBigData.readerExcel(file.getInputStream(), 13, 0);//String[] 存放一行,List<String[]> 代表一个excel表格
        for (int i = 0; i < list.size(); i++) {
            List<String[]> l = list.get(i);
            //遍历sheet
            //新增数据集
            StandardVersion standardVersion = new StandardVersion(version);
            StdDataSetModel stdeDataset = new StdDataSetModel();
            stdeDataset.setName(getNotNull(l.get(0)[1]));
            stdeDataset.setCode(getNotNull(l.get(1)[1]));
            stdeDataset.setSummary(getNotNull(l.get(3)[1]));
            stdeDataset.setLanguage(getNotNull(l.get(4)[1]));
            stdeDataset.setClassModel(getNotNull(l.get(5)[1]));
            stdeDataset.setstandardId(standardId);
            stdeDataset.setCatalog(0);
//            if(org.apache.commons.lang3.StringUtils.isNotBlank(getNotNull(l.get(2)[1]))){
//                stdeDataset.setCatalog(Integer.valueOf(getNotNull(l.get(2)[1])));
//            }
            stdDatasetService.add(standardVersion.getDataSetTableName(), stdeDataset);
            for (int row = 7; row < l.size(); row++) {
                //保存数据元
                StdMetaDataModel stdeMetadata = new StdMetaDataModel();
                stdeMetadata.setDatasetId(stdeDataset.getId());//肯定要设置
                stdeMetadata.setStandardId(standardId);
                stdeMetadata.setDeCode(getNotNull(l.get(row)[1]));
                stdeMetadata.setCode(getNotNull(l.get(row)[2]));
                stdeMetadata.setName(getNotNull(l.get(row)[3]));
                stdeMetadata.setDefinition(getNotNull(l.get(row)[4]));
                stdeMetadata.setType(getNotNull(l.get(row)[5]));
                stdeMetadata.setFormat(getNotNull(l.get(row)[6]));
                String dicId = getNotNull(l.get(row)[7]);
                if(org.apache.commons.lang3.StringUtils.isNotBlank(dicId)){
                    stdeMetadata.setDictId(Integer.valueOf(dicId));
                }
                stdeMetadata.setColumnName(getNotNull(l.get(row)[8]));
                stdeMetadata.setColumnType(getNotNull(l.get(row)[9]));
                stdeMetadata.setColumnLength(getNotNull(l.get(row)[10]));
                String isPrimaryKey = getNotNull(l.get(row)[11]);
                if(org.apache.commons.lang3.StringUtils.isNotBlank(isPrimaryKey)){
                    stdeMetadata.setPrimaryKey(Integer.valueOf(isPrimaryKey));
                }
                String isNullable = getNotNull(l.get(row)[12]);
                if(org.apache.commons.lang3.StringUtils.isNotBlank(isNullable)){
                    stdeMetadata.setNullable(Integer.valueOf(isNullable));
                }
                if(org.apache.commons.lang3.StringUtils.isBlank(stdeMetadata.getCode())){
                    continue;
                }
                stdMetadataService.add(standardVersion, stdeMetadata);
            }
        }
        return version;
    }

    @Transactional
    public String saveDictExcel(MultipartFile file, String version,Integer standardId) throws Exception {

        List<List<String[]>> list = ExcelUtilBigData.readerExcel(file.getInputStream(), 5, 3);
        list.stream().filter(medatas-> getNotNull(medatas.get(0)[1]).contains("ICD-10-CM")).forEach(medata->{
            System.out.println(list.indexOf(medata));
        });
        StandardVersion standardVersion = new StandardVersion(version);
        for (int i = 0; i < list.size(); i++) {
            List<String[]> l = list.get(i);
            //遍历sheet
            StdDictionaryModel stdeDict = new StdDictionaryModel();
            stdeDict.setstandardId(standardId);
            stdeDict.setCode(getNotNull(l.get(0)[1]));
            stdeDict.setName(getNotNull(l.get(1)[1]));
//            stdeDict.setDefine(getNotNull(l.get(2)[1]));
//            stdeDict.setDescription(getNotNull(l.get(3)[1]));
//            String parentId = getNotNull(l.get(4)[1]);
//            if(!StringUtils.isEmpty(parentId)){
//                stdeDict.setParentId(Integer.valueOf(parentId));
//            }
            stdDictService.add(standardVersion,stdeDict);
            for (int row = 0; row < l.size(); row++) {
                if (StringUtils.isEmpty(l.get(row)[4])) {
                    continue;
                }
                StdDictionaryEntryModel stdeDictItem = new StdDictionaryEntryModel();
                stdeDictItem.setstandardId(standardId);
                stdeDictItem.setDictId(stdeDict.getId());
                stdeDictItem.setValue(getNotNull(l.get(row)[4]));
                stdeDictItem.setCode(getNotNull(l.get(row)[3]));
                System.out.println("第"+(i+1)+"个表格;第"+(row+1)+"行数据");
                stdDictEntryService.add(standardVersion,stdeDictItem);
            }
        }
        return version;
    }

    private String getNotNull(Object obj) {
        if (!StringUtils.isEmpty(obj)) {
            return obj.toString().replace("\"", "");
        }
        return "";
    }

    public String isUpdateDatasetAndDict(String version) {
        JSONObject jo=new JSONObject();
        List<StdDataSetModel> stdDataSetModels = stdDatasetService.getList(version, null, null, null, null);
        if(stdDataSetModels!=null&&stdDataSetModels.size()>0){
            jo.put("datasetUpdate","true");
        }else{
            jo.put("datasetUpdate","false");
        }
        List<StdDictionaryModel> stdDictionaryModels = stdDictService.getList(version, null, null, null, null);
        if(stdDictionaryModels!=null&&stdDictionaryModels.size()>0){
            jo.put("dictUpdate","true");
        }else{
            jo.put("dictUpdate","false");
        }
        return jo.toString();
    }

    @Transactional
    public void deleteDataset(String version) throws Exception {
        Session session = getCurrentSession();
        //删除数据集
        String sql1 = "truncate table std_dataset_" + version;
        session.createSQLQuery(sql1).executeUpdate();
        //删除数据元
        String sql = "truncate table std_metadata_" + version;
        session.createSQLQuery(sql).executeUpdate();
    }

    public void deleteDict(String version) {
        Session session = getCurrentSession();
        //删除字典
        String sql1 = "truncate table std_dictionary_" + version;
        session.createSQLQuery(sql1).executeUpdate();
        //删除字典项
        String sql = "truncate table std_dictionary_entry_" + version;
        session.createSQLQuery(sql).executeUpdate();
    }
}

