package com.aps.service.plan;

import com.aps.common.util.redis.RedisUtils;
import com.aps.entity.Algorithm.Chromosome;
import com.aps.entity.Schedule.SceneChromsome;
import com.aps.entity.Schedule.SceneDetail;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * 场景结果文件读写服务
 */
@Service
public class SceneService {

    private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(SceneService.class);

    /**
     * 是否使用 GZIP 压缩，默认 true
     */
    private boolean useCompression = false;

    public void setUseCompression(boolean useCompression) {
        this.useCompression = useCompression;
    }

    @Autowired
    private RedisUtils redisUtils;

    private final ObjectMapper objectMapper = createObjectMapper();
    private final Map<String, Object> sceneLocks = new ConcurrentHashMap<>();

    private ObjectMapper createObjectMapper() {
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.disable(SerializationFeature.INDENT_OUTPUT);
        objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        return objectMapper;
    }

    private File getResultDirectory() {
        File resultDir = new File("result");
        if (!resultDir.exists()) {
            boolean created = resultDir.mkdirs();
            if (!created) {
                logger.warn("无法创建结果目录: {}", resultDir.getAbsolutePath());
                throw new RuntimeException("无法创建结果目录: " + resultDir.getAbsolutePath());
            }
        }
        return resultDir;
    }

    private String getFileExtension() {
        return useCompression ? ".json.gz" : ".json";
    }

    private File getChromosomeFile(String sceneId) {
        File resultDir = getResultDirectory();
        String fileName = "chromosome_result_" + sceneId + getFileExtension();
        return new File(resultDir, fileName);
    }

    private File getChromosomeFile(String sceneId, String version) {
        File resultDir = getResultDirectory();
        String fileName = "chromosome_result_" + sceneId + "_" + version + "_" + getFileExtension();
        return new File(resultDir, fileName);
    }

    public File getCurrentChromosomeFile(String sceneId) {
        SceneChromsome sceneChromsome = (SceneChromsome) redisUtils.get("SceneId." + sceneId);
        if (sceneChromsome == null) {
            return getChromosomeFile(sceneId);
        }
        return getChromosomeFile(sceneId, sceneChromsome.getVersion().toString());
    }

    /**
     * 从文件中读取 Chromosome 对象，并拆分文件读取与反序列化耗时。
     */
    public Chromosome loadChromosomeFromFile(String sceneId) {
        if (sceneId == null || sceneId.trim().isEmpty()) {
            logger.warn("场景ID不能为空");
            return null;
        }

        try {
            long totalStart = System.nanoTime();
            File file = getCurrentChromosomeFile(sceneId);

            if (!file.exists()) {
                logger.warn("染色体文件不存在: {}", file.getAbsolutePath());
                return null;
            }

            long fileSize = file.length();
            if (fileSize == 0) {
                logger.warn("染色体文件为空: {}", file.getAbsolutePath());
                return null;
            }

            logger.info("正在从文件加载染色体: {}, sceneId={}, fileSize={} bytes",
                    file.getAbsolutePath(), sceneId, fileSize);

            long deserializeStart = System.nanoTime();
            Chromosome chromosome;
            if (useCompression) {
                try (FileInputStream fis = new FileInputStream(file);
                     GZIPInputStream gzis = new GZIPInputStream(fis)) {
                    chromosome = objectMapper.readValue(gzis, Chromosome.class);
                }
            } else {
                try (FileInputStream fis = new FileInputStream(file)) {
                    chromosome = objectMapper.readValue(fis, Chromosome.class);
                }
            }
            long deserializeMs = (System.nanoTime() - deserializeStart) / 1_000_000;
            long totalMs = (System.nanoTime() - totalStart) / 1_000_000;

            logger.info("染色体加载成功，场景ID: {}, fileSize={} bytes, deserialize={} ms, total={} ms",
                    sceneId, fileSize, deserializeMs, totalMs);

            return chromosome;
        } catch (Exception e) {
            logger.error("加载染色体文件失败，场景ID: " + sceneId, e);
            throw new RuntimeException("加载染色体文件失败: " + e.getMessage(), e);
        }
    }

