// ==========================================================
// mod_colorizer.cpp - Native Item Mod Colorizer & RAM Patcher
// Poe2VisualTool v1.2.0 Pro In-Game HUD Engine
// C++23 Native - Token Highlighting & 1-Frame Panic Restore (<8.33ms)
// ==========================================================

#include "visual/mod_colorizer.hpp"
#include "common/string_utils.hpp"
#include <algorithm>
#include <cstring>
#include <sstream>

namespace visual {

ModColorizer::ModColorizer(IMemoryReader& memory)
    : memory_(memory) {}

ModColorizer::~ModColorizer() {
    if (isPatched_) {
        RestoreColorPatches();
    }
}

ColorRgb ModColorizer::GetCategoryColor(ModCategory category) {
    switch (category) {
        case ModCategory::PhysicalAttack:
            return ColorRgb(255, 77, 77);   // 🔴 Vibrant Red (#FF4D4D)
        case ModCategory::SpellElemental:
            return ColorRgb(77, 166, 255);  // 🔵 Sky Blue (#4DA6FF)
        case ModCategory::DefenseResistSpeed:
            return ColorRgb(80, 227, 194);  // 🟢 Mint Green (#50E3C2)
        case ModCategory::Tier1Rare:
            return ColorRgb(255, 215, 0);   // 🟡 Radiant Gold (#FFD700)
        default:
            return ColorRgb(200, 200, 200); // ⚪ Standard Silver
    }
}

uint32_t ModColorizer::GetCategoryColorHex(ModCategory category) {
    return GetCategoryColor(category).ToHex();
}

const char* ModColorizer::GetCategoryName(ModCategory category) {
    switch (category) {
        case ModCategory::PhysicalAttack:      return "Physical & Attack";
        case ModCategory::SpellElemental:      return "Spell & Elemental";
        case ModCategory::DefenseResistSpeed:  return "Defense, Speed & Resist";
        case ModCategory::Tier1Rare:           return "Tier 1 & High Value";
        default:                               return "Default";
    }
}

ModCategory ModColorizer::ClassifyMod(const std::string& modText) {
    std::string lower = modText;
    std::transform(lower.begin(), lower.end(), lower.begin(), [](unsigned char c) {
        return static_cast<char>(std::tolower(c));
    });

    // 1. Tier 1 / Special value check first
    if (lower.find("(tier 1)") != std::string::npos ||
        lower.find("(tier: 1)") != std::string::npos ||
        lower.find("fractured") != std::string::npos ||
        lower.find("synthesised") != std::string::npos ||
        lower.find("influenced") != std::string::npos) {
        return ModCategory::Tier1Rare;
    }

    // 2. Physical & Attack keywords
    if (lower.find("physical damage") != std::string::npos ||
        lower.find("attack speed") != std::string::npos ||
        lower.find("attacks") != std::string::npos ||
        lower.find("critical strike") != std::string::npos ||
        lower.find("armour") != std::string::npos ||
        lower.find("armor") != std::string::npos ||
        lower.find("bleed") != std::string::npos ||
        lower.find("impale") != std::string::npos ||
        lower.find("accuracy") != std::string::npos) {
        return ModCategory::PhysicalAttack;
    }

    // 3. Spell, Mana & Energy Shield keywords
    if (lower.find("spell damage") != std::string::npos ||
        lower.find("cast speed") != std::string::npos ||
        lower.find("energy shield") != std::string::npos ||
        lower.find("maximum mana") != std::string::npos ||
        lower.find("mana regeneration") != std::string::npos ||
        lower.find("spells") != std::string::npos) {
        return ModCategory::SpellElemental;
    }

    // 4. Defense, Movement Speed & Resistances
    if (lower.find("movement speed") != std::string::npos ||
        lower.find("evasion rating") != std::string::npos ||
        lower.find("fire resistance") != std::string::npos ||
        lower.find("cold resistance") != std::string::npos ||
        lower.find("lightning resistance") != std::string::npos ||
        lower.find("chaos resistance") != std::string::npos ||
        lower.find("elemental resistances") != std::string::npos ||
        lower.find("all resistances") != std::string::npos ||
        lower.find("maximum life") != std::string::npos) {
        return ModCategory::DefenseResistSpeed;
    }

    return ModCategory::Default;
}

std::string ModColorizer::FormatColoredBBCode(const std::string& text, ModCategory category) {
    if (category == ModCategory::Default) {
        return text;
    }

    ColorRgb rgb = GetCategoryColor(category);
    char hexBuf[16];
    std::snprintf(hexBuf, sizeof(hexBuf), "#%02X%02X%02X", rgb.r, rgb.g, rgb.b);

    std::ostringstream oss;
    oss << "[color=" << hexBuf << "]" << text << "[/color]";
    return oss.str();
}

bool ModColorizer::SetFontColorTableAddress(uintptr_t address, size_t size) {
    if (address == 0 || size == 0) return false;
    colorTableAddr_ = address;
    tableSize_ = size;
    return true;
}

bool ModColorizer::ApplyColorPatches() {
    if (!memory_.IsAttached() || colorTableAddr_ == 0 || tableSize_ == 0) {
        return false;
    }

    if (isPatched_) {
        return true;
    }

    // Backup original table bytes
    originalBytes_.resize(tableSize_);
    if (!memory_.Read(colorTableAddr_, originalBytes_.data(), tableSize_)) {
        return false;
    }

    // Prepare custom palette bytes:
    // Slot 0: Physical (Red)
    // Slot 1: Spell (Blue)
    // Slot 2: Defense/Resist (Green)
    // Slot 3: Tier 1 (Gold)
    patchedBytes_.resize(tableSize_);
    std::memcpy(patchedBytes_.data(), originalBytes_.data(), tableSize_);

    const ColorRgb c1 = GetCategoryColor(ModCategory::PhysicalAttack);
    const ColorRgb c2 = GetCategoryColor(ModCategory::SpellElemental);
    const ColorRgb c3 = GetCategoryColor(ModCategory::DefenseResistSpeed);
    const ColorRgb c4 = GetCategoryColor(ModCategory::Tier1Rare);

    if (tableSize_ >= 16) {
        patchedBytes_[0] = c1.r; patchedBytes_[1] = c1.g; patchedBytes_[2] = c1.b; patchedBytes_[3] = c1.a;
        patchedBytes_[4] = c2.r; patchedBytes_[5] = c2.g; patchedBytes_[6] = c2.b; patchedBytes_[7] = c2.a;
        patchedBytes_[8] = c3.r; patchedBytes_[9] = c3.g; patchedBytes_[10] = c3.b; patchedBytes_[11] = c3.a;
        patchedBytes_[12] = c4.r; patchedBytes_[13] = c4.g; patchedBytes_[14] = c4.b; patchedBytes_[15] = c4.a;
    }

    if (!memory_.Write(colorTableAddr_, patchedBytes_.data(), tableSize_)) {
        return false;
    }

    isPatched_ = true;
    return true;
}

bool ModColorizer::RestoreColorPatches() {
    if (!memory_.IsAttached() || colorTableAddr_ == 0 || !isPatched_) {
        return false;
    }

    if (!originalBytes_.empty()) {
        memory_.Write(colorTableAddr_, originalBytes_.data(), originalBytes_.size());
    }

    isPatched_ = false;
    return true;
}

void ModColorizer::PanicRestoreAll() {
    RestoreColorPatches();
}

} // namespace visual
