#ifndef PLANTSUNCAT_ZIP_H
#define PLANTSUNCAT_ZIP_H
#include "Core/Base/global_include.h"
#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <stdexcept>
#include <string>
#include <vector>

class Invalid_Archive_Error final : public std::runtime_error {
public:
    using std::runtime_error::runtime_error;
};

struct Archive_Directory_Layout_Rule {
    std::string directory;
    std::vector<std::string> required_files;
    std::vector<std::string> required_directories;
    std::vector<std::string> optional_files;
    std::vector<std::string> optional_directories;
};

struct Archive_Layout_Rules {
    std::vector<Archive_Directory_Layout_Rule> directories;
    std::size_t max_archive_size = 128 * 1024 * 1024;
    std::size_t max_entry_count = 16 * 1024;
    std::uint64_t max_entry_uncompressed_size = 256ULL * 1024 * 1024;
    std::uint64_t max_total_uncompressed_size = 512ULL * 1024 * 1024;
};

struct Archive_Write_Options {
    std::string format = "zip";
    std::string filter;
    std::string extension = "zip";
};

Psc::expected<void, std::string> validate_archive_layout_from_memory(
    const char* data,
    std::size_t size,
    const Archive_Layout_Rules& rules
);

void unarchive_file(const std::filesystem::path& zipPath, const std::filesystem::path& outDir);
void unarchive_from_memory(const char* data, size_t size, const std::filesystem::path& outDir);
void archive_directory(
    const std::filesystem::path& dirPath,
    const std::filesystem::path& archive_path,
    const Archive_Write_Options& options = {}
);
// std::string zip_directory_to_memory(const std::filesystem::path& dirPath,
//                                            const std::vector<std::filesystem::path>& ignoreDirs);

std::string
archive_directory_to_memory(
    const std::filesystem::path& dirPath,
    const std::vector<std::string>& ignorePatterns,
    const Archive_Write_Options& options = {}
);
#endif
