package com.goer.project.model.modelVersion.service.impl;

import java.io.StringWriter;
import java.util.List;

import com.goer.common.constant.Constants;
import com.goer.common.utils.DateUtils;
import com.goer.common.utils.StringUtils;
import com.goer.project.model.modelEntity.domain.ModelEntity;
import com.goer.project.model.modelEntity.mapper.ModelEntityMapper;
import com.goer.project.model.modelField.domain.ModelField;
import com.goer.project.model.modelProject.domain.ModelProject;
import com.goer.project.model.modelProject.mapper.ModelProjectMapper;
import com.goer.project.model.modelVersion.domain.VersionScript;
import com.goer.project.tool.gen.util.VelocityInitializer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.goer.project.model.modelVersion.mapper.ModelVersionMapper;
import com.goer.project.model.modelVersion.domain.ModelVersion;
import com.goer.project.model.modelVersion.service.IModelVersionService;
import com.goer.common.utils.text.Convert;
import sun.swing.StringUIClientPropertyKey;

/**
 * 模型对象版本号Service业务层处理
 * 
 * @author goer
 * @date 2022-01-17
 */
@Slf4j
@Service
public class ModelVersionServiceImpl implements IModelVersionService 
{
    @Autowired
    private ModelVersionMapper modelVersionMapper;
    @Autowired
    private ModelProjectMapper modelProjectMapper;
    @Autowired
    private ModelEntityMapper modelEntityMapper;
    /**
     * 查询模型对象版本号
     * 
     * @param id 模型对象版本号主键
     * @return 模型对象版本号
     */
    @Override
    public ModelVersion selectModelVersionById(Long id)
    {
        return modelVersionMapper.selectModelVersionById(id);
    }

    /**
     * 查询模型对象版本号列表
     * 
     * @param modelVersion 模型对象版本号
     * @return 模型对象版本号
     */
    @Override
    public List<ModelVersion> selectModelVersionList(ModelVersion modelVersion)
    {
        return modelVersionMapper.selectModelVersionList(modelVersion);
    }

    /**
     * 新增模型对象版本号
     * 
     * @param modelVersion 模型对象版本号
     * @return 结果
     */
    @Override
    public int insertModelVersion(ModelVersion modelVersion)
    {
        int ret = 0;

        modelVersion.setCreateTime(DateUtils.getNowDate());
        ret = ret + modelVersionMapper.insertModelVersion(modelVersion);

        // 更新模型对象版本
        ModelProject modelProject = new ModelProject();
        modelProject.setId(modelVersion.getProjectId());
        modelProject.setVersionId(modelVersion.getId());
        modelProject.setUpdateBy(modelVersion.getCreateBy());
        modelProject.setUpdateTime(modelVersion.getCreateTime());
        ret = ret + modelProjectMapper.updateModelProject(modelProject);

        // 保存数据类型履历
        ret = ret + modelVersionMapper.saveDataTypeVersion(modelVersion);

        // 保存数据表履历
        ModelEntity modelEntity = new ModelEntity();
        modelEntity.setProjectId(modelVersion.getProjectId());
        modelEntity.setVersionId(0L);
        List<ModelEntity> entityList = modelEntityMapper.selectModelEntityList(modelEntity);
        for(ModelEntity me : entityList) {
            ModelEntity nme = new ModelEntity();
            nme.setParentEntityId(me.getId());
            nme.setProjectId(me.getProjectId());
            nme.setVersionId(modelVersion.getId());
            nme.setEntityName(me.getEntityName());
            nme.setEntityCode(me.getEntityCode());
            nme.setEntitySort(me.getEntitySort());
            nme.setRemark(me.getRemark());
            nme.setParentVersionId(me.getVersionId());
            nme.setCreateBy(modelVersion.getCreateBy());
            nme.setCreateTime(modelVersion.getCreateTime());
            ret = ret + modelEntityMapper.insertModelEntity(nme);

            // 保存数据字段履历
            nme.setParentEntityId(me.getId());
            ret = ret + modelEntityMapper.saveModelFieldVersion(nme);
        }

        return ret;
    }

