package cn.stylefeng.team.meta.sdk.parser;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.stylefeng.roses.kernel.rule.enums.YesOrNotEnum;
import cn.stylefeng.roses.kernel.rule.exception.base.ServiceException;
import cn.stylefeng.team.meta.api.CreateTableSqlParseApi;
import cn.stylefeng.team.meta.api.entity.MetaField;
import cn.stylefeng.team.meta.api.pojo.TableParseInfo;
import cn.stylefeng.team.meta.sdk.exception.SqlParseExceptionEnum;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLObject;
import com.alibaba.druid.sql.ast.expr.SQLCharExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.ast.statement.SQLColumnConstraint;
import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLCreateTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLNotNullConstraint;
import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
import com.alibaba.druid.sql.parser.SQLStatementParser;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;

@Slf4j
public class MySqlCreateTableSqlParser implements CreateTableSqlParseApi {

    private static final String INPUT_CODE = "input";

    @Override
    public TableParseInfo parseToFields(String sql) {

        if (StrUtil.isBlank(sql)) {
            throw new ServiceException(SqlParseExceptionEnum.SQL_IS_EMPTY);
        }

        TableParseInfo tableParseInfo = new TableParseInfo();
        List<MetaField> metaFieldList = new ArrayList<>();

        SQLStatementParser parser = new MySqlStatementParser(sql);

        SQLCreateTableStatement sqlCreateTableStatement = null;
        try {
            sqlCreateTableStatement = parser.parseCreateTable();
        } catch (Exception e) {
            throw new ServiceException(SqlParseExceptionEnum.PARSE_SQL_ERROR);
        }
        List<SQLObject> sqlObjects = sqlCreateTableStatement.getChildren();

        tableParseInfo.setTableName(this.replaceSymbol(sqlCreateTableStatement.getTableName()));
        tableParseInfo.setTableComment(this.replaceSymbol(this.sqlExprToString(sqlCreateTableStatement.getComment())));

        for (SQLObject sqlObject : sqlObjects) {

            if (!(sqlObject instanceof SQLColumnDefinition)) {
                continue;
            }

            MetaField metaField = new MetaField();
            SQLColumnDefinition columnDefinition = ((SQLColumnDefinition) sqlObject);

            String simpleName = columnDefinition.getName().getSimpleName();
            metaField.setFieldCode(this.replaceSymbol(simpleName));

            Integer fieldType = this.getFieldType(columnDefinition);
            metaField.setFieldType(fieldType);

            metaField.setFieldLength(this.getFieldLength(columnDefinition));

            metaField.setDecimalLength(this.getDecimalLength(columnDefinition));

            metaField.setNotEmptyFlag(this.getNotEmptyFlag(columnDefinition));

            metaField.setKeyFlag(this.getKeyFlag(columnDefinition));

            metaField.setDescription(this.getComment(columnDefinition));

            metaField.setRealFlag(YesOrNotEnum.Y.getCode());

            metaField.setDefaultFormComponent(INPUT_CODE);

            metaFieldList.add(metaField);
        }

        tableParseInfo.setMetaFieldList(metaFieldList);
        return tableParseInfo;
    }

    private String sqlExprToString(SQLExpr sqlExpr) {
        if (sqlExpr instanceof SQLCharExpr) {
            return ((SQLCharExpr) sqlExpr).getText();
        } else if (sqlExpr instanceof SQLIdentifierExpr) {
            return ((SQLIdentifierExpr) sqlExpr).normalizedName();
        }
        return null;
    }

    private Integer getFieldType(SQLColumnDefinition columnDefinition) {

        String mysqlColumnType = columnDefinition.getDataType().getName();
        return MysqlTypeToMetaFieldType.getMetaType(mysqlColumnType);
    }

    private String getComment(SQLColumnDefinition columnDefinition) {
        if (ObjectUtil.isEmpty(columnDefinition.getComment())) {
            return "";
        } else {
            return this.sqlExprToString(columnDefinition.getComment());
        }
    }

    private String getNotEmptyFlag(SQLColumnDefinition columnDefinition) {
        System.out.println(columnDefinition);

        List<SQLColumnConstraint> constraints = columnDefinition.getConstraints();
        if (ObjectUtil.isEmpty(constraints)) {
            return YesOrNotEnum.N.getCode();
        }

        for (SQLColumnConstraint constraint : constraints) {
            if (constraint instanceof SQLNotNullConstraint) {
                return YesOrNotEnum.Y.getCode();
            }
        }

        return YesOrNotEnum.N.getCode();
    }

    private String getKeyFlag(SQLColumnDefinition columnDefinition) {
        boolean primaryKey = columnDefinition.isPrimaryKey();
        return primaryKey ? YesOrNotEnum.Y.getCode() : YesOrNotEnum.N.getCode();
    }

    private Integer getFieldLength(SQLColumnDefinition columnDefinition) {
        List<SQLExpr> arguments = columnDefinition.getDataType().getArguments();
        if (ObjectUtil.isEmpty(arguments)) {
            return null;
        }
        SQLExpr sqlExpr = arguments.get(0);
        if (sqlExpr instanceof SQLIntegerExpr) {
            return ((SQLIntegerExpr) sqlExpr).getNumber().intValue();
        }
        return null;
    }

    private Integer getDecimalLength(SQLColumnDefinition columnDefinition) {
        List<SQLExpr> arguments = columnDefinition.getDataType().getArguments();
        if (ObjectUtil.isEmpty(arguments) || arguments.size() <= 1) {
            return null;
        }
        SQLExpr sqlExpr = arguments.get(1);
        if (sqlExpr instanceof SQLIntegerExpr) {
            return ((SQLIntegerExpr) sqlExpr).getNumber().intValue();
        }
        return null;
    }

    private String replaceSymbol(String name) {
        return SQLUtils.normalize(name);
    }

}
