#pragma once
#include "../Module.h"
#include "../ModuleCategory.h"
#include "../eft_api.h"
#include "../game_state.h"
#include "../../config/CheckboxValue.h"
#include "../../config/ColorpickerValue.h"
#include "../../config/FloatSliderValue.h"
#include "../../config/IntSliderValue.h"
#include "../../config/MenuSectionValue.h"
#include "../../gui/menu/menu.h"
#include "../../util/i18n.h"

class AmmoHudModule : Module
{
public:
    AmmoHudModule() : Module("Ammo HUD", Misc, "ammo_hud_mod")
    {
    }

    CheckboxValue* enabled = conf(new CheckboxValue(false, "enabled_cb"));
    ColorpickerValue* color = conf(new ColorpickerValue({0.95f, 0.92f, 0.82f, 1.f}, "color_clr"));
    IntSliderValue* font_size = conf(new IntSliderValue(18, 8, 36, "font_size_itm"));

    MenuSectionValue* section_layout_ = conf(new MenuSectionValue("layout_sec"));
    FloatSliderValue* pos_x = conf(new FloatSliderValue(80.f, 0.f, 3840.f, "ammo_hud_pos_x_itm"));
    FloatSliderValue* pos_y = conf(new FloatSliderValue(820.f, 0.f, 2160.f, "ammo_hud_pos_y_itm"));

    void init() override
    {
        enabled->set_master_toggle(true);
    }

    void prepare_menu_draw() override
    {
        const auto dis = [](ConfigValue* v, const bool disabled) { v->set_disabled(disabled); };
        const bool on = enabled->get_value();

        section_layout_->set_section_active(on);
        dis(color, !on);
        dis(font_size, !on);
        dis(pos_x, !on);
        dis(pos_y, !on);
    }

    void draw_menu_extra() override
    {
        if (!enabled->get_value()) return;

        const float sf = menu::get_scale_factor();
        ImGui::Dummy(ImVec2(0, 2.f * sf));
        ImGui::TextColored(menu::palette::muted, "%s", i18n::tr("ammo_hud_drag_inf").c_str());
    }

    void draw_overlay(ImDrawList* draw_list) override
    {
        if (!game_state::is_in_raid || !enabled->get_value() || !cached_.active) return;

        const float sf = menu::get_scale_factor();
        const float font_px = static_cast<float>(font_size->get_value()) * sf;
        ImFont* font = menu::get_hud_font();
        const ImU32 color_u32 = ImGui::GetColorU32(color->get_value());

        const std::string mag_line = std::to_string(cached_.mag_count) + " / " + std::to_string(cached_.mag_max);
        const std::string chamber_line = cached_.chamber_count > 0 && !cached_.chamber_name.empty()
            ? cached_.chamber_name
            : i18n::tr("ammo_hud_empty_lbl");

        float x = pos_x->get_value();
        float y = pos_y->get_value();

        if (menu::is_active())
        {
            const ImVec2 drag_min(x, y);
            const ImVec2 drag_max(x + font_px * 8.f, y + font_px * 2.4f);
            const ImU32 border_col = (color_u32 & 0x00FFFFFFu) | (static_cast<ImU32>(0.35f * 255.f) << 24);
            draw_list->AddRect(drag_min, drag_max, border_col, 2.f * sf, 0, 1.5f * sf);

            const ImVec2 mouse = ImGui::GetIO().MousePos;
            if (ImGui::IsMouseDown(ImGuiMouseButton_Left)
                && mouse.x >= drag_min.x && mouse.x <= drag_max.x
                && mouse.y >= drag_min.y && mouse.y <= drag_max.y)
            {
                const ImVec2 delta = ImGui::GetIO().MouseDelta;
                pos_x->set_value(x + delta.x);
                pos_y->set_value(y + delta.y);
            }
            return;
        }

        ImVec2 pos(x, y);
        draw_list->AddText(font, font_px, pos, color_u32, mag_line.c_str());
        pos.y += font_px + 2.f * sf;
        draw_list->AddText(font, font_px, pos, color_u32, chamber_line.c_str());
    }

    void application_update() override
    {
        if (!game_state::is_in_raid)
            cached_ = {};
    }

    void gameworld_update(const Il2CppClass* /*game_world_class*/, Il2CppObjectInstance /*game_world_instance*/,
                          Il2CppObjectInstance main_player) override
    {
        if (!enabled->get_value())
        {
            cached_ = {};
            return;
        }

        bool hands_not_firearm = false;
        eft_api::weapon_ammo_state fresh{};
        if (eft_api::try_read_weapon_ammo(main_player.get_instance(), fresh, &hands_not_firearm))
        {
            cached_ = fresh;
            return;
        }

        if (hands_not_firearm)
            cached_ = {};
    }

private:
    eft_api::weapon_ammo_state cached_{};
};