package com.lingyue.graph.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.lingyue.document.entity.DocumentElement;
import com.lingyue.document.repository.DocumentElementRepository;
import com.lingyue.graph.dto.*;
import com.lingyue.graph.entity.DataSource;
import com.lingyue.graph.entity.GraphNode;
import com.lingyue.graph.repository.DataSourceRepository;
import com.lingyue.graph.repository.GraphNodeRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

/**
 * 数据源服务
 * 管理数据源的 CRUD 和值获取
 * 
 * @author lingyue
 * @since 2026-01-21
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DataSourceService {
    
    private final DataSourceRepository dataSourceRepository;
    private final GraphNodeRepository graphNodeRepository;
    private final DocumentElementRepository documentElementRepository;
    private final ObjectMapper objectMapper;
    
    // ==================== CRUD 操作 ====================
    
    /**
     * 创建数据源
     */
    @Transactional
    public DataSource create(String userId, CreateDataSourceRequest request) {
        DataSource dataSource = new DataSource();
        dataSource.setUserId(userId);
        dataSource.setName(request.getName());
        dataSource.setType(request.getType());
        dataSource.setDocumentId(request.getDocumentId());
        dataSource.setSourceType(request.getSourceType() != null ? request.getSourceType() : "manual");
        dataSource.setValueType(request.getValueType() != null ? request.getValueType() : "text");
        dataSource.setAggregateType(request.getAggregateType() != null ? request.getAggregateType() : "first");
        dataSource.setSeparator(request.getSeparator() != null ? request.getSeparator() : "");
        dataSource.setNodeIds(request.getNodeIds());
        dataSource.setConfig(request.getConfig());
        dataSource.setMetadata(request.getMetadata());
        
        dataSourceRepository.insert(dataSource);
        log.info("创建数据源: id={}, name={}, type={}", dataSource.getId(), dataSource.getName(), dataSource.getType());
        return dataSource;
    }
    
    /**
     * 获取数据源
     */
    public DataSource getById(String id) {
        return dataSourceRepository.selectById(id);
    }
    
    /**
     * 按文档ID查询
     */
    public List<DataSource> getByDocumentId(String documentId) {
        return dataSourceRepository.findByDocumentId(documentId);
    }
    
    /**
     * 按用户ID查询
     */
    public List<DataSource> getByUserId(String userId) {
        return dataSourceRepository.findByUserId(userId);
    }
    
    /**
     * 按类型查询
     */
    public List<DataSource> getByUserIdAndType(String userId, String type) {
        return dataSourceRepository.findByUserIdAndType(userId, type);
    }
    
    /**
     * 更新数据源
     */
    @Transactional
    public DataSource update(String id, UpdateDataSourceRequest request) {
        DataSource dataSource = dataSourceRepository.selectById(id);
        if (dataSource == null) {
            throw new IllegalArgumentException("数据源不存在: " + id);
        }
        
        if (request.getName() != null) {
            dataSource.setName(request.getName());
        }
        if (request.getType() != null) {
            dataSource.setType(request.getType());
        }
        if (request.getSourceType() != null) {
            dataSource.setSourceType(request.getSourceType());
        }
        if (request.getValueType() != null) {
            dataSource.setValueType(request.getValueType());
        }
        if (request.getAggregateType() != null) {
            dataSource.setAggregateType(request.getAggregateType());
        }
        if (request.getSeparator() != null) {
            dataSource.setSeparator(request.getSeparator());
        }
        if (request.getConfig() != null) {
            dataSource.setConfig(request.getConfig());
        }
        if (request.getMetadata() != null) {
            dataSource.setMetadata(request.getMetadata());
        }
        
        dataSourceRepository.updateById(dataSource);
        log.info("更新数据源: id={}", id);
        return dataSource;
    }
    
    /**
     * 更新节点引用
     */
    @Transactional
    public DataSource updateRefs(String id, UpdateRefsRequest request) {
        DataSource dataSource = dataSourceRepository.selectById(id);
        if (dataSource == null) {
            throw new IllegalArgumentException("数据源不存在: " + id);
        }
        
        NodeRefs currentRefs = parseNodeRefs(dataSource.getNodeIds());
        List<NodeRef> newRefs = request.getRefs() != null ? request.getRefs() : new ArrayList<>();
        
        if (request.isReplace()) {
            // 替换模式
            currentRefs.setRefs(newRefs);
        } else if (request.isAppend()) {
            // 追加模式
            currentRefs.getRefs().addAll(newRefs);
        } else if (request.isRemove()) {
            // 移除模式
            Set<String> idsToRemove = newRefs.stream()
                    .map(NodeRef::getId)
                    .collect(Collectors.toSet());
            currentRefs.setRefs(
                    currentRefs.getRefs().stream()
                            .filter(ref -> !idsToRemove.contains(ref.getId()))
                            .collect(Collectors.toList())
            );
        }
        
        dataSource.setNodeIds(currentRefs);
        dataSourceRepository.updateById(dataSource);
        log.info("更新数据源引用: id={}, mode={}, count={}", id, request.getMode(), currentRefs.size());
        return dataSource;
    }
    
    /**
     * 删除数据源
     */
    @Transactional
    public void delete(String id) {
        dataSourceRepository.deleteById(id);
        log.info("删除数据源: id={}", id);
    }
    
    // ==================== 核心取值逻辑 ====================
    
    /**
     * 获取数据源的值
     * 核心方法：从绑定的节点中提取并聚合值
     */
    public DataSourceValue getValue(String dataSourceId) {
        DataSource dataSource = dataSourceRepository.selectById(dataSourceId);
        if (dataSource == null) {
            throw new IllegalArgumentException("数据源不存在: " + dataSourceId);
        }
        return getValue(dataSource);
    }
    
    /**
     * 获取数据源的值
     */
    public DataSourceValue getValue(DataSource dataSource) {
        NodeRefs refs = parseNodeRefs(dataSource.getNodeIds());
        
        if (refs.isEmpty()) {
            return DataSourceValue.empty(dataSource.getId(), dataSource.getName());
        }
        
        // 获取所有节点值
        List<NodeValueItem> items = fetchNodeValues(refs);
        
        if (items.isEmpty()) {
            return DataSourceValue.empty(dataSource.getId(), dataSource.getName());
        }
        
        // 根据值类型和聚合方式生成返回值
        return aggregateValues(dataSource, items);
    }
    
    /**
     * 批量获取数据源值
     */
    public Map<String, DataSourceValue> batchGetValue(List<String> dataSourceIds) {
        Map<String, DataSourceValue> result = new LinkedHashMap<>();
        
        if (dataSourceIds == null || dataSourceIds.isEmpty()) {
            return result;
        }
        
        // 批量查询数据源
        List<DataSource> dataSources = dataSourceRepository.selectBatchIds(dataSourceIds);
        
        for (DataSource dataSource : dataSources) {
            try {
                DataSourceValue value = getValue(dataSource);
                result.put(dataSource.getId(), value);
            } catch (Exception e) {
                log.error("获取数据源值失败: id={}, error={}", dataSource.getId(), e.getMessage());
                result.put(dataSource.getId(), DataSourceValue.empty(dataSource.getId(), dataSource.getName()));
            }
        }
        
        return result;
    }
    
    // ==================== 私有方法 ====================
    
    /**
     * 解析节点引用
     */
    private NodeRefs parseNodeRefs(Object nodeIds) {
        if (nodeIds == null) {
            return new NodeRefs();
        }
        
        try {
            if (nodeIds instanceof NodeRefs) {
                return (NodeRefs) nodeIds;
            }
            if (nodeIds instanceof Map) {
                return objectMapper.convertValue(nodeIds, NodeRefs.class);
            }
            if (nodeIds instanceof String) {
                return objectMapper.readValue((String) nodeIds, NodeRefs.class);
            }
            return objectMapper.convertValue(nodeIds, NodeRefs.class);
        } catch (Exception e) {
            log.warn("解析节点引用失败: {}", e.getMessage());
            return new NodeRefs();
        }
    }
    
    /**
     * 获取所有节点的值
     */
    private List<NodeValueItem> fetchNodeValues(NodeRefs refs) {
        List<NodeValueItem> items = new ArrayList<>();
        
        // 获取图节点
        List<String> graphNodeIds = refs.getGraphNodeIds();
        if (!graphNodeIds.isEmpty()) {
            List<GraphNode> graphNodes = graphNodeRepository.selectBatchIds(graphNodeIds);
            for (GraphNode node : graphNodes) {
                items.add(createValueItemFromGraphNode(node));
            }
        }
        
        // 获取文档元素
        List<String> elementIds = refs.getDocumentElementIds();
        if (!elementIds.isEmpty()) {
            List<DocumentElement> elements = documentElementRepository.selectBatchIds(elementIds);
            for (DocumentElement element : elements) {
                items.add(createValueItemFromElement(element));
            }
        }
        
        return items;
    }
    
    /**
     * 从图节点创建值项
     */
    private NodeValueItem createValueItemFromGraphNode(GraphNode node) {
        return NodeValueItem.text(
                NodeRef.TYPE_GRAPH_NODE,
                node.getId(),
                node.getValue(),
                node.getName()
        );
    }
    
    /**
     * 从文档元素创建值项
     */
    @SuppressWarnings("unchecked")
    private NodeValueItem createValueItemFromElement(DocumentElement element) {
        String elementType = element.getElementType();
        
        if ("image".equals(elementType)) {
            return NodeValueItem.image(
                    NodeRef.TYPE_DOCUMENT_ELEMENT,
                    element.getId(),
                    element.getImageUrl(),
                    element.getImagePath(),
                    element.getImageAlt()
            );
        } else if ("table".equals(elementType)) {
            return NodeValueItem.table(
                    NodeRef.TYPE_DOCUMENT_ELEMENT,
                    element.getId(),
                    element.getTableData(),
                    "表格 #" + element.getTableIndex()
            );
        } else {
            // 文本类型（paragraph, heading 等）
            return NodeValueItem.text(
                    NodeRef.TYPE_DOCUMENT_ELEMENT,
                    element.getId(),
                    element.getContent(),
                    elementType
            );
        }
    }
    
    /**
     * 聚合值
     */
    @SuppressWarnings("unchecked")
    private DataSourceValue aggregateValues(DataSource dataSource, List<NodeValueItem> items) {
        String valueType = dataSource.getValueType();
        String aggregateType = dataSource.getAggregateType();
        String separator = dataSource.getSeparator() != null ? dataSource.getSeparator() : "";
        
        // 图片类型
        if ("image".equals(valueType)) {
            NodeValueItem firstImage = items.stream()
                    .filter(item -> "image".equals(item.getValueType()))
                    .findFirst()
                    .orElse(null);
            
            if (firstImage != null) {
                return DataSourceValue.image(
                        dataSource.getId(),
                        dataSource.getName(),
                        firstImage.getImageUrl(),
                        firstImage.getImagePath(),
                        items
                );
            }
            return DataSourceValue.empty(dataSource.getId(), dataSource.getName());
        }
        
        // 表格类型
        if ("table".equals(valueType)) {
            NodeValueItem firstTable = items.stream()
                    .filter(item -> "table".equals(item.getValueType()))
                    .findFirst()
                    .orElse(null);
            
            if (firstTable != null) {
                return DataSourceValue.table(
                        dataSource.getId(),
                        dataSource.getName(),
                        firstTable.getTableData(),
                        items
                );
            }
            return DataSourceValue.empty(dataSource.getId(), dataSource.getName());
        }
        
        // 文本类型 - 需要聚合
        List<String> textValues = items.stream()
                .filter(item -> "text".equals(item.getValueType()) && item.getTextValue() != null)
                .map(NodeValueItem::getTextValue)
                .collect(Collectors.toList());
        
        String aggregatedText;
        switch (aggregateType) {
            case "first":
                aggregatedText = textValues.isEmpty() ? "" : textValues.get(0);
                break;
            case "last":
                aggregatedText = textValues.isEmpty() ? "" : textValues.get(textValues.size() - 1);
                break;
            case "concat":
                aggregatedText = String.join(separator, textValues);
                break;
            case "sum":
                aggregatedText = String.valueOf(textValues.stream()
                        .mapToDouble(this::parseDouble)
                        .sum());
                break;
            case "avg":
                aggregatedText = String.valueOf(textValues.stream()
                        .mapToDouble(this::parseDouble)
                        .average()
                        .orElse(0.0));
                break;
            case "list":
            default:
                // list 模式返回所有项
                return DataSourceValue.builder()
                        .dataSourceId(dataSource.getId())
                        .dataSourceName(dataSource.getName())
                        .type(DataSourceValue.TYPE_TEXT)
                        .textValue(String.join(separator.isEmpty() ? "\n" : separator, textValues))
                        .items(items)
                        .nodeCount(items.size())
                        .build();
        }
        
        return DataSourceValue.text(dataSource.getId(), dataSource.getName(), aggregatedText, items);
    }
    
    /**
     * 安全解析数字
     */
    private double parseDouble(String value) {
        try {
            return Double.parseDouble(value.replaceAll("[^0-9.\\-]", ""));
        } catch (Exception e) {
            return 0.0;
        }
    }
}
