package com.lingyue.extract.service;

import com.lingyue.extract.dto.request.AddSourceDocumentRequest;
import com.lingyue.extract.dto.request.BatchAddSourceDocumentsRequest;
import com.lingyue.extract.dto.request.ReorderSourceDocumentsRequest;
import com.lingyue.extract.dto.request.UpdateSourceDocumentRequest;
import com.lingyue.extract.dto.response.SourceDocumentResponse;
import com.lingyue.extract.entity.SourceDocument;
import com.lingyue.extract.repository.ExtractRuleRepository;
import com.lingyue.extract.repository.SourceDocumentRepository;
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;

/**
 * 来源文档服务
 * 
 * @author lingyue
 * @since 2026-01-22
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class SourceDocumentService {
    
    private final SourceDocumentRepository sourceDocumentRepository;
    private final ExtractRuleRepository extractRuleRepository;
    
    /**
     * 添加来源文档
     */
    @Transactional
    public SourceDocument add(String projectId, AddSourceDocumentRequest request) {
        SourceDocument doc = new SourceDocument();
        doc.setId(UUID.randomUUID().toString());
        doc.setProjectId(projectId);
        doc.setDocumentId(request.getDocumentId());
        doc.setAlias(request.getAlias());
        doc.setDocType(request.getDocType());
        doc.setMetadata(request.getMetadata());
        doc.setCreateTime(new Date());
        
        // 设置顺序
        if (request.getDisplayOrder() != null) {
            doc.setDisplayOrder(request.getDisplayOrder());
        } else {
            // 追加到最后
            int maxOrder = sourceDocumentRepository.getMaxDisplayOrder(projectId);
            doc.setDisplayOrder(maxOrder + 1);
        }
        
        sourceDocumentRepository.insert(doc);
        log.info("添加来源文档成功: projectId={}, sourceDocId={}, documentId={}", 
                 projectId, doc.getId(), doc.getDocumentId());
        return doc;
    }
    
    /**
     * 批量添加来源文档
     */
    @Transactional
    public List<SourceDocument> batchAdd(String projectId, BatchAddSourceDocumentsRequest request) {
        int maxOrder = sourceDocumentRepository.getMaxDisplayOrder(projectId);
        List<SourceDocument> docs = new ArrayList<>();
        
        for (int i = 0; i < request.getDocuments().size(); i++) {
            AddSourceDocumentRequest docRequest = request.getDocuments().get(i);
            
            SourceDocument doc = new SourceDocument();
            doc.setId(UUID.randomUUID().toString());
            doc.setProjectId(projectId);
            doc.setDocumentId(docRequest.getDocumentId());
            doc.setAlias(docRequest.getAlias());
            doc.setDocType(docRequest.getDocType());
            doc.setMetadata(docRequest.getMetadata());
            doc.setCreateTime(new Date());
            
            if (docRequest.getDisplayOrder() != null) {
                doc.setDisplayOrder(docRequest.getDisplayOrder());
            } else {
                doc.setDisplayOrder(maxOrder + i + 1);
            }
            
            sourceDocumentRepository.insert(doc);
            docs.add(doc);
        }
        
        log.info("批量添加来源文档成功: projectId={}, count={}", projectId, docs.size());
        return docs;
    }
    
    /**
     * 获取来源文档详情
     */
    public SourceDocument getById(String id) {
        return sourceDocumentRepository.selectById(id);
    }
    
    /**
     * 获取来源文档详情响应
     */
    public SourceDocumentResponse getSourceDocumentResponse(String id) {
        SourceDocument doc = sourceDocumentRepository.selectById(id);
        if (doc == null) {
            return null;
        }
        return SourceDocumentResponse.fromEntity(doc);
    }
    
    /**
     * 获取项目的来源文档列表
     */
    public List<SourceDocumentResponse> listByProjectId(String projectId) {
        List<SourceDocument> docs = sourceDocumentRepository.findByProjectId(projectId);
        return docs.stream()
                .map(SourceDocumentResponse::fromEntity)
                .collect(Collectors.toList());
    }
    
    /**
     * 根据 Document ID 查询来源文档
     */
    public List<SourceDocument> findByDocumentId(String documentId) {
        return sourceDocumentRepository.findByDocumentId(documentId);
    }
    
    /**
     * 根据项目ID和别名查询
     */
    public SourceDocument findByProjectIdAndAlias(String projectId, String alias) {
        return sourceDocumentRepository.findByProjectIdAndAlias(projectId, alias);
    }
    
    /**
     * 更新来源文档
     */
    @Transactional
    public SourceDocument update(String id, UpdateSourceDocumentRequest request) {
        SourceDocument doc = sourceDocumentRepository.selectById(id);
        if (doc == null) {
            return null;
        }
        
        if (request.getAlias() != null) {
            doc.setAlias(request.getAlias());
        }
        if (request.getDocType() != null) {
            doc.setDocType(request.getDocType());
        }
        if (request.getDisplayOrder() != null) {
            doc.setDisplayOrder(request.getDisplayOrder());
        }
        if (request.getMetadata() != null) {
            doc.setMetadata(request.getMetadata());
        }
        
        sourceDocumentRepository.updateById(doc);
        log.info("更新来源文档成功: sourceDocId={}", id);
        return doc;
    }
    
    /**
     * 移除来源文档
     */
    @Transactional
    public boolean remove(String id) {
        SourceDocument doc = sourceDocumentRepository.selectById(id);
        if (doc == null) {
            return false;
        }
        
        // 检查是否有关联的规则
        int ruleCount = extractRuleRepository.findBySourceDocId(id).size();
        if (ruleCount > 0) {
            log.warn("来源文档存在关联规则，无法删除: sourceDocId={}, ruleCount={}", id, ruleCount);
            throw new IllegalStateException("来源文档存在关联规则，请先删除相关规则");
        }
        
        sourceDocumentRepository.deleteById(id);
        log.info("移除来源文档成功: sourceDocId={}", id);
        return true;
    }
    
    /**
     * 强制移除来源文档（同时删除关联规则）
     */
    @Transactional
    public boolean forceRemove(String id) {
        SourceDocument doc = sourceDocumentRepository.selectById(id);
        if (doc == null) {
            return false;
        }
        
        // 删除关联的规则
        var rules = extractRuleRepository.findBySourceDocId(id);
        for (var rule : rules) {
            extractRuleRepository.deleteById(rule.getId());
        }
        
        sourceDocumentRepository.deleteById(id);
        log.info("强制移除来源文档成功: sourceDocId={}, 删除规则={}", id, rules.size());
        return true;
    }
    
    /**
     * 调整文档顺序
     */
    @Transactional
    public void reorder(String projectId, ReorderSourceDocumentsRequest request) {
        List<String> orderedIds = request.getOrderedIds();
        
        for (int i = 0; i < orderedIds.size(); i++) {
            String docId = orderedIds.get(i);
            SourceDocument doc = sourceDocumentRepository.selectById(docId);
            if (doc != null && doc.getProjectId().equals(projectId)) {
                doc.setDisplayOrder(i + 1);
                sourceDocumentRepository.updateById(doc);
            }
        }
        
        log.info("调整来源文档顺序成功: projectId={}, count={}", projectId, orderedIds.size());
    }
    
    /**
     * 统计项目来源文档数量
     */
    public int countByProjectId(String projectId) {
        return sourceDocumentRepository.countByProjectId(projectId);
    }
    
    /**
     * 更新来源文档的解析状态（从 metadata 中）
     */
    @Transactional
    public void updateParseStatus(String sourceDocId, String parseStatus) {
        SourceDocument doc = sourceDocumentRepository.selectById(sourceDocId);
        if (doc == null) {
            return;
        }
        
        Map<String, Object> metadata = doc.getMetadata();
        if (metadata == null) {
            metadata = new HashMap<>();
        }
        metadata.put("parseStatus", parseStatus);
        doc.setMetadata(metadata);
        
        sourceDocumentRepository.updateById(doc);
        log.debug("更新来源文档解析状态: sourceDocId={}, parseStatus={}", sourceDocId, parseStatus);
    }
}
