#pragma once

#include <godot_cpp/classes/ref_counted.hpp>
#include <godot_cpp/variant/string.hpp>
#include <godot_cpp/variant/packed_string_array.hpp>
#include <godot_cpp/variant/packed_byte_array.hpp>
#include <godot_cpp/variant/dictionary.hpp>

#include <StormLib.h>

#include <vector>
#include <string>

namespace godot {

// ─────────────────────────────────────────────────────────────────────────────
// MPQArchiveEntry – one open archive with its priority
// ─────────────────────────────────────────────────────────────────────────────
struct MPQArchiveEntry {
    HANDLE  handle   = nullptr;
    String  path;
    int     priority = 0;   // higher = wins
};

// ─────────────────────────────────────────────────────────────────────────────
// MPQManager – GDScript-accessible class
// Usage:
//   var mgr = MPQManager.new()
//   mgr.open_client("res://sources", "ruRU")
//   var data = mgr.read_file("Interface\\FrameXML\\GlobalStrings.lua")
//   mgr.extract_all("DBFilesClient", "res://data/extracted/dbc")
//   mgr.close()
// ─────────────────────────────────────────────────────────────────────────────
class MPQManager : public RefCounted {
    GDCLASS(MPQManager, RefCounted)

public:
    MPQManager();
    ~MPQManager();

    // Open all MPQ archives from a WoW 3.3.5a client folder.
    // base_path – folder containing Data/
    // locale    – e.g. "ruRU", "enUS", "deDE"
    // Returns number of successfully opened archives (0 on total failure).
    int open_client(const String &base_path, const String &locale);

    // Open a single MPQ archive explicitly (for custom workflows).
    bool open_archive(const String &path, int priority);

    // Close all open archives.
    void close();

    // Check whether a file exists in any archive.
    bool has_file(const String &internal_path) const;

    // Read a file from the highest-priority archive that contains it.
    PackedByteArray read_file(const String &internal_path) const;

    // Extract a single file to output_path (creates parent dirs).
    bool extract_file(const String &internal_path, const String &output_path) const;

    // Extract all files matching filter (e.g. "DBFilesClient\\*.dbc")
    // into output_dir, preserving sub-paths.
    // Returns number of extracted files.
    int extract_files(const String &filter, const String &output_dir) const;

    // List all files in all archives matching filter. Deduplicates by name,
    // keeping only the entry from the highest-priority archive.
    PackedStringArray list_files(const String &filter = "*") const;

    // Info: how many archives are open
    int get_archive_count() const;

    // Info: array of Dictionaries { "path": ..., "priority": ..., "file_count": ... }
    Array get_archive_info() const;

protected:
    static void _bind_methods();

private:
    std::vector<MPQArchiveEntry> m_archives; // sorted ascending by priority

    // Returns the handle of the highest-priority archive that contains the file.
    // Returns nullptr if not found.
    HANDLE find_file(const std::string &internal_path) const;

    // Helper: std::string → Godot String
    static String to_godot(const std::string &s);
    // Helper: Godot String → std::string (ANSI/UTF8 path)
    static std::string to_std(const String &s);

    // Ensure output directory exists (creates recursively)
    static bool ensure_dir(const std::string &path);

    // WoW 3.3.5a archive load order (lowest→highest priority)
    // locale archives always have higher priority than base archives
    static std::vector<std::pair<std::string,int>> build_archive_list(
        const std::string &data_dir,
        const std::string &locale);
};

} // namespace godot
