package com.lingyue.parse.service;

import com.lingyue.common.exception.ServiceException;
import com.lingyue.document.entity.Document;
import com.lingyue.document.service.DocumentService;
import com.lingyue.parse.config.FileStorageProperties;
import com.lingyue.parse.dto.FileUploadResponse;
import com.lingyue.parse.enums.FileType;
import com.lingyue.parse.enums.ParseStatus;
import com.lingyue.parse.util.FileTypeDetector;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

/**
 * 文件上传服务
 * 
 * @author lingyue
 * @since 2026-01-14
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FileUploadService {
    
    private final FileStorageProperties fileStorageProperties;
    private final ParseTaskExecutor parseTaskExecutor;
    private final DocumentService documentService;
    
    /**
     * 上传文件
     * 
     * @param file 上传的文件
     * @param userId 用户ID
     * @return 上传响应
     */
    public FileUploadResponse uploadFile(MultipartFile file, String userId) {
        // 1. 验证文件
        validateFile(file);
        
        // 2. 检测文件类型
        FileType fileType = FileTypeDetector.detectFileType(file);
        log.info("检测到文件类型: {}", fileType);
        
        // 3. 生成文档ID
        String documentId = UUID.randomUUID().toString();
        
        // 4. 构建存储路径
        String filePath = buildFilePath(userId, documentId, file.getOriginalFilename());
        
        // 5. 保存文件
        try {
            saveFile(file, filePath);
            log.info("文件保存成功: {}", filePath);
        } catch (IOException e) {
            log.error("文件保存失败", e);
            throw new ServiceException("文件保存失败: " + e.getMessage());
        }

        // 6. 在 documents 表中创建记录（满足外键约束）
        Document document = new Document();
        document.setId(documentId);
        document.setUserId(userId);
        document.setName(file.getOriginalFilename());
        document.setType(mapFileTypeToDocType(fileType));
        document.setStatus("parsing");
        document.setFileSize(file.getSize());
        document.setFileUrl(filePath);
        document.setParseStatus("pending");
        document.setParseProgress(0);
        documentService.saveDocument(document);
        log.info("文档记录创建成功, documentId={}", documentId);

        // 7. 提交解析任务（异步执行）
        parseTaskExecutor.submitParseTask(documentId, filePath, fileType);
        
        // 8. 构建响应
        return FileUploadResponse.builder()
                .documentId(documentId)
                .fileName(file.getOriginalFilename())
                .fileType(fileType.name())
                .fileSize(file.getSize())
                .filePath(filePath)
                .parseStatus(ParseStatus.PENDING.getCode())
                .uploadTime(LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME))
                .build();
    }
    
    /**
     * 将 FileType 转换为文档类型字符串
     */
    private String mapFileTypeToDocType(FileType fileType) {
        switch (fileType) {
            case PDF:
                return "pdf";
            case WORD:
            case WORD_OLD:
                return "word";
            case EXCEL:
            case EXCEL_OLD:
                return "excel";
            case IMAGE_JPG:
            case IMAGE_PNG:
            case IMAGE_GIF:
                return "image";
            default:
                return "other";
        }
    }
    
    /**
     * 验证文件
     */
    private void validateFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new ServiceException("文件不能为空");
        }
        
        String originalFilename = file.getOriginalFilename();
        if (originalFilename == null || originalFilename.isEmpty()) {
            throw new ServiceException("文件名不能为空");
        }
        
        // 验证文件扩展名
        if (!FileTypeDetector.isAllowedExtension(originalFilename, 
                fileStorageProperties.getAllowedExtensions())) {
            throw new ServiceException("不支持的文件类型，允许的类型: " + 
                    fileStorageProperties.getAllowedExtensions());
        }
        
        // 验证文件大小（500MB）
        long maxSize = 500 * 1024 * 1024L;
        if (file.getSize() > maxSize) {
            throw new ServiceException("文件大小超过限制（最大500MB）");
        }
    }
    
    /**
     * 构建文件存储路径
     * 
     * @param userId 用户ID
     * @param documentId 文档ID
     * @param originalFilename 原始文件名
     * @return 文件路径
     */
    private String buildFilePath(String userId, String documentId, String originalFilename) {
        // 获取文件扩展名
        String extension = "";
        if (originalFilename.contains(".")) {
            extension = originalFilename.substring(originalFilename.lastIndexOf("."));
        }
        
        // 构建路径: /data/lingyue/files/{userId}/{documentId}/original{extension}
        return Paths.get(
                fileStorageProperties.getBasePath(),
                userId,
                documentId,
                "original" + extension
        ).toString();
    }
    
    /**
     * 保存文件到磁盘
     */
    private void saveFile(MultipartFile file, String filePath) throws IOException {
        Path path = Paths.get(filePath);
        
        // 创建目录
        Files.createDirectories(path.getParent());
        
        // 保存文件
        file.transferTo(path.toFile());
    }
    
    /**
     * 删除文件
     * 
     * @param filePath 文件路径
     */
    public void deleteFile(String filePath) {
        try {
            File file = new File(filePath);
            if (file.exists()) {
                if (file.delete()) {
                    log.info("文件删除成功: {}", filePath);
                } else {
                    log.warn("文件删除失败: {}", filePath);
                }
            }
        } catch (Exception e) {
            log.error("删除文件异常", e);
        }
    }
    
    /**
     * 检查文件是否存在
     */
    public boolean fileExists(String filePath) {
        return new File(filePath).exists();
    }
}