    /**
     * 修改模型对象版本号
     * 
     * @param modelVersion 模型对象版本号
     * @return 结果
     */
    @Override
    public int updateModelVersion(ModelVersion modelVersion)
    {
        modelVersion.setUpdateTime(DateUtils.getNowDate());
        return modelVersionMapper.updateModelVersion(modelVersion);
    }

    /**
     * 批量删除模型对象版本号
     * 
     * @param ids 需要删除的模型对象版本号主键
     * @return 结果
     */
    @Override
    public int deleteModelVersionByIds(String ids)
    {
        return modelVersionMapper.deleteModelVersionByIds(Convert.toStrArray(ids));
    }

    /**
     * 删除模型对象版本号信息
     * 
     * @param id 模型对象版本号主键
     * @return 结果
     */
    @Override
    public int deleteModelVersionById(Long id)
    {
        return modelVersionMapper.deleteModelVersionById(id);
    }

    /**
     * 查询模型对象版本号列表(带变更明细)
     *
     * @param modelVersion 模型对象版本号
     * @return 模型对象版本号集合
     */
    @Override
    public List<ModelVersion> selectModelVersionWithDetailList(ModelVersion modelVersion) {
        return modelVersionMapper.selectModelVersionWithDetailList(modelVersion);
    }

    /**
     * 根据版本好创建对应的sql脚本
     *
     * @param modelVersion
     * @return
     */
    @Override
    public ModelVersion buildVersionScript(ModelVersion modelVersion) {
        modelVersion.setDbType("mysql");
        modelVersion.setSyncFlag("0");
        String dbType = "mysql";
        // 模型对象id
        Long projectId = modelVersion.getProjectId();
        // 查看版本id
        Long versionId = modelVersion.getId() == null ? 0L:modelVersion.getId();
        // 上一个版本
        Long parentVersionId = 0L;

        ModelProject modelProject = modelProjectMapper.selectModelProjectById(modelVersion.getProjectId());
        if(modelProject.getVersionId() != null && modelProject.getVersionId() != 0L) {
            if(modelVersion.getId() != null && modelVersion.getId() != 0L) {
                // 查看某个版本，需要拿上个版本
                ModelVersion mv = modelVersionMapper.selectModelVersionById(modelVersion.getId());
                if(mv != null) {
                    modelVersion.setVersionNo(mv.getVersionNo());
                    modelVersion.setVersionRemark(mv.getVersionRemark());
                    modelVersion.setSyncFlag(mv.getSyncFlag());
                    parentVersionId = mv.getParentVersionId();
                }
            } else {
                // 最新修改版本，则查看的是modelProject.versionId版及0版的内容
                // 0 <->modelProject.getVersionId()
                modelVersion.setVersionNo("最新内容");
                modelVersion.setVersionRemark("最新变化内容未保存版本");
                parentVersionId = modelProject.getVersionId();
            }
        } else {
            modelVersion.setVersionNo("初版内容");
            modelVersion.setVersionRemark("初版内容未保存版本");
        }
        modelVersion.setParentVersionId(parentVersionId);

        VersionScript script = buildScript(modelVersion);
        modelVersion.setChangeContent(script.getChangeContent());
        modelVersion.setScriptContent(script.getScriptContent());
        return modelVersion;
    }

