package com.ruoyi.oa.service.impl;

import com.ruoyi.oa.domain.bo.OaAiDataQueryBo;
import com.ruoyi.oa.domain.vo.DynamicDataVo;
import com.ruoyi.oa.domain.vo.TableColumnVo;
import com.ruoyi.oa.enums.TableMappingEnum;
import com.ruoyi.oa.service.IAiDataQueryService;
import com.ruoyi.oa.service.IDatabaseQueryService;
import com.ruoyi.oa.utils.AiServiceUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * AI数据查询服务实现类
 *
 * @author ruoyi
 * @date 2024-12-19
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AiDataQueryServiceImpl implements IAiDataQueryService {

    private final IDatabaseQueryService databaseQueryService;
    private final AiServiceUtil aiServiceUtil;

    @Override
    public DynamicDataVo queryDataByAi(OaAiDataQueryBo queryBo) {
        try {
            // 1. 从用户查询中提取关键词
            String[] keywords = extractKeywords(queryBo.getQuery());
            
            // 2. 根据关键词匹配相关表
            List<String> matchedTables = matchTablesByKeywords(keywords);
            
            // 3. 如果关键词匹配失败，使用AI智能识别表
            if (matchedTables.isEmpty()) {
                log.info("关键词匹配失败，使用AI智能识别表");
                matchedTables = identifyTablesByAi(queryBo.getQuery());
                
                if (matchedTables.isEmpty()) {
                    throw new RuntimeException("未找到与查询需求相关的数据表");
                }
            }
            
            // 4. 获取匹配表的字段信息
            Map<String, List<TableColumnVo>> tableColumns = databaseQueryService.getTableColumns(matchedTables);
            
            // 5. 生成AI提示词
            String prompt = generateAiPrompt(queryBo.getQuery(), matchedTables, tableColumns);
            
            // 6. 调用AI生成SQL
            String aiResponse = aiServiceUtil.callDeepSeek(prompt);
            
            // 7. 提取SQL语句
            String sql = extractSqlFromAiResponse(aiResponse);
            
            // 8. 执行SQL查询
            String primaryTable = matchedTables.get(0); // 使用第一个匹配的表作为主表
            DynamicDataVo result = databaseQueryService.executeQueryWithMeta(sql, primaryTable, queryBo.getIncludeMeta());
            
            // 9. 限制返回记录数
            if (result.getResponse() instanceof DynamicDataVo.TableData) {
                DynamicDataVo.TableData tableData = (DynamicDataVo.TableData) result.getResponse();
                if (tableData.getDatasource() != null && tableData.getDatasource().size() > queryBo.getLimit()) {
                    tableData.setDatasource(tableData.getDatasource().subList(0, queryBo.getLimit()));
                }
            }
            
            // 10. 根据数据内容智能选择renderType
            result = determineRenderType(result, queryBo.getQuery());
            
            return result;
            
        } catch (Exception e) {
            log.error("AI数据查询失败", e);
            throw new RuntimeException("AI数据查询失败: " + e.getMessage());
        }
    }

    @Override
    public List<String> matchTablesByKeywords(String[] keywords) {
        return TableMappingEnum.getTableNamesByKeywords(keywords);
    }

    @Override
    public String generateAiPrompt(String userQuery, List<String> tableNames, 
                                 Map<String, List<TableColumnVo>> tableColumns) {
        StringBuilder prompt = new StringBuilder();
        
        // 系统角色设定
        prompt.append("你是一个专业的数据库查询专家，请根据用户的需求和提供的数据库表结构信息，生成相应的SQL查询语句。\n\n");
        
        // 重要规则
        prompt.append("重要规则：\n");
        prompt.append("1. 只能生成SELECT查询语句，严禁生成INSERT、UPDATE、DELETE、DROP、CREATE、ALTER等修改数据的语句\n");
        prompt.append("2. 生成的SQL必须语法正确，可以直接执行\n");
        prompt.append("3. 如果涉及多表查询，请使用适当的JOIN语句\n");
        prompt.append("4. 请根据用户需求添加适当的WHERE条件、ORDER BY、LIMIT等子句\n");
        prompt.append("5. 确保查询能返回有意义的数据，避免空结果\n");
        prompt.append("6. 如果查询可能返回空结果，请添加适当的默认条件或使用COALESCE等函数\n");
        prompt.append("7. 只返回SQL语句，不要包含其他解释文字\n\n");
        
        // 用户需求
        prompt.append("用户需求：").append(userQuery).append("\n\n");
        
        // 相关表信息
        prompt.append("相关数据表信息：\n");
        for (String tableName : tableNames) {
            prompt.append("表名：").append(tableName).append("\n");
            prompt.append("表描述：").append(TableMappingEnum.getDescriptionByTableName(tableName)).append("\n");
            
            List<TableColumnVo> columns = tableColumns.get(tableName);
            if (columns != null) {
                prompt.append("字段信息：\n");
                for (TableColumnVo column : columns) {
                    prompt.append("  - ").append(column.getColumnName())
                          .append(" (").append(column.getColumnType()).append(")")
                          .append(" - ").append(column.getColumnComment() != null ? column.getColumnComment() : "无注释");
                    
                    if ("1".equals(column.getIsPk())) {
                        prompt.append(" [主键]");
                    }
                    if ("1".equals(column.getIsRequired())) {
                        prompt.append(" [必填]");
                    }
                    prompt.append("\n");
                }
            }
            prompt.append("\n");
        }
        
        // 输出要求
        prompt.append("请根据以上信息生成SQL查询语句，确保查询能返回有意义的数据。如果查询可能返回空结果，请考虑：\n");
        prompt.append("1. 使用LEFT JOIN而不是INNER JOIN\n");
        prompt.append("2. 添加适当的默认值或使用COALESCE函数\n");
        prompt.append("3. 使用LIMIT限制返回记录数（建议50条以内）\n");
        prompt.append("4. 添加ORDER BY确保结果有序\n");
        prompt.append("只返回SQL语句本身，不要包含任何其他文字。");
        
        return prompt.toString();
    }

    /**
     * 从用户查询中提取关键词
     */
    private String[] extractKeywords(String query) {
        if (query == null || query.trim().isEmpty()) {
            return new String[0];
        }
        
        // 移除常见的查询词汇
        String cleanedQuery = query.replaceAll("查询|获取|显示|查看|搜索|查找|统计|分析|的|表|情况|信息|数据", "");
        
        // 按空格、标点符号分割
        String[] words = cleanedQuery.split("[\\s,，。！？!?]+");
        
        // 过滤掉空字符串和太短的词
        List<String> keywords = new ArrayList<>();
        for (String word : words) {
            if (word != null && word.trim().length() >= 2) {
                keywords.add(word.trim());
            }
        }
        
        // 如果没有提取到关键词，尝试更简单的分割方式
        if (keywords.isEmpty()) {
            // 直接按字符分割，提取有意义的词组
            String[] simpleWords = cleanedQuery.split("");
            StringBuilder currentWord = new StringBuilder();
            for (String charStr : simpleWords) {
                if (charStr.matches("[\\u4e00-\\u9fa5]")) { // 中文字符
                    currentWord.append(charStr);
                } else {
                    if (currentWord.length() >= 2) {
                        keywords.add(currentWord.toString());
                    }
                    currentWord.setLength(0);
                }
            }
            // 处理最后一个词
            if (currentWord.length() >= 2) {
                keywords.add(currentWord.toString());
            }
        }
        
        return keywords.toArray(new String[0]);
    }

    /**
     * 使用AI智能识别相关的数据表
     */
    private List<String> identifyTablesByAi(String userQuery) {
        try {
            // 从数据库中获取所有可用的表信息
            Map<String, String> allTableDescriptions = getAvailableTablesFromDatabase();
            
            if (allTableDescriptions.isEmpty()) {
                log.warn("未从数据库获取到任何表信息");
                return new ArrayList<>();
            }
            
            // 构建AI提示词
            StringBuilder prompt = new StringBuilder();
            prompt.append("你是一个数据库专家，请根据用户的查询需求，从以下数据库表中选择最相关的表名。\n\n");
            prompt.append("用户查询：").append(userQuery).append("\n\n");
            prompt.append("可用的数据库表：\n");
            
            for (Map.Entry<String, String> entry : allTableDescriptions.entrySet()) {
                prompt.append("- ").append(entry.getKey()).append(" (").append(entry.getValue()).append(")\n");
            }
            
            prompt.append("\n请根据用户查询需求，返回最相关的表名（用逗号分隔，最多返回3个表）。");
            prompt.append("只返回表名，不要包含其他解释文字。");
            
            // 调用AI获取表名
            String aiResponse = aiServiceUtil.callDeepSeek(prompt.toString());
            
            // 解析AI返回的表名
            List<String> identifiedTables = parseTableNamesFromAiResponse(aiResponse, allTableDescriptions.keySet());
            
            log.info("AI识别的表：{}", identifiedTables);
            return identifiedTables;
            
        } catch (Exception e) {
            log.error("AI表识别失败", e);
            return new ArrayList<>();
        }
    }
    
    /**
     * 从数据库中获取所有可用的表信息
     */
    private Map<String, String> getAvailableTablesFromDatabase() {
        try {
            String sql = "select table_name, table_comment from information_schema.tables " +
                        "where table_schema = (select database()) " +
                        "AND table_name NOT LIKE 'ACT_%' " +
                        "AND table_name NOT LIKE 'xxl_job_%' " +
                        "AND table_name NOT LIKE 'FLW_%' " +
                        "AND table_name NOT LIKE 'gen_%' " +
                        "order by table_name";
            
            List<Map<String, Object>> results = databaseQueryService.executeQuery(sql);
            Map<String, String> tableDescriptions = new HashMap<>();
            
            for (Map<String, Object> row : results) {
                String tableName = (String) row.get("table_name");
                String tableComment = (String) row.get("table_comment");
                
                if (tableName != null) {
                    // 如果表注释为空，使用枚举中的描述作为备选
                    String description = (tableComment != null && !tableComment.trim().isEmpty()) 
                        ? tableComment 
                        : TableMappingEnum.getDescriptionByTableName(tableName);
                    
                    // 如果枚举中也没有描述，使用表名作为描述
                    if (description == null || description.trim().isEmpty()) {
                        description = tableName;
                    }
                    
                    tableDescriptions.put(tableName, description);
                }
            }
            
            log.info("从数据库获取到 {} 个表", tableDescriptions.size());
            return tableDescriptions;
            
        } catch (Exception e) {
            log.error("从数据库获取表信息失败", e);
            // 如果数据库查询失败，回退到枚举中的表
            return TableMappingEnum.getAllTableDescriptions();
        }
    }
    
    /**
     * 从AI响应中解析表名
     */
    private List<String> parseTableNamesFromAiResponse(String aiResponse, Set<String> validTableNames) {
        List<String> identifiedTables = new ArrayList<>();
        
        if (aiResponse == null || aiResponse.trim().isEmpty()) {
            return identifiedTables;
        }
        
        // 清理AI响应
        String cleanedResponse = aiResponse.trim();
        
        // 如果响应包含```标记，提取其中的内容
        if (cleanedResponse.contains("```")) {
            int start = cleanedResponse.indexOf("```") + 3;
            int end = cleanedResponse.indexOf("```", start);
            if (end > start) {
                cleanedResponse = cleanedResponse.substring(start, end).trim();
            }
        }
        
        // 按逗号、分号、换行符分割
        String[] tableNames = cleanedResponse.split("[,，;；\\n\\r]+");
        
        for (String tableName : tableNames) {
            String trimmedName = tableName.trim();
            // 移除可能的括号内容
            if (trimmedName.contains("(")) {
                trimmedName = trimmedName.substring(0, trimmedName.indexOf("(")).trim();
            }
            
            // 验证表名是否有效
            if (validTableNames.contains(trimmedName)) {
                identifiedTables.add(trimmedName);
            }
        }
        
        return identifiedTables;
    }

    /**
     * 从AI响应中提取SQL语句
     */
    private String extractSqlFromAiResponse(String aiResponse) {
        if (aiResponse == null || aiResponse.trim().isEmpty()) {
            throw new RuntimeException("AI未返回有效的SQL语句");
        }
        
        log.info("AI原始响应: {}", aiResponse);
        
        // 清理AI响应，提取SQL语句
        String cleanedResponse = aiResponse.trim();
        
        // 如果响应包含```sql和```标记，提取其中的内容
        if (cleanedResponse.contains("```sql")) {
            int start = cleanedResponse.indexOf("```sql") + 6;
            int end = cleanedResponse.indexOf("```", start);
            if (end > start) {
                cleanedResponse = cleanedResponse.substring(start, end).trim();
            }
        } else if (cleanedResponse.contains("```")) {
            int start = cleanedResponse.indexOf("```") + 3;
            int end = cleanedResponse.indexOf("```", start);
            if (end > start) {
                cleanedResponse = cleanedResponse.substring(start, end).trim();
            }
        }
        
        log.info("提取的SQL: {}", cleanedResponse);
        
        // 验证是否为有效的SQL查询语句
        if (!databaseQueryService.isQuerySql(cleanedResponse)) {
            log.error("SQL验证失败: {}", cleanedResponse);
            throw new RuntimeException("AI生成的SQL语句不符合安全要求: " + cleanedResponse);
        }
        
        log.info("SQL验证通过: {}", cleanedResponse);
        return cleanedResponse;
    }
    
    /**
     * 根据数据内容和用户查询智能选择renderType并设置对应的数据格式
     */
    private DynamicDataVo determineRenderType(DynamicDataVo result, String userQuery) {
        // 默认使用table类型
        String renderType = "table";
        
        // 如果用户查询包含特定关键词，选择对应的renderType
        String lowerQuery = userQuery.toLowerCase();
        
        if (lowerQuery.contains("统计") || lowerQuery.contains("图表") || lowerQuery.contains("趋势") || 
            lowerQuery.contains("分析") || lowerQuery.contains("可视化")) {
            renderType = "chart";
        } else if (lowerQuery.contains("文本") || lowerQuery.contains("描述") || lowerQuery.contains("说明")) {
            renderType = "text";
        } else if (lowerQuery.contains("复合") || lowerQuery.contains("多个") || lowerQuery.contains("组合")) {
            renderType = "fix";
        }
        
        // 根据renderType设置对应的数据格式
        if (result.getResponse() instanceof DynamicDataVo.TableData) {
            DynamicDataVo.TableData tableData = (DynamicDataVo.TableData) result.getResponse();
            
            switch (renderType) {
                case "text":
                    // 文本格式：返回字符串
                    if (tableData.getDatasource() == null || tableData.getDatasource().isEmpty()) {
                        result.setResponse("暂无相关数据");
                    } else {
                        // 将表格数据转换为文本描述
                        StringBuilder textResponse = new StringBuilder();
                        textResponse.append("查询结果：\n");
                        textResponse.append("共找到 ").append(tableData.getDatasource().size()).append(" 条记录\n\n");
                        
                        for (int i = 0; i < Math.min(tableData.getDatasource().size(), 5); i++) {
                            Map<String, Object> row = tableData.getDatasource().get(i);
                            textResponse.append("记录 ").append(i + 1).append("：");
                            for (Map.Entry<String, Object> entry : row.entrySet()) {
                                textResponse.append(entry.getKey()).append("=").append(entry.getValue()).append(", ");
                            }
                            textResponse.append("\n");
                        }
                        
                        if (tableData.getDatasource().size() > 5) {
                            textResponse.append("... 还有 ").append(tableData.getDatasource().size() - 5).append(" 条记录");
                        }
                        
                        result.setResponse(textResponse.toString());
                    }
                    break;
                    
                case "chart":
                    // 图表格式：检查是否有数值数据
                    boolean hasNumericData = false;
                    if (tableData.getDatasource().size() > 0) {
                        Map<String, Object> firstRow = tableData.getDatasource().get(0);
                        for (Object value : firstRow.values()) {
                            if (value instanceof Number) {
                                hasNumericData = true;
                                break;
                            }
                        }
                    }
                    
                    if (hasNumericData) {
                        // 转换为图表数据格式
                        DynamicDataVo.ChartData chartData = new DynamicDataVo.ChartData();
                        
                        // 图表配置
                        Map<String, Object> options = new HashMap<>();
                        options.put("title", "数据统计图表");
                        options.put("type", "bar");
                        options.put("xAxis", "类别");
                        options.put("yAxis", "数值");
                        chartData.setOptions(options);
                        chartData.setDataset(tableData.getDatasource());
                        
                        result.setResponse(chartData);
                    } else {
                        // 如果没有数值数据，转为文本格式
                        renderType = "text";
                        result.setResponse("数据不适合图表展示，转为文本格式显示");
                    }
                    break;
                    
                case "fix":
                    // 复合格式：返回数组格式
                    List<Map<String, Object>> fixData = new ArrayList<>();
                    
                    // 添加表格数据
                    Map<String, Object> tableBlock = new HashMap<>();
                    tableBlock.put("meta", result.getMeta());
                    tableBlock.put("response", tableData);
                    tableBlock.put("renderType", "table");
                    fixData.add(tableBlock);
                    
                    // 添加统计信息
                    Map<String, Object> statsBlock = new HashMap<>();
                    Map<String, Object> statsMeta = new HashMap<>();
                    
                    List<Map<String, Object>> statsFields = new ArrayList<>();
                    Map<String, Object> totalField = new HashMap<>();
                    totalField.put("fieldName", "total");
                    totalField.put("label", "总记录数");
                    totalField.put("type", "number");
                    statsFields.add(totalField);
                    
                    Map<String, Object> descField = new HashMap<>();
                    descField.put("fieldName", "description");
                    descField.put("label", "描述");
                    descField.put("type", "string");
                    statsFields.add(descField);
                    
                    statsMeta.put("fields", statsFields);
                    statsBlock.put("meta", statsMeta);
                    
                    Map<String, Object> statsResponse = new HashMap<>();
                    statsResponse.put("total", tableData.getDatasource().size());
                    statsResponse.put("description", "查询结果统计");
                    statsBlock.put("response", statsResponse);
                    statsBlock.put("renderType", "text");
                    fixData.add(statsBlock);
                    
                    result.setResponse(fixData);
                    break;
                    
                case "table":
                default:
                    // 表格格式：保持原有格式
                    // 如果数据为空，转为文本
                    if (tableData.getDatasource() == null || tableData.getDatasource().isEmpty()) {
                        renderType = "text";
                        result.setResponse("暂无相关数据");
                    }
                    break;
            }
        }
        
        result.setRenderType(renderType);
        return result;
    }
} 