    /**
     * 将染色体结果保存到 JSON 文件
     */
    public boolean saveChromosomeToFile(Chromosome chromosome, String sceneId) {
        if (chromosome == null) {
            logger.warn("染色体对象不能为空");
            return false;
        }

        if (sceneId == null || sceneId.trim().isEmpty()) {
            logger.warn("场景ID不能为空");
            return false;
        }

        Object sceneLock = sceneLocks.computeIfAbsent(sceneId, key -> new Object());
        synchronized (sceneLock) {
            try {
            ObjectMapper objectMapper = createObjectMapper();

            SceneChromsome sceneChromsome = (SceneChromsome) redisUtils.get("SceneId." + sceneId);
            Integer nextVersion;
            List<SceneDetail> retainedDetails = new ArrayList<>();
            if (sceneChromsome == null) {
                sceneChromsome = new SceneChromsome();
                sceneChromsome.setSceneID(sceneId);
                nextVersion = 1;
            } else {
                Integer currentVersion = sceneChromsome.getVersion();
                if (currentVersion == null) {
                    currentVersion = 0;
                }
                nextVersion = currentVersion + 1;
                if (sceneChromsome.getSceneDetails() != null) {
                    Integer finalCurrentVersion = currentVersion;
                    retainedDetails.addAll(sceneChromsome.getSceneDetails().stream()
                            .filter(detail -> detail != null
                                    && detail.getVersion() != null
                                    && detail.getVersion() <= finalCurrentVersion)
                            .collect(Collectors.toList()));
                }
            }

            File file = getChromosomeFile(sceneId, nextVersion.toString());
            File tempFile = new File(file.getParentFile(), file.getName() + ".tmp");

            chromosome.setVersion(nextVersion);
            if (useCompression) {
                try (FileOutputStream fos = new FileOutputStream(tempFile);
                     GZIPOutputStream gzos = new GZIPOutputStream(fos)) {
                    objectMapper.writeValue(gzos, chromosome);
                }
            } else {
                objectMapper.writeValue(tempFile, chromosome);
            }

            if (tempFile.length() == 0) {
                logger.error("写入的临时文件为空: {}", tempFile.getAbsolutePath());
                Files.deleteIfExists(tempFile.toPath());
                return false;
            }

            if (useCompression) {
                try (FileInputStream fis = new FileInputStream(tempFile);
                     GZIPInputStream gzis = new GZIPInputStream(fis)) {
                    Chromosome verifyChromosome = objectMapper.readValue(gzis, Chromosome.class);
                    if (verifyChromosome == null) {
                        throw new IOException("验证读取失败");
                    }
                }
            } else {
                try {
                    Chromosome verifyChromosome = objectMapper.readValue(tempFile, Chromosome.class);
                    if (verifyChromosome == null) {
                        throw new IOException("验证读取失败");
                    }
                } catch (Exception e) {
                    logger.error("验证染色体文件内容失败，文件: {}", tempFile.getAbsolutePath(), e);
                    Files.deleteIfExists(tempFile.toPath());
                    return false;
                }
            }

            if (file.exists()) {
                Files.deleteIfExists(file.toPath());
            }
            Files.move(tempFile.toPath(), file.toPath());

            if (sceneChromsome.getSceneDetails() != null) {
                for (SceneDetail detail : sceneChromsome.getSceneDetails()) {
                    if (detail != null && detail.getVersion() != null && detail.getVersion() > nextVersion) {
                        File futureFile = getChromosomeFile(sceneId, detail.getVersion().toString());
                        Files.deleteIfExists(futureFile.toPath());
                    }
                }
            }

            SceneDetail sceneDetail = new SceneDetail();
            sceneDetail.setVersion(nextVersion);
            retainedDetails.add(sceneDetail);
            sceneChromsome.setVersion(nextVersion);
            sceneChromsome.setSceneDetails(retainedDetails);
            redisUtils.set("SceneId." + sceneId, sceneChromsome);

            logger.info("染色体保存成功，场景ID: {}, 文件: {}", sceneId, file.getAbsolutePath());
            return true;
            } catch (Exception e) {
                logger.error("保存染色体文件失败，场景ID: " + sceneId, e);
                return false;
            }
        }
    }

    public SceneChromsome getSceneChromsome(String sceneId) {
        return (SceneChromsome) redisUtils.get("SceneId." + sceneId);
    }

    public Chromosome moveChromosome(String sceneId, Integer version) {
        SceneChromsome sceneChromsome = (SceneChromsome) redisUtils.get("SceneId." + sceneId);
        if (sceneChromsome == null) {
            return null;
        }

        int previousVersion = sceneChromsome.getVersion() - 1;
        if (previousVersion == 0) {
            throw new RuntimeException("无法撤销，当前已经是第一个版本");
        }

        sceneChromsome.setVersion(previousVersion);
        redisUtils.set("SceneId." + sceneId, sceneChromsome);
        Chromosome chromosome = loadChromosomeFromFile(sceneId);
        if (chromosome == null) {
            sceneChromsome.setVersion(sceneChromsome.getVersion() + 1);
            redisUtils.set("SceneId." + sceneId, sceneChromsome);
            throw new RuntimeException("撤销操作失败，未找到上一个版本");
        }
        return chromosome;
    }

