package org.limine.snapper.processes;

import org.limine.snapper.formats.json1.ImageDetail;
import org.limine.snapper.formats.json1.Manifest;
import org.limine.snapper.formats.json1.SnapshotEntry;
import org.limine.snapper.objects.Config;
import tools.jackson.databind.json.JsonMapper;

import java.io.File;
import java.util.HashSet;
import java.util.List;

public class HistoryWriter {

    /**
     * Save manifest.
     */
    public static void save(Manifest manifest, String filePath) {
        updateDetail(manifest);
        Utility.ensurePathExists(filePath);
        JsonMapper jsonMapper = new JsonMapper();
        jsonMapper.writerWithDefaultPrettyPrinter().writeValue(new File(filePath), manifest);
        Utility.infoMessage("Saved:", filePath);
    }

    public static void backup(String manifestPath) {
        if (Utility.isFilePresent(manifestPath)) {
            // Auto time-based backup. Check if an older backup exists.
            String backupPath = manifestPath + Config.BACKUP_SUFFIX;
            boolean isBackupNeeded = true;
            if (Utility.isFilePresent(backupPath)) {
                isBackupNeeded = Utility.isFileOlderThan(backupPath, Config.CONFIG_BACKUP_THRESHOLD);
            }
            if (isBackupNeeded) {
                Utility.copyFile(manifestPath, backupPath, true, false, false);
            }
        }
    }

    private static void updateDetail(Manifest manifest) {
        if (!Config.MANIFEST_VERSION.equals(manifest.getVersion())) {
            manifest.setVersion(Config.MANIFEST_VERSION);
        }
        if (Config.FS_UUID != null && !Config.FS_UUID.equals(manifest.getUuid())) {
            // UUID is changed based on the user-defined config.
            manifest.setUuid(Config.FS_UUID);
            return;
        }
        if (Config.IS_TIME_FOR_RESTORE) {
            return;
        }
        if (manifest.getUuid() == null || manifest.getUuid().isEmpty()) {
            manifest.setUuid(Utility.getUuid());
        }
    }

    public static boolean cleanupUnusedFiles(Manifest manifest, Config config) {
        boolean unusedFilesFound = false;
        HashSet<String> neededFiles = new HashSet<>();
        for (SnapshotEntry entry : manifest.getSnapshotEntries()) {
            for (ImageDetail image : entry.allImages()) {
                neededFiles.add(image.fileHashName());
            }
        }
        String dirPath = Utility.buildPath(config.espPath(), config.machineID(), Config.HISTORY_FOLDER);
        List<String> directory = Utility.collectFilesFromDirectory(dirPath);
        for (String fileName : directory) {
            if ((Config.MANIFEST_FILE + Config.BACKUP_SUFFIX).startsWith(fileName)) {
                continue;
            }
            // Check if the file is unused
            if (!neededFiles.contains(fileName)) {
                Utility.deleteFile(Utility.buildPath(dirPath, fileName));
                unusedFilesFound = true;
            }
        }
        return unusedFilesFound;
    }
}
