package com.lingyue.graph.service;

import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * NER 结果转换为 Block TextElement 的服务
 * 
 * 核心职责：
 * 1. 将 NER 提取的实体（带字符偏移）转换为 TextElement 结构
 * 2. 将纯文本拆分为 text_run 和 entity 元素的混合列表
 * 
 * @author lingyue
 * @since 2026-01-21
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class NerToBlockService {
    
    /**
     * 将纯文本和 NER 实体转换为 TextElement 列表
     * 
     * @param text 纯文本内容
     * @param entities NER 提取的实体列表，每个实体需包含 name, type, charStart, charEnd
     * @return TextElement 列表
     */
    public List<TextElementDTO> convertToTextElements(String text, List<Map<String, Object>> entities) {
        if (text == null || text.isEmpty()) {
            return Collections.emptyList();
        }
        
        if (entities == null || entities.isEmpty()) {
            // 无实体，整个文本作为一个 text_run
            TextElementDTO element = new TextElementDTO();
            element.setType("text_run");
            element.setContent(text);
            return Collections.singletonList(element);
        }
        
        // 1. 提取并排序实体位置
        List<EntityPosition> positions = extractEntityPositions(text, entities);
        
        // 2. 根据实体位置拆分文本
        return splitTextByEntities(text, positions);
    }
    
    /**
     * 将文档级别的 NER 结果分配到各个 Block
     * 
     * @param blocks 文档的所有块（需包含 charStart, charEnd, text）
     * @param entities 文档级别的 NER 实体（globalCharStart, globalCharEnd）
     * @return 每个 blockId 对应的 TextElement 列表
     */
    public Map<String, List<TextElementDTO>> distributeEntitiesToBlocks(
            List<BlockInfo> blocks, List<Map<String, Object>> entities) {
        
        Map<String, List<TextElementDTO>> result = new LinkedHashMap<>();
        
        if (blocks == null || blocks.isEmpty()) {
            return result;
        }
        
        // 按 charStart 排序块
        List<BlockInfo> sortedBlocks = blocks.stream()
                .sorted(Comparator.comparingInt(BlockInfo::getCharStart))
                .collect(Collectors.toList());
        
        // 为每个块分配实体
        for (BlockInfo block : sortedBlocks) {
            // 找出落在该块范围内的实体
            List<Map<String, Object>> blockEntities = filterEntitiesForBlock(
                    entities, block.getCharStart(), block.getCharEnd());
            
            // 将全局偏移转换为块内偏移
            List<Map<String, Object>> localizedEntities = localizeEntityPositions(
                    blockEntities, block.getCharStart());
            
            // 转换为 TextElement
            List<TextElementDTO> elements = convertToTextElements(block.getText(), localizedEntities);
            
            result.put(block.getBlockId(), elements);
        }
        
        return result;
    }
    
    /**
     * 将单个段落文本和实体转换为 TextElement（简化版，用于单块处理）
     */
    public List<TextElementDTO> convertParagraphToElements(String paragraphText, 
                                                            List<Map<String, Object>> entities) {
        return convertToTextElements(paragraphText, entities);
    }
    
    // ==================== 内部方法 ====================
    
    /**
     * 从实体列表中提取位置信息
     */
    private List<EntityPosition> extractEntityPositions(String text, List<Map<String, Object>> entities) {
        List<EntityPosition> positions = new ArrayList<>();
        
        for (Map<String, Object> entity : entities) {
            EntityPosition pos = new EntityPosition();
            
            // 获取实体基本信息
            pos.setName(getStringValue(entity, "name"));
            pos.setType(getStringValue(entity, "type", "ENTITY"));
            pos.setEntityId(getStringValue(entity, "tempId", UUID.randomUUID().toString().replace("-", "")));
            
            // 获取位置信息
            Object positionObj = entity.get("position");
            if (positionObj instanceof Map) {
                @SuppressWarnings("unchecked")
                Map<String, Object> posMap = (Map<String, Object>) positionObj;
                pos.setCharStart(getIntValue(posMap, "charStart", -1));
                pos.setCharEnd(getIntValue(posMap, "charEnd", -1));
            } else {
                // 直接从实体中获取
                pos.setCharStart(getIntValue(entity, "charStart", -1));
                pos.setCharEnd(getIntValue(entity, "charEnd", -1));
            }
            
            // 验证位置有效性
            if (pos.getCharStart() >= 0 && pos.getCharEnd() > pos.getCharStart() 
                    && pos.getCharEnd() <= text.length()) {
                
                // 验证实体名称与文本位置是否匹配
                String textAtPosition = text.substring(pos.getCharStart(), pos.getCharEnd());
                if (pos.getName() != null && pos.getName().equals(textAtPosition)) {
                    positions.add(pos);
                } else {
                    // 位置不匹配，尝试通过名称查找
                    // 注意：indexOf 只返回第一个匹配位置，对于重复出现的实体可能不准确
                    // 理想情况下 NER 服务应该提供准确的位置信息
                    int foundIndex = text.indexOf(pos.getName());
                    if (foundIndex >= 0) {
                        pos.setCharStart(foundIndex);
                        pos.setCharEnd(foundIndex + pos.getName().length());
                        positions.add(pos);
                        log.debug("实体位置校正: name={}, newStart={}（注意：仅匹配首次出现）", pos.getName(), foundIndex);
                    } else {
                        log.warn("实体位置无效且无法查找: name={}, charStart={}, charEnd={}", 
                                pos.getName(), pos.getCharStart(), pos.getCharEnd());
                    }
                }
            } else if (pos.getName() != null) {
                // 没有有效位置，尝试通过名称查找
                int foundIndex = text.indexOf(pos.getName());
                if (foundIndex >= 0) {
                    pos.setCharStart(foundIndex);
                    pos.setCharEnd(foundIndex + pos.getName().length());
                    positions.add(pos);
                }
            }
        }
        
        // 按位置排序
        positions.sort(Comparator.comparingInt(EntityPosition::getCharStart));
        
        // 去重和处理重叠
        return removeOverlappingEntities(positions);
    }
    
    /**
     * 移除重叠的实体（保留较长的）
     */
    private List<EntityPosition> removeOverlappingEntities(List<EntityPosition> positions) {
        if (positions.size() <= 1) {
            return positions;
        }
        
        List<EntityPosition> result = new ArrayList<>();
        EntityPosition prev = null;
        
        for (EntityPosition curr : positions) {
            if (prev == null) {
                prev = curr;
            } else if (curr.getCharStart() >= prev.getCharEnd()) {
                // 不重叠
                result.add(prev);
                prev = curr;
            } else {
                // 重叠，保留较长的
                if (curr.getCharEnd() - curr.getCharStart() > prev.getCharEnd() - prev.getCharStart()) {
                    prev = curr;
                }
                // 否则保持 prev
            }
        }
        
        if (prev != null) {
            result.add(prev);
        }
        
        return result;
    }
    
    /**
     * 根据实体位置拆分文本为 TextElement 列表
     */
    private List<TextElementDTO> splitTextByEntities(String text, List<EntityPosition> positions) {
        List<TextElementDTO> elements = new ArrayList<>();
        int currentPos = 0;
        
        for (EntityPosition entityPos : positions) {
            // 实体前的普通文本
            if (entityPos.getCharStart() > currentPos) {
                String beforeText = text.substring(currentPos, entityPos.getCharStart());
                if (!beforeText.isEmpty()) {
                    TextElementDTO textEl = new TextElementDTO();
                    textEl.setType("text_run");
                    textEl.setContent(beforeText);
                    elements.add(textEl);
                }
            }
            
            // 实体元素
            TextElementDTO entityEl = new TextElementDTO();
            entityEl.setType("entity");
            entityEl.setEntityId(entityPos.getEntityId());
            entityEl.setEntityText(text.substring(entityPos.getCharStart(), entityPos.getCharEnd()));
            entityEl.setEntityType(entityPos.getType().toUpperCase());
            entityEl.setConfirmed(false); // NER 自动识别的默认未确认
            elements.add(entityEl);
            
            currentPos = entityPos.getCharEnd();
        }
        
        // 最后剩余的普通文本
        if (currentPos < text.length()) {
            String afterText = text.substring(currentPos);
            if (!afterText.isEmpty()) {
                TextElementDTO textEl = new TextElementDTO();
                textEl.setType("text_run");
                textEl.setContent(afterText);
                elements.add(textEl);
            }
        }
        
        return elements;
    }
    
    /**
     * 筛选落在指定块范围内的实体
     */
    private List<Map<String, Object>> filterEntitiesForBlock(List<Map<String, Object>> entities,
                                                               int blockStart, int blockEnd) {
        if (entities == null) {
            return Collections.emptyList();
        }
        
        return entities.stream()
                .filter(entity -> {
                    int charStart = getEntityCharStart(entity);
                    int charEnd = getEntityCharEnd(entity);
                    // 实体完全在块范围内
                    return charStart >= blockStart && charEnd <= blockEnd;
                })
                .collect(Collectors.toList());
    }
    
    /**
     * 将实体的全局偏移转换为块内偏移
     */
    private List<Map<String, Object>> localizeEntityPositions(List<Map<String, Object>> entities, 
                                                                int blockStart) {
        return entities.stream()
                .map(entity -> {
                    Map<String, Object> localized = new HashMap<>(entity);
                    
                    // 调整位置
                    Object positionObj = entity.get("position");
                    if (positionObj instanceof Map) {
                        @SuppressWarnings("unchecked")
                        Map<String, Object> posMap = new HashMap<>((Map<String, Object>) positionObj);
                        int charStart = getIntValue(posMap, "charStart", 0);
                        int charEnd = getIntValue(posMap, "charEnd", 0);
                        posMap.put("charStart", charStart - blockStart);
                        posMap.put("charEnd", charEnd - blockStart);
                        localized.put("position", posMap);
                    } else {
                        int charStart = getIntValue(entity, "charStart", 0);
                        int charEnd = getIntValue(entity, "charEnd", 0);
                        localized.put("charStart", charStart - blockStart);
                        localized.put("charEnd", charEnd - blockStart);
                    }
                    
                    return localized;
                })
                .collect(Collectors.toList());
    }
    
    private int getEntityCharStart(Map<String, Object> entity) {
        Object positionObj = entity.get("position");
        if (positionObj instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> posMap = (Map<String, Object>) positionObj;
            return getIntValue(posMap, "charStart", -1);
        }
        return getIntValue(entity, "charStart", -1);
    }
    
    private int getEntityCharEnd(Map<String, Object> entity) {
        Object positionObj = entity.get("position");
        if (positionObj instanceof Map) {
            @SuppressWarnings("unchecked")
            Map<String, Object> posMap = (Map<String, Object>) positionObj;
            return getIntValue(posMap, "charEnd", -1);
        }
        return getIntValue(entity, "charEnd", -1);
    }
    
    // ==================== 工具方法 ====================
    
    private String getStringValue(Map<String, Object> map, String key) {
        return getStringValue(map, key, null);
    }
    
    private String getStringValue(Map<String, Object> map, String key, String defaultValue) {
        Object value = map.get(key);
        return value != null ? value.toString() : defaultValue;
    }
    
    private int getIntValue(Map<String, Object> map, String key, int defaultValue) {
        Object value = map.get(key);
        if (value instanceof Number) {
            return ((Number) value).intValue();
        }
        if (value instanceof String) {
            try {
                return Integer.parseInt((String) value);
            } catch (NumberFormatException e) {
                return defaultValue;
            }
        }
        return defaultValue;
    }
    
    // ==================== 数据传输对象 ====================
    
    /**
     * TextElement DTO（与 DocumentBlock.TextElement 对应）
     */
    @Data
    public static class TextElementDTO {
        private String type;  // text_run / entity / link / mention_doc
        
        // text_run
        private String content;
        
        // entity
        private String entityId;
        private String entityText;
        private String entityType;
        private Boolean confirmed;
        
        // link
        private String url;
        
        // mention_doc
        private String refDocId;
        private String refDocTitle;
    }
    
    /**
     * 块信息（用于分配实体）
     */
    @Data
    public static class BlockInfo {
        private String blockId;
        private int charStart;
        private int charEnd;
        private String text;
    }
    
    /**
     * 实体位置（内部使用）
     */
    @Data
    private static class EntityPosition {
        private String entityId;
        private String name;
        private String type;
        private int charStart;
        private int charEnd;
    }
}