    /**
     * 生成脚本
     *
     * @param modelVersion
     * @return
     */
    private VersionScript buildScript(ModelVersion modelVersion) {
        // 初始化返回对象
        VersionScript retObj = new VersionScript();
        retObj.setChangeContent("");
        retObj.setScriptContent("");

        StringBuffer sbScriptContent = new StringBuffer();
        StringBuffer sbChangeContent = new StringBuffer();

        // 新版本内容
        ModelEntity modelEntity = new ModelEntity();
        modelEntity.setProjectId(modelVersion.getProjectId());
        modelEntity.setVersionId(modelVersion.getId());
        List<ModelEntity> newEntityList = modelEntityMapper.selectModelEntityWithFieldList(modelEntity);

        // 无数据
        if(newEntityList == null || newEntityList.size() <= 0) {
            return retObj;
        }

        VersionScript tmpVs = new VersionScript();

        VelocityInitializer.initVelocity();
        List<ModelEntity> baseEntityList = null;
        if(modelVersion.getParentVersionId() != 0L) {
            // 上一个版本
            modelEntity.setVersionId(modelVersion.getParentVersionId());
            baseEntityList = modelEntityMapper.selectModelEntityWithFieldList(modelEntity);
        }
        if(baseEntityList != null && baseEntityList.size() >0) {
            // 比较版本内容
            for (ModelEntity me : newEntityList) {
                boolean exist = false;
                for (ModelEntity bme : baseEntityList) {
                    // 找到相同表
                    if(bme.getEntityCode().equalsIgnoreCase(me.getEntityCode())) {
                        // 数据表注释更新
                        if(!StringUtils.equals(StringUtils.trim(bme.getEntityName()),StringUtils.trim(me.getEntityName()))) {
                            // 数据表注释更新
                            tmpVs = updateTableCommentScript(bme.getEntityCode(), bme.getEntityName(), me.getEntityName(), modelVersion.getDbType());
                            sbChangeContent.append(tmpVs.getChangeContent());
                            sbChangeContent.append(Constants.NEW_LINE);
                            sbScriptContent.append(tmpVs.getScriptContent());
                        }
                        // 字段更新
                        List<ModelField> baseFields = bme.getFields();
                        List<ModelField> fields = me.getFields();
                        if(fields == null || fields.size() <=0){
                            sbChangeContent.append("异常：数据表【" + modelEntity.getEntityName() + "】[" + modelEntity.getEntityCode() + "]字段信息未设置。");
                            sbChangeContent.append(Constants.NEW_LINE);
                            break;
                        }
                        // 匹配字段
                        String addAfter = "FIRST";
                        for(ModelField mf:fields) {
                            mf.setEntityCode(me.getEntityCode());
                            mf.setEntityName(me.getEntityName());
                            mf.setAddAfter(addAfter);

                            boolean fexist = false;
                            String bAddAfter = "FIRST";
                            for(ModelField bmf:baseFields) {
                                bmf.setAddAfter(bAddAfter);
                                if(bmf.getFieldCode().equals(mf.getFieldCode())) {
                                    if((!StringUtils.equalsIgnoreCase(bmf.getFieldName(),mf.getFieldName()) ||
                                            !StringUtils.equalsIgnoreCase(bmf.getNotNull(),mf.getNotNull()) ||
                                            !StringUtils.equalsIgnoreCase(bmf.getAutoIncrement(),mf.getAutoIncrement()) ||
                                            !StringUtils.equalsIgnoreCase(bmf.getDefaultValue(),mf.getDefaultValue()) ||
                                            !StringUtils.equalsIgnoreCase(bmf.getAddAfter(),mf.getAddAfter()) ||
                                            !StringUtils.equalsIgnoreCase(bmf.getFieldTypeCode(),mf.getFieldTypeCode()))) {
                                        // 更新字段设置
                                        tmpVs = modifyFieldScript(mf, bmf, modelVersion.getDbType());
                                        sbChangeContent.append(tmpVs.getChangeContent());
                                        sbChangeContent.append(Constants.NEW_LINE);
                                        sbScriptContent.append(tmpVs.getScriptContent());
                                    }
                                    fexist = true;
                                    break;
                                }
                                bAddAfter = "AFTER " + bmf.getFieldCode();
                            }
                            if(!fexist) {
                                // 新建字段
                                tmpVs = createFieldScript(mf, modelVersion.getDbType());
                                sbChangeContent.append(tmpVs.getChangeContent());
                                sbChangeContent.append(Constants.NEW_LINE);
                                sbScriptContent.append(tmpVs.getScriptContent());
                            }
                            addAfter = "AFTER " + mf.getFieldCode();
                        }

                        // 删除字段
                        for(ModelField bmf : baseFields) {
                            bmf.setEntityCode(bme.getEntityCode());
                            bmf.setEntityName(bme.getEntityName());

                            boolean fexist = false;
                            for (ModelField mf : fields) {
                                if (bmf.getFieldCode().equals(mf.getFieldCode())) {
                                    fexist = true;
                                    break;
                                }
                            }
                            if (!fexist) {
                                // 删除字段
                                tmpVs = deleteFieldScript(bmf, modelVersion.getDbType());
                                sbChangeContent.append(tmpVs.getChangeContent());
                                sbChangeContent.append(Constants.NEW_LINE);
                                sbScriptContent.append(tmpVs.getScriptContent());
                            }
                        }
                        // 相同表
                        exist = true;
                        break;
                    }
                }
                if(!exist) {
                    // 新建数据表
                    tmpVs = createTableScript(me, modelVersion.getDbType());
                    sbChangeContent.append(tmpVs.getChangeContent());
                    sbChangeContent.append(Constants.NEW_LINE);
                    sbScriptContent.append(tmpVs.getScriptContent());
                }
            }

            //删除数据表
            for (ModelEntity bme : baseEntityList) {
                boolean exist = false;
                for (ModelEntity me : baseEntityList) {
                    // 找到相同表
                    if(bme.getEntityCode().equalsIgnoreCase(me.getEntityCode())) {
                        exist = true;
                        break;
                    }
                }
                if(!exist) {
                    // 删除数据表
                    tmpVs = deleteTableScript(bme, modelVersion.getDbType());
                    sbChangeContent.append(tmpVs.getChangeContent());
                    sbChangeContent.append(Constants.NEW_LINE);
                    sbScriptContent.append(tmpVs.getScriptContent());
                }
            }
        } else {
            for (ModelEntity me : newEntityList) {
                // 新建数据表
                tmpVs = createTableScript(me, modelVersion.getDbType());
                sbChangeContent.append(tmpVs.getChangeContent());
                sbChangeContent.append(Constants.NEW_LINE);
                sbScriptContent.append(tmpVs.getScriptContent());
            }
        }

        // 返回信息
        retObj.setChangeContent(sbChangeContent.toString());
        retObj.setScriptContent(sbScriptContent.toString());
        return retObj;
    }

