package com.lingyue.parse.util;

import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.function.Consumer;

/**
 * 大文件分块处理工具
 * 用于处理大文件，避免内存溢出
 * 
 * @author lingyue
 * @since 2026-01-14
 */
@Slf4j
public class FileChunkProcessor {
    
    /**
     * 默认块大小（字节）
     */
    private static final int DEFAULT_CHUNK_SIZE = 10 * 1024 * 1024; // 10MB
    
    /**
     * 大文件阈值（字节），超过此大小使用分块处理
     */
    private static final long LARGE_FILE_THRESHOLD = 50 * 1024 * 1024; // 50MB
    
    /**
     * 判断文件是否需要分块处理
     * 
     * @param filePath 文件路径
     * @return true表示需要分块处理
     */
    public static boolean needsChunkProcessing(String filePath) {
        File file = new File(filePath);
        return file.exists() && file.length() > LARGE_FILE_THRESHOLD;
    }
    
    /**
     * 分块读取文本文件
     * 
     * @param filePath 文件路径
     * @param chunkProcessor 块处理器
     */
    public static void processTextFileInChunks(String filePath, Consumer<String> chunkProcessor) {
        processTextFileInChunks(filePath, chunkProcessor, DEFAULT_CHUNK_SIZE);
    }
    
    /**
     * 分块读取文本文件
     * 
     * @param filePath 文件路径
     * @param chunkProcessor 块处理器
     * @param chunkSize 块大小（字节）
     */
    public static void processTextFileInChunks(String filePath, Consumer<String> chunkProcessor, int chunkSize) {
        try (BufferedReader reader = Files.newBufferedReader(Path.of(filePath), StandardCharsets.UTF_8)) {
            char[] buffer = new char[chunkSize];
            int charsRead;
            StringBuilder chunk = new StringBuilder();
            
            while ((charsRead = reader.read(buffer, 0, chunkSize)) != -1) {
                chunk.append(buffer, 0, charsRead);
                
                // 如果块达到一定大小，处理它
                if (chunk.length() >= chunkSize) {
                    chunkProcessor.accept(chunk.toString());
                    chunk.setLength(0); // 清空StringBuilder
                }
            }
            
            // 处理剩余的块
            if (chunk.length() > 0) {
                chunkProcessor.accept(chunk.toString());
            }
        } catch (IOException e) {
            log.error("分块读取文件失败: {}", filePath, e);
            throw new RuntimeException("分块读取文件失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 分块写入文本文件
     * 
     * @param filePath 文件路径
     * @param content 内容
     * @param chunkSize 块大小（字节）
     */
    public static void writeTextFileInChunks(String filePath, String content, int chunkSize) {
        try (BufferedWriter writer = Files.newBufferedWriter(Path.of(filePath), StandardCharsets.UTF_8)) {
            int length = content.length();
            int offset = 0;
            
            while (offset < length) {
                int end = Math.min(offset + chunkSize, length);
                String chunk = content.substring(offset, end);
                writer.write(chunk);
                offset = end;
            }
        } catch (IOException e) {
            log.error("分块写入文件失败: {}", filePath, e);
            throw new RuntimeException("分块写入文件失败: " + e.getMessage(), e);
        }
    }
    
    /**
     * 获取文件大小（MB）
     */
    public static double getFileSizeMB(String filePath) {
        File file = new File(filePath);
        if (!file.exists()) {
            return 0;
        }
        return file.length() / (1024.0 * 1024.0);
    }
}
