package cn.ibizlab.codegen.model;

import net.ibizsys.model.database.IPSDEFDTColumn;
import net.ibizsys.model.dataentity.IPSDataEntity;
import net.ibizsys.model.dataentity.defield.IPSDEField;
import net.ibizsys.model.dataentity.defield.IPSLinkDEField;
import net.ibizsys.model.dataentity.der.IPSDER1N;
import net.ibizsys.model.dataentity.der.IPSDERBase;
import net.ibizsys.model.dataentity.ds.IPSDEDataQueryCode;
import net.ibizsys.model.dataentity.ds.IPSDEDataQueryCodeCond;
import net.ibizsys.model.dataentity.ds.IPSDEDataSetGroupParam;
import net.ibizsys.model.dataentity.ds.PSDEDataSetGroupParamImpl;
import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class TransUtils {







    public static String contextParamConvert(String contextParam)
    {
        String resultParam=getJavaSqlCode(contextParam).replaceAll("(IN|in) \\(\\$\\{srf(datacontext|sessioncontext|webcontext)\\('(\\w+)','(.*?)'\\)}\\)","$1 (\\${ctx.$2.$3})");
        resultParam=resultParam.replaceAll("\\$\\{srf(datacontext|sessioncontext|webcontext)\\('(\\w+)','(.*?)'\\)}","#{ctx.$1.$2}");
        resultParam=resultParam.replaceAll("\\$\\{srf(datacontext|sessioncontext|webcontext)\\('(\\w+)'\\)}","#{ctx.$1.$2}");

        Pattern p = Pattern.compile("ctx.(datacontext|sessioncontext|webcontext).(\\w+)");
        Matcher m = p.matcher(resultParam);
        StringBuffer sb = new StringBuffer();

        while(m.find()){
            String match = m.group();

            resultParam=resultParam.replace(match,match.toLowerCase());

        }

        resultParam=resultParam.replace("AND t11.SRFDCID = '__SRFSAASDCID__'","");
        return resultParam;
    }


    public static String getQueryCode(IPSDEDataQueryCode dq)
    {
        String code=contextParamConvert(dq.getQueryCode());
        if(dq.getPSDEDataQueryCodeConds()!=null)
        {
            int i=0;
            boolean b=checkIgnoreNullvalueCond(dq.getPSDEDataQueryCodeConds());
            for(IPSDEDataQueryCodeCond cond:dq.getPSDEDataQueryCodeConds())
            {
                if(i==0)
                    code=code.concat(" where ");
                else if(i>0)
                    code=code.concat(" and ");

                code=code.concat(b?checkNullContextParamConvert(cond.getCustomCond()):contextParamConvert(cond.getCustomCond()));
                i++;
            }
        }
        return code;
    }



    private static String getJavaSqlCode(String strSQLCode)
    {
        strSQLCode = strSQLCode.replace("\r\n", " ");
        strSQLCode = strSQLCode.replace("\r", " ");
        strSQLCode = strSQLCode.replace("\n", " ");
        strSQLCode = strSQLCode.replace("\"", "\\\"");
        return strSQLCode;
    }


    public static String checkNullContextParamConvert(String contextParam) {
        String resultParam = getJavaSqlCode(contextParam).replaceAll("<#assign _value=srf(datacontext|sessioncontext|webcontext)\\('(\\w+)','(.*?)'\\)><#if _value\\?length gt 0>(.*?)\\(\\$\\{_value}\\)<#else>1=1</#if>"," ('${ctx.$1.$2}'=null or '${ctx.$1.$2}'='' or  $4  \\${ctx.$1.$2} ");
        resultParam = resultParam.replaceAll("<#assign _value=srf(datacontext|sessioncontext|webcontext)\\('(\\w+)','(.*?)'\\)><#if _value\\?length gt 0>(.*?)\\$\\{_value}(.*?)?<#else>1=1</#if>", " (#{ctx.$1.$2}=null or #{ctx.$1.$2}='' or $4#{ctx.$1.$2}$5)");
        resultParam=contextParamConvert(resultParam);
        return resultParam;
    }

    public static boolean checkIgnoreNullvalueCond(List<IPSDEDataQueryCodeCond> list)
    {
        if(list!=null)
        {
            for(IPSDEDataQueryCodeCond cond:list)
            {
                if(getJavaSqlCode(cond.getCustomCond()).matches("(.*?)srf(datacontext|sessioncontext|webcontext)(.*?)\\\\\"ignoreempty\\\\\":true(.*?)"))
                    return true;
            }
        }
        return false;
    }

    public static POSchema PojoSchema2DocumentPO(PojoSchema pojoSchema)
    {
        POSchema poSchema=new POSchema().setName(pojoSchema.getCodeName().toLowerCase()).setDefaultDataSource(pojoSchema.getDefaultDataSoruce())
                .setRemarks(pojoSchema.getTitle()).setLogicVal(pojoSchema.getOptions().getLogicVal()).setLogicDelVal(pojoSchema.getOptions().getLogicDelVal());


        for(String name:pojoSchema.getProperties().keySet())
        {
            PojoSchema sub=pojoSchema.getProperties().get(name);


            String dataType=sub.getOptions().getDataType();
            Integer length=sub.getOptions().getDataLength();
            Integer precision=sub.getOptions().getDataPreci();

            POSchema.Column column=new POSchema.Column().setName(name).setAlias(name).setRemarks(sub.getTitle()).setDefaultValue(sub.getOptions().getDefaultValue()).setPredefined(sub.getOptions().getPredefined()).setLength(length);

            if(PojoSchema.Type.object.getCode().equals(sub.getType())||PojoSchema.Type.array.getCode().equals(sub.getType()))
            {
                if(!sub.getOptions().isPhysicalField())
                    continue;

                if(StringUtils.isEmpty(dataType))dataType="TEXT";
                column.setType(dataType);
                column.setLength(null);
            }
            else if(PojoSchema.Type.string.getCode().equals(sub.getType())&&(!StringUtils.isEmpty(sub.getFormat())))
            {
                if(StringUtils.isEmpty(dataType)&&(sub.getFormat().indexOf("date")>=0))
                    dataType="DATETIME";
                else
                    dataType="VARCHAR";
                column.setType(dataType);
            }
            else if(PojoSchema.Type.integer.getCode().equals(sub.getType()) )
            {
                if(StringUtils.isEmpty(dataType))dataType="INT";
                column.setType(dataType);
            }
            else if(PojoSchema.Type.number.getCode().equals(sub.getType()) )
            {
                if(StringUtils.isEmpty(dataType))dataType="NUMBER";
                column.setType(dataType);
            }
            else {
                if(StringUtils.isEmpty(dataType))dataType="VARCHAR";
                column.setType(dataType);
            }

            if(column.isNumber())
                column.setPrecision(precision);

            if((pojoSchema.getRequired()!=null&&pojoSchema.getRequired().contains(name))||(!pojoSchema.getOptions().isNullable()))
                column.getConstraints(true).setNullable(false);

            if(pojoSchema.getKeyMap()!=null&&pojoSchema.getKeyMap().containsKey(column.getName())) {
                String primaryKeyName="PK_"+poSchema.getName().toUpperCase()+"_"+ column.getName().toUpperCase();
                column.getConstraints(true).setPrimaryKey(true).setPrimaryKeyName(primaryKeyName);
            }
            if(sub.getOptions().isLogicValidField())
            {
                if(!StringUtils.isEmpty(pojoSchema.getOptions().getLogicVal()))
                    column.setDefaultValue(pojoSchema.getOptions().getLogicVal());
                else
                    column.setDefaultValue("1");
            }
            if(!StringUtils.isEmpty(sub.getOptions().getSearchModes()))
                column.putSearchModes(sub.getOptions().getSearchModes());

            if("PICKUP".equals(sub.getOptions().getFieldType())&&sub.getOptions().isPhysicalField())
            {
                PojoSchema relationshipModel=pojoSchema.getRefSchema(sub.getOptions().getRelationName());
                String fkName=sub.getOptions().getRelationName().toUpperCase();
                if((!StringUtils.isEmpty(relationshipModel.getOptions().getRefTableName()))&&(!StringUtils.isEmpty(fkName))) {
                    column.getConstraints(true).setReferencedTableName(relationshipModel.getOptions().getRefTableName()).setReferencedColumnNames(sub.getOptions().getRefFieldName()).setForeignKeyName(fkName);
                    poSchema.addForeignKeyConstraint(new POSchema.ForeignKeyConstraint().setConstraintName(fkName).setBaseTableName(poSchema.getName()).setBaseColumnNames(column.getName()).setReferencedTableName(relationshipModel.getOptions().getRefTableName()).setReferencedColumnNames(sub.getOptions().getRefFieldName()));
                }
            }
            else  if((!StringUtils.isEmpty(sub.getOptions().getRelationName()))) {
                PojoSchema relationshipModel=pojoSchema.getRefSchema(sub.getOptions().getRelationName());
                if(relationshipModel!=null&&(!StringUtils.isEmpty(relationshipModel.getOptions().getTableName()))) {
                    column.getConstraints(true).setReferencedTableName(relationshipModel.getOptions().getTableName())
                            .setReferencedColumnNames(sub.getOptions().getRefFieldName());
                }
            }

            if(!sub.getOptions().isPhysicalField())
                poSchema.addTransient(column.setComputed(true));
            else
                poSchema.addColumn(column);

        }
        String defaultQueryScript=pojoSchema.getOptions().getDefaultQueryScript();
        if(!StringUtils.isEmpty(defaultQueryScript))
            poSchema.setDefaultQueryScriptSQL(defaultQueryScript);

        return poSchema;
    }


    public static POSchema EntityModelModel2PO(EntityModel entityModel, String dsType) {

        final String dataSourceType=dsType.toLowerCase();
        POSchema poSchema=new POSchema().setDsType(dataSourceType).setName(entityModel.getTableName(dataSourceType)).setDefaultDataSource(entityModel.getDsName())
                .setRemarks(entityModel.getLogicName()).setLogicVal(entityModel.getValidLogicValue()).setLogicDelVal(entityModel.getInvalidLogicValue());

        poSchema.setNode(entityModel.getDataEntity());

        Map<String,FieldModel> keyMap=new LinkedHashMap<>();
        Map<String,RelationshipModel> relationshipModelMap = new LinkedHashMap<>();
        if(entityModel.getKeyFields()!=null)entityModel.getKeyFields().forEach(model->keyMap.put(model.getFieldName(),model));

        int order = 1;
        for (FieldModel fieldModel : entityModel.getFields()) {
            IPSDEField sub=fieldModel.getDataEntityField();

            String colName=fieldModel.getColumnName(dataSourceType);

            Integer length=sub.getLength();
            Integer precision=sub.getPrecision();

            POSchema.Column column=new POSchema.Column().setName(colName).setAlias(sub.getCodeName()).setRemarks(sub.getLogicName()).setPredefined(sub.getPredefinedType()).setLength(length).setType(sub.getDataType());

            column.setNode(sub);

            if(column.isNumber())
                column.setPrecision(precision);

            if(!sub.isAllowEmpty())
                column.getConstraints(true).setNullable(false);

            if(keyMap.containsKey(column.getName())) {
                String primaryKeyName="PK_"+poSchema.getName().toUpperCase()+"_"+ column.getName().toUpperCase();
                column.getConstraints(true).setPrimaryKey(true).setPrimaryKeyName(primaryKeyName);
            }
            if(fieldModel.isLogicValidField())
            {
                if(!StringUtils.isEmpty(entityModel.getValidLogicValue()))
                    column.setDefaultValue(entityModel.getValidLogicValue());
                else
                    column.setDefaultValue("1");
            }

            Set<String> searchModes=fieldModel.getSearchMode();
            if(!ObjectUtils.isEmpty(searchModes))
                column.setSearchModes(searchModes);

            if(fieldModel.getReference()!=null&&sub.isLinkDEField())
            {
                RelationshipModel relationshipModel=fieldModel.getReference();
                String fkName=relationshipModel.getName().toUpperCase();
                if(relationshipModel!=null&&(!StringUtils.isEmpty(relationshipModel.getTableName()))&&(!StringUtils.isEmpty(fkName))) {
                    column.getConstraints(true).setReferencedTableName(relationshipModel.getTableName())
                            .setReferencedColumnNames(fieldModel.getRefFieldName()).setForeignKeyName(fkName);

                    poSchema.addForeignKeyConstraint(new POSchema.ForeignKeyConstraint().setConstraintName(fkName)
                            .setBaseTableName(poSchema.getName()).setBaseColumnNames(column.getName())
                            .setReferencedTableName(relationshipModel.getTableName()).setReferencedColumnNames(fieldModel.getRefFieldName()));
                }
                if(column.getSearchModes()==null)
                    column.setSearchModes(new LinkedHashSet<>());
                if(!column.getSearchModes().contains("eq"))
                    column.getSearchModes().add("eq");

            }
            else  if(fieldModel.getReference()!=null) {
                RelationshipModel relationshipModel = fieldModel.getReference();
                String fkName=relationshipModel.getName().toUpperCase();
                if(relationshipModel!=null&&(!StringUtils.isEmpty(relationshipModel.getTableName()))&&(!StringUtils.isEmpty(fkName))) {
                    column.getConstraints(true).setReferencedTableName(relationshipModel.getTableName())
                            .setReferencedColumnNames(fieldModel.getRefFieldName());
                }
            }

            if(!fieldModel.isPhisicalDEField())
                poSchema.addTransient(column.setComputed(true));
            else
                poSchema.addColumn(column);

            order++;
        }

        if(entityModel.getQueries()!=null)
        {

            entityModel.getQueries().forEach(dataSet->{

                if(dataSet.getDatasetId().startsWith(entityModel.getEntityName().toLowerCase()+"-")&&dataSet.getDatasetId().endsWith(dataSourceType))
                {
                    POSchema.Segment segment=new POSchema.Segment().setName(dataSet.getDatasetId()).setVendorProvider(dataSourceType).setBody(dataSet.getDsCode());
                    if(!StringUtils.isEmpty(dataSet.getDsModel()))
                        segment.setFormat(dataSet.getDsModel());
                    poSchema.addSegment(segment);
                }
                else  if(!dataSet.getDatasetId().startsWith(entityModel.getEntityName().toLowerCase()+"-"))
                {
                    POSchema.Segment segment=new POSchema.Segment().setName(dataSet.getCodeName().toString()).setVendorProvider(dataSourceType).setBody(dataSet.getDsCode());
                    if(!StringUtils.isEmpty(dataSet.getDsModel()))
                        segment.setFormat(dataSet.getDsModel());
                    poSchema.addSegment(segment);
                }
            });

        }


        return poSchema;
    }


}
