package com.aps.service;

import com.aps.macroplanner.output.dto.OptimizationResult;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.zip.GZIPInputStream;

/**
 * MP排产结果读取服务。
 *
 * <p>从结果文件反序列化 {@link OptimizationResult}，供前端接口使用。
 * 逻辑与 {@code ResultWriter.getResultFromFile} 一致，但独立于求解器运行时依赖。</p>
 */
@Service
@Slf4j
public class MacroPlannerResultService {

    private static final String OUTPUT_DIR = "mp/result";
    private static final String RESULT_FILE_PREFIX = "optimization_result_";
    private static final String JSON_EXT = ".json";
    private static final String GZ_EXT = ".json.gz";

    private final ObjectMapper objectMapper;

    public MacroPlannerResultService() {
        this.objectMapper = new ObjectMapper();
        this.objectMapper.registerModule(new JavaTimeModule());
        this.objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
    }

    /**
     * 根据场景ID读取MP排产结果。
     *
     * @param sceneId 场景ID
     * @return 反序列化后的优化结果, 或 null (文件不存在/读取失败)
     */
    public OptimizationResult getResult(String sceneId) {
        if (sceneId == null || sceneId.isEmpty()) {
            log.warn("sceneId为空, 无法读取结果");
            return null;
        }

        File file = getOptimizationFile(sceneId);
        if (file == null || !file.exists() || file.length() == 0) {
            log.warn("结果文件不存在或为空: sceneId={}", sceneId);
            return null;
        }

        long start = System.currentTimeMillis();
        OptimizationResult result = deserialize(file);
        long elapsed = System.currentTimeMillis() - start;

        if (result != null) {
            log.info("读取MP结果成功: sceneId={}, 耗时={}ms, 文件大小={}KB",
                    sceneId, elapsed, file.length() / 1024);
        }
        return result;
    }

    /**
     * 定位结果文件, 优先 .json, 其次 .json.gz。
     */
    private File getOptimizationFile(String sceneId) {
        String workDir = System.getProperty("user.dir");
        Path resultDir = Paths.get(workDir, OUTPUT_DIR);

        // 优先未压缩
        File jsonFile = resultDir.resolve(RESULT_FILE_PREFIX + sceneId + JSON_EXT).toFile();
        if (jsonFile.exists() && jsonFile.length() > 0) {
            return jsonFile;
        }

        // 其次压缩
        File gzFile = resultDir.resolve(RESULT_FILE_PREFIX + sceneId + GZ_EXT).toFile();
        if (gzFile.exists() && gzFile.length() > 0) {
            return gzFile;
        }

        return jsonFile; // 返回 .json 路径用于日志提示
    }

    /**
     * 反序列化, 自动处理 GZIP 压缩。
     */
    private OptimizationResult deserialize(File file) {
        try (InputStream is = openInputStream(file)) {
            return objectMapper.readValue(is, OptimizationResult.class);
        } catch (IOException e) {
            log.error("反序列化结果失败: file={}, error={}", file.getAbsolutePath(), e.getMessage(), e);
            return null;
        }
    }

    /**
     * 根据文件扩展名决定是否包裹 GZIP 输入流。
     */
    private InputStream openInputStream(File file) throws IOException {
        FileInputStream fis = new FileInputStream(file);
        if (file.getName().endsWith(".gz")) {
            return new GZIPInputStream(fis);
        }
        return fis;
    }
}