    /**
     * 新建数据表
     * @param modelEntity
     * @return
     */
    private VersionScript createTableScript(ModelEntity modelEntity, String dbType){
        // 初始化返回对象
        VersionScript retObj = new VersionScript();
        retObj.setChangeContent("");
        retObj.setScriptContent("");

        List<ModelField> fields = modelEntity.getFields();
        if(fields == null || fields.size() <= 0) {
            return retObj;
        }

        // 设置模板变量信息
        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("modelEntity", modelEntity);
        // 获取模板
        String template = "vm/sql/" + dbType + "/createTable.vm";
        // 渲染模板
        StringWriter sw = new StringWriter();
        Template tpl = Velocity.getTemplate(template, Constants.UTF8);
        tpl.merge(velocityContext, sw);
        retObj.setChangeContent("新建数据表：【" + modelEntity.getEntityCode() + "】【" + modelEntity.getEntityName() + "】");
        retObj.setScriptContent(sw.toString());
        log.info(retObj.getScriptContent());
        IOUtils.closeQuietly(sw);
        return retObj;
    }

    /**
     * 新建数据表字段
     * @param modelField
     * @return
     */
    private VersionScript createFieldScript(ModelField modelField, String dbType){
        // 初始化返回对象
        VersionScript retObj = new VersionScript();
        retObj.setChangeContent("");
        retObj.setScriptContent("");

        // 设置模板变量信息
        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("modelField", modelField);
        // 获取模板
        String template = "vm/sql/" + dbType + "/createField.vm";
        // 渲染模板
        StringWriter sw = new StringWriter();
        Template tpl = Velocity.getTemplate(template, Constants.UTF8);
        tpl.merge(velocityContext, sw);
        retObj.setChangeContent("新建数据表字段：【[" + modelField.getEntityCode() + "].[" + modelField.getFieldCode() + "]】【[" + modelField.getEntityName() + "].[" + modelField.getFieldName() + "]】");
        retObj.setScriptContent(sw.toString());
        log.info(retObj.getScriptContent());
        IOUtils.closeQuietly(sw);
        return retObj;
    }