    public Chromosome revertVersion(String sceneId, Integer version) {
        SceneChromsome sceneChromsome = (SceneChromsome) redisUtils.get("SceneId." + sceneId);
        if (sceneChromsome == null) {
            return null;
        }

        Integer currentVersion = sceneChromsome.getVersion();
        sceneChromsome.setVersion(version);
        redisUtils.set("SceneId." + sceneId, sceneChromsome);
        Chromosome chromosome = loadChromosomeFromFile(sceneId);
        if (chromosome == null) {
            sceneChromsome.setVersion(currentVersion);
            redisUtils.set("SceneId." + sceneId, sceneChromsome);
            throw new RuntimeException("恢复版本失败，未找到对应版本");
        }
        return chromosome;
    }

    /**
     * 检查染色体文件是否存在
     */
    public boolean chromosomeFileExists(String sceneId) {
        if (sceneId == null || sceneId.trim().isEmpty()) {
            return false;
        }
        SceneChromsome sceneChromsome = (SceneChromsome) redisUtils.get("SceneId." + sceneId);
        File file;
        if (sceneChromsome == null) {
            file = getChromosomeFile(sceneId);
        } else {
            file = getChromosomeFile(sceneId, sceneChromsome.getVersion().toString());
        }
        return file.exists() && file.length() > 0;
    }

    /**
     * 删除染色体文件
     */
    public boolean deleteChromosomeFile(String sceneId) {
        try {
            SceneChromsome sceneChromsome = (SceneChromsome) redisUtils.get("SceneId." + sceneId);
            File file;
            if (sceneChromsome == null) {
                file = getChromosomeFile(sceneId);
                if (file.exists()) {
                    boolean deleted = Files.deleteIfExists(file.toPath());
                    if (deleted) {
                        logger.info("删除染色体文件成功: {}", file.getAbsolutePath());
                    }
                }
            } else {
                for (SceneDetail detail : sceneChromsome.getSceneDetails()) {
                    file = getChromosomeFile(sceneId, detail.getVersion().toString());
                    if (file.exists()) {
                        boolean deleted = Files.deleteIfExists(file.toPath());
                        if (deleted) {
                            logger.info("删除染色体文件成功: {}", file.getAbsolutePath());
                        }
                    }
                }
            }

            redisUtils.del("SceneId." + sceneId);
            logger.info("删除Redis场景信息成功: {}", "SceneId." + sceneId);

            return true;
        } catch (Exception e) {
            logger.error("删除染色体文件失败，场景ID: " + sceneId, e);
            return false;
        }
    }

    /**
     * 清理历史版本的排产结果文件，只保留当前版本
     */
    public boolean cleanupHistoricalVersions(String sceneId) {
        try {
            if (sceneId == null || sceneId.trim().isEmpty()) {
                logger.warn("场景ID不能为空");
                return false;
            }

            SceneChromsome sceneChromsome = (SceneChromsome) redisUtils.get("SceneId." + sceneId);
            if (sceneChromsome == null) {
                logger.warn("场景信息不存在: {}", sceneId);
                return false;
            }

            Integer currentVersion = sceneChromsome.getVersion();
            logger.info("清理场景 {} 的历史版本排产结果文件，当前版本: {}", sceneId, currentVersion);

            List<SceneDetail> sceneDetails = sceneChromsome.getSceneDetails();
            if (sceneDetails != null && !sceneDetails.isEmpty()) {
                for (SceneDetail detail : sceneDetails) {
                    Integer version = detail.getVersion();
                    if (version < currentVersion) {
                        File file = getChromosomeFile(sceneId, version.toString());
                        if (file.exists()) {
                            boolean deleted = Files.deleteIfExists(file.toPath());
                            if (deleted) {
                                logger.info("删除历史版本排产结果文件成功: {}, 版本: {}", file.getAbsolutePath(), version);
                            }
                        }
                    }
                }
            }

            logger.info("清理场景 {} 的历史版本排产结果文件完成", sceneId);
            return true;
        } catch (Exception e) {
            logger.error("清理历史版本排产结果文件失败，场景ID: " + sceneId, e);
            return false;
        }
    }
}
