package com.agileboot.codegen.util;

import com.agileboot.codegen.entity.ClassInfo;
import com.agileboot.codegen.entity.FieldInfo;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 表解析工具类
 */
public class TableParseUtil {

    /**
     * 解析DDL SQL语句获取ClassInfo
     *
     * @param sql          DDL SQL语句
     * @param ignorePrefix 忽略前缀
     * @return ClassInfo对象
     */
    public static ClassInfo parseTableSql(String sql, String ignorePrefix) {
        if (StringUtils.isBlank(sql)) {
            return null;
        }

        try {
            ClassInfo classInfo = new ClassInfo();
            List<FieldInfo> fieldList = new ArrayList<>();

            // 解析表名和注释
            parseTableInfo(sql, classInfo, ignorePrefix);

            // 解析字段信息
            parseFieldInfo(sql, fieldList);

            classInfo.setFieldList(fieldList);
            
            // 验证解析结果
            if (StringUtils.isBlank(classInfo.getTableName())) {
                throw new RuntimeException("无法解析表名，请检查SQL语句格式");
            }
            
            if (fieldList.isEmpty()) {
                throw new RuntimeException("无法解析字段信息，请检查SQL语句格式");
            }
            
            return classInfo;
        } catch (Exception e) {
            throw new RuntimeException("解析DDL SQL失败: " + e.getMessage(), e);
        }
    }

    /**
     * 解析表信息
     */
    private static void parseTableInfo(String sql, ClassInfo classInfo, String ignorePrefix) {
        // 匹配表名的正则表达式
        Pattern tablePattern = Pattern.compile("CREATE\\s+TABLE\\s+[`'\"]*([\\w_]+)[`'\"]*", Pattern.CASE_INSENSITIVE);
        Matcher tableMatcher = tablePattern.matcher(sql);

        if (tableMatcher.find()) {
            String tableName = tableMatcher.group(1);
            classInfo.setOriginTableName(tableName);

            // 去掉前缀
            String processedTableName = tableName;
            if (StringUtils.isNotBlank(ignorePrefix) && tableName.startsWith(ignorePrefix)) {
                processedTableName = tableName.substring(ignorePrefix.length());
            }

            classInfo.setTableName(processedTableName);
            classInfo.setClassName(toCamelCase(processedTableName, true));
        }

        // 匹配表注释
        Pattern commentPattern = Pattern.compile("COMMENT\\s*=\\s*['\"]([^'\"]*)['\"]", Pattern.CASE_INSENSITIVE);
        Matcher commentMatcher = commentPattern.matcher(sql);
        if (commentMatcher.find()) {
            classInfo.setClassComment(commentMatcher.group(1));
        }
    }

    /**
     * 解析字段信息
     */
    private static void parseFieldInfo(String sql, List<FieldInfo> fieldList) {
        // 匹配字段定义的正则表达式
        Pattern fieldPattern = Pattern.compile(
                "[`'\"]*([\\w_]+)[`'\"]*\\s+([\\w()]+).*?(?:COMMENT\\s*['\"]([^'\"]*)['\"])?",
                Pattern.CASE_INSENSITIVE
        );

        String[] lines = sql.split("\n");
        for (String line : lines) {
            line = line.trim();
            // 跳过非字段行
            if (line.startsWith("CREATE") || line.startsWith("PRIMARY") ||
                    line.startsWith("KEY") || line.startsWith("INDEX") ||
                    line.startsWith(")") || line.isEmpty()) {
                continue;
            }

            Matcher fieldMatcher = fieldPattern.matcher(line);
            if (fieldMatcher.find()) {
                FieldInfo fieldInfo = new FieldInfo();
                String columnName = fieldMatcher.group(1);
                String columnType = fieldMatcher.group(2);
                String comment = fieldMatcher.group(3);

                fieldInfo.setColumnName(columnName);
                fieldInfo.setFieldName(toCamelCase(columnName, false));
                fieldInfo.setFieldClass(getJavaType(columnType));
                fieldInfo.setSwaggerClass(getSwaggerType(columnType));
                fieldInfo.setFieldComment(comment != null ? comment : "");

                fieldList.add(fieldInfo);
            }
        }
    }

    /**
     * 转换为驼峰命名
     *
     * @param str        原字符串
     * @param firstUpper 首字母是否大写
     * @return 驼峰命名字符串
     */
    private static String toCamelCase(String str, boolean firstUpper) {
        if (StringUtils.isBlank(str)) {
            return str;
        }

        StringBuilder result = new StringBuilder();
        String[] parts = str.toLowerCase().split("_");

        for (int i = 0; i < parts.length; i++) {
            String part = parts[i];
            if (StringUtils.isNotBlank(part)) {
                if (i == 0 && !firstUpper) {
                    result.append(part);
                } else {
                    result.append(part.substring(0, 1).toUpperCase())
                            .append(part.substring(1));
                }
            }
        }

        return result.toString();
    }

    /**
     * 获取Java类型
     */
    private static String getJavaType(String mysqlType) {
        String lowerType = mysqlType.toLowerCase();
        if (lowerType.contains("bigint")) {
            return "Long";
        } else if (lowerType.contains("int") || lowerType.contains("tinyint")) {
            return "Integer";
        } else if (lowerType.contains("varchar") || lowerType.contains("text") || lowerType.contains("char")) {
            return "String";
        } else if (lowerType.contains("decimal") || lowerType.contains("double")) {
            return "Double";
        } else if (lowerType.contains("float")) {
            return "Float";
        } else if (lowerType.contains("date") || lowerType.contains("time")) {
            return "Date";
        } else {
            return "String";
        }
    }

    /**
     * 获取Swagger类型
     */
    private static String getSwaggerType(String mysqlType) {
        String lowerType = mysqlType.toLowerCase();
        if (lowerType.contains("int") || lowerType.contains("tinyint")) {
            return "integer";
        } else if (lowerType.contains("varchar") || lowerType.contains("text") || lowerType.contains("char")) {
            return "string";
        } else if (lowerType.contains("decimal") || lowerType.contains("double") || lowerType.contains("float")) {
            return "number";
        } else if (lowerType.contains("date") || lowerType.contains("time")) {
            return "string";
        } else {
            return "string";
        }
    }
}