    /**
     * 修改数据表注释
     * @param entityCode
     * @param baseEntityName
     * @param entityName
     * @param dbType
     * @return
     */
    private VersionScript updateTableCommentScript(String entityCode, String baseEntityName, String entityName, String dbType){
        // 初始化返回对象
        VersionScript retObj = new VersionScript();
        retObj.setChangeContent("");
        retObj.setScriptContent("");

        // 设置模板变量信息
        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("entityCode", StringUtils.trim(entityCode));
        velocityContext.put("baseEntityName", baseEntityName);
        velocityContext.put("entityName", StringUtils.trim(entityName));
        // 获取模板
        String template = "vm/sql/" + dbType + "/updateTableComment.vm";
        // 渲染模板
        StringWriter sw = new StringWriter();
        Template tpl = Velocity.getTemplate(template, Constants.UTF8);
        tpl.merge(velocityContext, sw);
        retObj.setChangeContent("更新数据表注释：【" + entityCode + "】【" + baseEntityName + " => " + entityName + "】");
        retObj.setScriptContent(sw.toString());
        log.info(retObj.getScriptContent());
        IOUtils.closeQuietly(sw);
        return retObj;
    }

    /**
     * 修改数据表字段
     * @param me
     * @param bmf
     * @param dbType
     * @return
     */
    private VersionScript modifyFieldScript(ModelField me, ModelField bmf, String dbType){
        // 初始化返回对象
        VersionScript retObj = new VersionScript();
        retObj.setChangeContent("");
        retObj.setScriptContent("");

        // 设置模板变量信息
        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("modelField", me);
        velocityContext.put("baseField", bmf);

        // 获取模板
        String template = "vm/sql/" + dbType + "/modifyField.vm";
        // 渲染模板
        StringWriter sw = new StringWriter();
        Template tpl = Velocity.getTemplate(template, Constants.UTF8);
        tpl.merge(velocityContext, sw);
        retObj.setChangeContent("更新数据表字段：【[" + me.getEntityCode() + "].[" + me.getFieldCode() + "]】【[" + me.getEntityName() + "].[" + me.getFieldName() + "]】");
        retObj.setScriptContent(sw.toString());
        log.info(retObj.getScriptContent());
        IOUtils.closeQuietly(sw);
        return retObj;
    }

    /**
     * 删除数据表
     * @param modelEntity
     * @return
     */
    private VersionScript deleteTableScript(ModelEntity modelEntity, String dbType){
        // 初始化返回对象
        VersionScript retObj = new VersionScript();
        retObj.setChangeContent("");
        retObj.setScriptContent("");

        // 设置模板变量信息
        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("modelEntity", modelEntity);
        // 获取模板
        String template = "vm/sql/" + dbType + "/deleteTable.vm";
        // 渲染模板
        StringWriter sw = new StringWriter();
        Template tpl = Velocity.getTemplate(template, Constants.UTF8);
        tpl.merge(velocityContext, sw);
        retObj.setChangeContent("删除数据表：【" + modelEntity.getEntityCode() + "】【" + modelEntity.getEntityName() + "】");
        retObj.setScriptContent(sw.toString());
        log.info(retObj.getScriptContent());
        IOUtils.closeQuietly(sw);
        return retObj;
    }

    /**
     * 删除数据表字段
     * @param modelField
     * @return
     */
    private VersionScript deleteFieldScript(ModelField modelField, String dbType){
        // 初始化返回对象
        VersionScript retObj = new VersionScript();
        retObj.setChangeContent("");
        retObj.setScriptContent("");

        // 设置模板变量信息
        VelocityContext velocityContext = new VelocityContext();
        velocityContext.put("modelField", modelField);
        // 获取模板
        String template = "vm/sql/" + dbType + "/deleteField.vm";
        // 渲染模板
        StringWriter sw = new StringWriter();
        Template tpl = Velocity.getTemplate(template, Constants.UTF8);
        tpl.merge(velocityContext, sw);
        retObj.setChangeContent("删除数据表字段：【[" + modelField.getEntityCode() + "].[" + modelField.getFieldCode() + "]】【[" + modelField.getEntityName() + "].[" + modelField.getFieldName() + "]】");
        retObj.setScriptContent(sw.toString());
        log.info(retObj.getScriptContent());
        IOUtils.closeQuietly(sw);
        return retObj;
    }
}
