#include "Web/MapRegistry.h"

#include <algorithm>
#include <cctype>
#include <filesystem>
#include <string>

#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#include <Windows.h>

#include "EmbeddedMaps.h"

// Returns the directory that contains the running exe.
// Used so that maps/ is always resolved relative to the exe, not the CWD.
static std::filesystem::path ExeDir() {
    wchar_t buf[MAX_PATH] = {};
    GetModuleFileNameW(nullptr, buf, MAX_PATH);
    return std::filesystem::path(buf).parent_path();
}

// -------------------------------------------------------------------------
// Static map table
// -------------------------------------------------------------------------

static const MapInfo kMaps[] = {
    { "chernarusplus", "ChernarusPlus", 15360,  0 },
    { "livonia",       "Livonia",       15360,  1 },
    { "namalsk",       "Namalsk",       12800,  2 },
    { "banov",         "Banov",         15360,  3 },
    { "deadfall",      "Deadfall",      10000,  4 },
    { "deerisle",      "Deerisle",      16384,  5 },
    { "esseker",       "Esseker",       12800,  6 },
    { "lux",           "Lux",           15360,  7 },
    { "sakhal",        "Sakhal",        15360,  8 },
    { "takistan",      "Takistan",      12800,  9 },
    { "alteria",       "Alteria",        8192, 10 },
};

static constexpr int kMapCount = static_cast<int>(sizeof(kMaps) / sizeof(kMaps[0]));

// -------------------------------------------------------------------------
// Alias table: normalised-key → canonical id
// -------------------------------------------------------------------------

struct Alias { const char* from; const char* to; };

static const Alias kAliases[] = {
    { "enoch",      "livonia"       },
    { "chernarus",  "chernarusplus" },
};

// -------------------------------------------------------------------------
// Normalise: lowercase, keep only alphanumeric chars.
// -------------------------------------------------------------------------

static std::string Normalise(std::string_view sv) {
    std::string out;
    out.reserve(sv.size());
    for (unsigned char c : sv) {
        if (std::isalnum(c))
            out += static_cast<char>(std::tolower(c));
    }
    return out;
}

// -------------------------------------------------------------------------
// MapRegistry implementation
// -------------------------------------------------------------------------

const MapInfo* MapRegistry::Resolve(std::string_view serverMapName) {
    std::string key = Normalise(serverMapName);
    if (key.empty()) return nullptr;

    // Check alias table first.
    for (const auto& alias : kAliases) {
        if (key == alias.from) {
            key = alias.to;
            break;
        }
    }

    // Exact match against canonical id.
    for (const auto& m : kMaps) {
        if (key == m.id)
            return &m;
    }

    // Partial prefix match (e.g. "chernarusplus_2022" → "chernarusplus").
    for (const auto& m : kMaps) {
        if (key.rfind(m.id, 0) == 0)
            return &m;
    }

    // Partial suffix / contains match (e.g. "dayz_namalsk").
    for (const auto& m : kMaps) {
        if (key.find(m.id) != std::string::npos)
            return &m;
    }

    return nullptr;
}

void MapRegistry::Translate(const MapInfo& m, float worldX, float worldZ,
                             float& outX, float& outY) {
    if (m.id == "livonia") {
        outX = worldX * 1.2f;
        outY = (12800.0f - worldZ) * 1.2f;
    } else {
        outX = worldX;
        outY = static_cast<float>(m.worldSize) - worldZ;
    }
}

bool MapRegistry::HasMapImage(const MapInfo& m) {
    std::filesystem::path p = ExeDir() / "maps" / (m.id + ".png");
    if (std::filesystem::exists(p)) return true;
    auto [ptr, sz] = GetEmbeddedMap(m.id);
    return ptr != nullptr;
}

const MapInfo* MapRegistry::AllMaps(int& count) {
    count = kMapCount;
    return kMaps;
}
