#include "presentation/pages/DiagnosticsPage.h"

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

#include <imgui.h>
#include <imgui_stdlib.h>

#include "foundation/diagnostics/Logger.h"
#include "presentation/localization/UiLocalizationService.h"
#include "presentation/MenuContext.h"
#include "presentation/fonts/MenuFontAtlas.h"
#include "presentation/theme/MenuTheme.h"
#include "presentation/runtime/Viewport.h"
#include "presentation/widgets/BasicWidgets.h"
#include "foundation/text/StringUtils.h"

namespace ta::presentation::pages
{
    namespace
    {

        bool level_enabled(const DiagnosticsPageState& state, const ta::foundation::logger::Level level)
        {
            switch (level)
            {
            case ta::foundation::logger::Level::Path: return state.show_path;
            case ta::foundation::logger::Level::Info: return state.show_info;
            case ta::foundation::logger::Level::Warning: return state.show_warnings;
            case ta::foundation::logger::Level::Error:
            case ta::foundation::logger::Level::Fatal: return state.show_errors;
            default: return true;
            }
        }

        bool entry_matches(const ta::foundation::logger::Entry& entry,
                           const DiagnosticsPageState& state,
                           const std::string& filter)
        {
            if (!level_enabled(state, entry.level))
                return false;
            if (filter.empty())
                return true;
            return ta::foundation::text::lower_copy(entry.timestamp + " " + entry.channel + " " + entry.message).find(filter) != std::string::npos;
        }

        ImVec4 level_color(const ta::foundation::logger::Level level)
        {
            switch (level)
            {
            case ta::foundation::logger::Level::Path: return ta::presentation::theme::palette::accent;
            case ta::foundation::logger::Level::Warning: return ta::presentation::theme::palette::accent2;
            case ta::foundation::logger::Level::Error: return ImVec4(0.95f, 0.35f, 0.35f, 1.0f);
            case ta::foundation::logger::Level::Fatal: return ImVec4(1.0f, 0.15f, 0.15f, 1.0f);
            case ta::foundation::logger::Level::Info:
            default: return ta::presentation::theme::palette::text;
            }
        }

        void draw_status_card(const char* title, const bool ready, const std::string& detail)
        {
            ImGui::BeginGroup();
            ImGui::TextColored(ready ? ta::presentation::theme::palette::success : ta::presentation::theme::palette::accent2,
                               "%s", ready ? "●" : "○");
            ImGui::SameLine();
            ImGui::TextUnformatted(ta::presentation::localization::tr(title).c_str());
            ImGui::TextColored(ta::presentation::theme::palette::muted, "%s", detail.c_str());
            ImGui::EndGroup();
        }

        void update_rates(DiagnosticsPageState& state,
                          const DiagnosticsSnapshot& snapshot)
        {
            const double now = ImGui::GetTime();
            if (state.rate_sample_time <= 0.0)
            {
                state.rate_sample_time = now;
                state.previous_application_hits = snapshot.hooks.tarkov_application_update_hits;
                state.previous_gameworld_hits = snapshot.hooks.game_world_update_hits;
                state.previous_present_hits = snapshot.render.present_hits;
                state.previous_fixed_update_hits = snapshot.hooks.player_fixed_update_hits;
                return;
            }

            const double elapsed = now - state.rate_sample_time;
            if (elapsed < 0.5)
                return;

            const auto rate = [elapsed](const std::uint64_t current, const std::uint64_t previous)
            {
                if (current < previous || elapsed <= 0.0)
                    return 0.0f;
                return static_cast<float>(static_cast<double>(current - previous) / elapsed);
            };

            state.application_hz = rate(snapshot.hooks.tarkov_application_update_hits, state.previous_application_hits);
            state.gameworld_hz = rate(snapshot.hooks.game_world_update_hits, state.previous_gameworld_hits);
            state.present_hz = rate(snapshot.render.present_hits, state.previous_present_hits);
            state.fixed_update_hz = rate(snapshot.hooks.player_fixed_update_hits, state.previous_fixed_update_hits);

            state.previous_application_hits = snapshot.hooks.tarkov_application_update_hits;
            state.previous_gameworld_hits = snapshot.hooks.game_world_update_hits;
            state.previous_present_hits = snapshot.render.present_hits;
            state.previous_fixed_update_hits = snapshot.hooks.player_fixed_update_hits;
            state.rate_sample_time = now;
        }

        void draw_rate_card(const char* title, const float value, const char* unit)
        {
            ImGui::BeginGroup();
            ImGui::TextColored(ta::presentation::theme::palette::accent, "%s", ta::presentation::localization::tr(title).c_str());
            ImGui::PushFont(ta::presentation::fonts::bold_font());
            ImGui::Text("%.1f %s", value, unit);
            ImGui::PopFont();
            ImGui::EndGroup();
        }

        void timing_row(const char* label, const ta::foundation::diagnostics::TimingMetricSnapshot& metric)
        {
            ImGui::TableNextRow();
            ImGui::TableSetColumnIndex(0);
            ImGui::TextUnformatted(ta::presentation::localization::tr(label).c_str());
            ImGui::TableSetColumnIndex(1);
            ImGui::Text("%.3f", metric.latest_ms);
            ImGui::TableSetColumnIndex(2);
            ImGui::Text("%.3f", metric.average_ms);
            ImGui::TableSetColumnIndex(3);
            ImGui::Text("%.3f", metric.max_ms);
            ImGui::TableSetColumnIndex(4);
            ImGui::Text("%llu", static_cast<unsigned long long>(metric.samples));
        }

        std::size_t config_value_count(const MenuContext& ctx)
        {
            if (!ctx.config)
                return 0;

            std::size_t count = ctx.config->global_config.values.size();
            for (const ConfigPanelSnapshot& panel : ctx.config->panels)
                count += panel.values.size();
            return count;
        }

        void draw_performance_diagnostics(const MenuContext& ctx,
                                          DiagnosticsPageState& state,
                                          const DiagnosticsSnapshot& snapshot)
        {
            update_rates(state, snapshot);

            if (ImGui::BeginTable("##performance_rates", 4,
                                  ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_BordersInnerV))
            {
                ImGui::TableNextRow();
                ImGui::TableSetColumnIndex(0);
                draw_rate_card("Present rate", state.present_hz, "FPS");
                ImGui::TableSetColumnIndex(1);
                draw_rate_card("Application update rate", state.application_hz, "Hz");
                ImGui::TableSetColumnIndex(2);
                draw_rate_card("GameWorld update rate", state.gameworld_hz, "Hz");
                ImGui::TableSetColumnIndex(3);
                draw_rate_card("FixedUpdate rate", state.fixed_update_hz, "Hz");
                ImGui::EndTable();
            }

            ImGui::Spacing();
            if (ImGui::BeginTable("##performance_timings", 5,
                                  ImGuiTableFlags_RowBg |
                                  ImGuiTableFlags_BordersInnerH |
                                  ImGuiTableFlags_SizingStretchProp))
            {
                ImGui::TableSetupColumn(ta::presentation::localization::tr("Measured path").c_str(), ImGuiTableColumnFlags_WidthStretch);
                ImGui::TableSetupColumn(ta::presentation::localization::tr("Latest ms").c_str(), ImGuiTableColumnFlags_WidthFixed, 90.0f);
                ImGui::TableSetupColumn(ta::presentation::localization::tr("Average ms").c_str(), ImGuiTableColumnFlags_WidthFixed, 90.0f);
                ImGui::TableSetupColumn(ta::presentation::localization::tr("Maximum ms").c_str(), ImGuiTableColumnFlags_WidthFixed, 90.0f);
                ImGui::TableSetupColumn(ta::presentation::localization::tr("Samples").c_str(), ImGuiTableColumnFlags_WidthFixed, 80.0f);
                ImGui::TableHeadersRow();
                timing_row("Application feature update", snapshot.application_loop.application_update_timing);
                timing_row("GameWorld feature update", snapshot.application_loop.gameworld_update_timing);
                timing_row("Overlay frame", snapshot.render.overlay_frame_timing);
                ImGui::EndTable();
            }

            const std::size_t item_count = ctx.items.catalog ? ctx.items.catalog->items.size() : 0;
            const auto quest_snapshot = ctx.quests.queries
                ? ctx.quests.queries->latest_snapshot()
                : std::shared_ptr<const ta::features::quests::contracts::QuestListSnapshot>{};
            const std::size_t quest_count = quest_snapshot ? quest_snapshot->quests.size() : 0;
            const std::size_t label_count = ctx.esp.labels.size();
            const std::size_t config_count = config_value_count(ctx);

            ImGui::Spacing();
            ImGui::TextColored(ta::presentation::theme::palette::muted, "%s", ta::presentation::localization::tr("Snapshot sizes").c_str());
            if (ImGui::BeginTable("##snapshot_sizes", 4, ImGuiTableFlags_SizingStretchSame))
            {
                ImGui::TableNextRow();
                ImGui::TableSetColumnIndex(0);
                ImGui::Text("%s: %zu", ta::presentation::localization::tr("Catalog items").c_str(), item_count);
                ImGui::TableSetColumnIndex(1);
                ImGui::Text("%s: %zu", ta::presentation::localization::tr("Active quests").c_str(), quest_count);
                ImGui::TableSetColumnIndex(2);
                ImGui::Text("%s: %zu", ta::presentation::localization::tr("ESP labels").c_str(), label_count);
                ImGui::TableSetColumnIndex(3);
                ImGui::Text("%s: %zu", ta::presentation::localization::tr("Setting values").c_str(), config_count);
                ImGui::EndTable();
            }
        }

        void draw_runtime_cards(const DiagnosticsSnapshot& snapshot)
        {
            if (ImGui::BeginTable("##runtime_cards", 3,
                                  ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_BordersInnerV))
            {
                ImGui::TableNextRow();
                ImGui::TableSetColumnIndex(0);
                draw_status_card("ImGui", snapshot.render.imgui_initialized,
                                 snapshot.render.imgui_initialized ? ta::presentation::localization::tr("Initialized") : ta::presentation::localization::tr("Not initialized"));
                ImGui::TableSetColumnIndex(1);
                draw_status_card("Item factory", snapshot.item_factory_captured,
                                 snapshot.item_factory_captured ? ta::presentation::localization::tr("Ready") : ta::presentation::localization::tr("Not Ready"));
                ImGui::TableSetColumnIndex(2);
                const bool gameworld_active = snapshot.hooks.gameworld_update_dispatch_hits > 0;
                draw_status_card("GameWorld", gameworld_active,
                                 std::to_string(snapshot.hooks.gameworld_update_dispatch_hits) + " " + ta::presentation::localization::tr("dispatches"));

                ImGui::TableNextRow();
                ImGui::TableSetColumnIndex(0);
                draw_status_card("Setting commands",
                                 snapshot.config_commands.consumed == snapshot.config_commands.requested,
                                 std::to_string(snapshot.config_commands.consumed) + "/" + std::to_string(snapshot.config_commands.requested));
                ImGui::TableSetColumnIndex(1);
                draw_status_card("Item actions",
                                 snapshot.item_actions.consumed == snapshot.item_actions.requested,
                                 std::to_string(snapshot.item_actions.consumed) + "/" + std::to_string(snapshot.item_actions.requested));
                ImGui::TableSetColumnIndex(2);
                draw_status_card("Quest batches",
                                 snapshot.quest_commands.consumed == snapshot.quest_commands.requested,
                                 std::to_string(snapshot.quest_commands.consumed) + "/" + std::to_string(snapshot.quest_commands.requested));
                ImGui::EndTable();
            }
        }

        void counter_row(const char* label, const std::uint64_t value, const char* meaning)
        {
            ImGui::TableNextRow();
            ImGui::TableSetColumnIndex(0);
            ImGui::TextUnformatted(ta::presentation::localization::tr(label ? label : "").c_str());
            ImGui::TableSetColumnIndex(1);
            ImGui::Text("%llu", static_cast<unsigned long long>(value));
            ImGui::TableSetColumnIndex(2);
            ImGui::TextColored(ta::presentation::theme::palette::muted, "%s", ta::presentation::localization::tr(meaning ? meaning : "").c_str());
        }

        void ratio_row(const char* label,
                       const std::uint64_t consumed,
                       const std::uint64_t requested,
                       const char* meaning)
        {
            ImGui::TableNextRow();
            ImGui::TableSetColumnIndex(0);
            ImGui::TextUnformatted(ta::presentation::localization::tr(label ? label : "").c_str());
            ImGui::TableSetColumnIndex(1);
            ImGui::Text("%llu/%llu",
                        static_cast<unsigned long long>(consumed),
                        static_cast<unsigned long long>(requested));
            ImGui::TableSetColumnIndex(2);
            ImGui::TextColored(ta::presentation::theme::palette::muted, "%s", ta::presentation::localization::tr(meaning ? meaning : "").c_str());
        }

        void draw_runtime_details(const DiagnosticsSnapshot& snapshot)
        {
            if (!ImGui::CollapsingHeader(ta::presentation::localization::tr("Detailed counters").c_str()))
                return;

            if (!ImGui::BeginTable("##runtime_diagnostics", 3,
                                   ImGuiTableFlags_RowBg |
                                   ImGuiTableFlags_BordersInnerH |
                                   ImGuiTableFlags_SizingStretchProp))
            {
                return;
            }

            ImGui::TableSetupColumn(ta::presentation::localization::tr("Boundary").c_str(), ImGuiTableColumnFlags_WidthStretch, 0.35f);
            ImGui::TableSetupColumn(ta::presentation::localization::tr("Hits").c_str(), ImGuiTableColumnFlags_WidthFixed, 90.0f);
            ImGui::TableSetupColumn(ta::presentation::localization::tr("Execution role").c_str(), ImGuiTableColumnFlags_WidthStretch, 0.65f);
            ImGui::TableHeadersRow();

            counter_row("TarkovApplication.Update", snapshot.hooks.tarkov_application_update_hits, "application-thread command intake");
            counter_row("GameWorld.Update hook", snapshot.hooks.game_world_update_hits, "authoritative raid callback");
            counter_row("GameWorld dispatcher", snapshot.hooks.gameworld_update_dispatch_hits, "feature module dispatch");
            counter_row("DX11 Present", snapshot.render.present_hits, "UI capture and rendering");
            counter_row("Player.FixedUpdate", snapshot.hooks.player_fixed_update_hits, "movement hook callback");
            counter_row("LocalGame.Stop", snapshot.hooks.local_game_stop_hits, "raid shutdown callback");
            counter_row("Item factory hook", snapshot.item_factory_hits,
                        snapshot.item_factory_captured ? "factory captured" : "factory not captured");
            ratio_row("Setting commands", snapshot.config_commands.consumed, snapshot.config_commands.requested, "application-thread queue");
            ratio_row("Item actions", snapshot.item_actions.consumed, snapshot.item_actions.requested, "GameWorld command slot");
            ratio_row("Quest batches", snapshot.quest_commands.consumed, snapshot.quest_commands.requested, "GameWorld command queue");
            ratio_row("Player actions", snapshot.player_actions.consumed, snapshot.player_actions.requested, "GameWorld command slot");
            ratio_row("Unlock doors", snapshot.world_unlock_doors.consumed, snapshot.world_unlock_doors.requested, "World command slot");
            ratio_row("Item Teleport", snapshot.world_item_teleport.consumed, snapshot.world_item_teleport.requested, "World command slot");
            ImGui::EndTable();
        }

        void draw_runtime_tab(const DiagnosticsSnapshot& snapshot)
        {
            draw_runtime_cards(snapshot);
            ImGui::Spacing();
            draw_runtime_details(snapshot);
        }

        void draw_log_toolbar(DiagnosticsPageState& state)
        {
            const float scale = ta::presentation::runtime::scale_factor();
            const bool compact = ImGui::GetContentRegionAvail().x < 760.0f * scale;

            const auto draw_log_actions = [&]()
            {
                if (ta::presentation::widgets::action_button(ta::presentation::localization::tr("Save snapshot"), 130.0f, 105.0f))
                {
                    if (ta::foundation::logger::save_history())
                        state.save_status = ta::presentation::localization::tr("Saved") + ": " + ta::foundation::logger::history_snapshot_path().string();
                    else
                        state.save_status = ta::presentation::localization::tr("Save failed");
                }
                ImGui::SameLine();
                if (ta::presentation::widgets::action_button(ta::presentation::localization::tr("Clear in-memory log"), 155.0f, 125.0f))
                {
                    ta::foundation::logger::clear_history();
                    state.paused = false;
                    state.save_status = ta::presentation::localization::tr("In-memory log cleared");
                }
            };

            if (compact)
            {
                ImGui::SetNextItemWidth(-1.0f);
                ImGui::InputTextWithHint("##execution_log_filter",
                                         ta::presentation::localization::tr("Filter trace id, component or message").c_str(),
                                         &state.filter);

                const std::string pause_label = ta::presentation::localization::tr(state.paused ? "Resume" : "Pause");
                if (ta::presentation::widgets::action_button(pause_label, 105.0f, 85.0f))
                    state.paused = !state.paused;
                ImGui::SameLine();
                ImGui::Checkbox(ta::presentation::localization::tr("Follow latest").c_str(), &state.auto_scroll);
            }
            else if (ImGui::BeginTable("##log_primary_toolbar", 3,
                                       ImGuiTableFlags_SizingStretchProp |
                                       ImGuiTableFlags_NoSavedSettings))
            {
                ImGui::TableSetupColumn("##filter", ImGuiTableColumnFlags_WidthStretch, 0.72f);
                ImGui::TableSetupColumn("##pause", ImGuiTableColumnFlags_WidthFixed, 110.0f * scale);
                ImGui::TableSetupColumn("##scroll", ImGuiTableColumnFlags_WidthFixed, 130.0f * scale);
                ImGui::TableNextRow();
                ImGui::TableSetColumnIndex(0);
                ImGui::SetNextItemWidth(-1.0f);
                ImGui::InputTextWithHint("##execution_log_filter",
                                         ta::presentation::localization::tr("Filter trace id, component or message").c_str(),
                                         &state.filter);
                ImGui::TableSetColumnIndex(1);
                const std::string pause_label = ta::presentation::localization::tr(state.paused ? "Resume" : "Pause");
                if (ta::presentation::widgets::action_button(pause_label, 105.0f, 85.0f))
                    state.paused = !state.paused;
                ImGui::TableSetColumnIndex(2);
                ImGui::Checkbox(ta::presentation::localization::tr("Follow latest").c_str(), &state.auto_scroll);
                ImGui::EndTable();
            }

            if (compact)
            {
                if (ImGui::BeginTable("##log_levels_compact", 3,
                                      ImGuiTableFlags_SizingStretchSame |
                                      ImGuiTableFlags_NoSavedSettings))
                {
                    ImGui::TableNextColumn();
                    ImGui::Checkbox(ta::presentation::localization::tr("Trace").c_str(), &state.show_path);
                    ImGui::TableNextColumn();
                    ImGui::Checkbox(ta::presentation::localization::tr("Info").c_str(), &state.show_info);
                    ImGui::TableNextColumn();
                    ImGui::Checkbox(ta::presentation::localization::tr("Warnings").c_str(), &state.show_warnings);
                    ImGui::TableNextColumn();
                    ImGui::Checkbox(ta::presentation::localization::tr("Errors").c_str(), &state.show_errors);
                    ImGui::TableNextColumn();
                    ImGui::Checkbox(ta::presentation::localization::tr("Thread").c_str(), &state.show_thread);
                    ImGui::EndTable();
                }
            }
            else if (ImGui::BeginTable("##log_secondary_toolbar", 2,
                                       ImGuiTableFlags_SizingStretchProp |
                                       ImGuiTableFlags_NoSavedSettings))
            {
                ImGui::TableSetupColumn("##levels", ImGuiTableColumnFlags_WidthStretch, 0.62f);
                ImGui::TableSetupColumn("##actions", ImGuiTableColumnFlags_WidthStretch, 0.38f);
                ImGui::TableNextRow();
                ImGui::TableSetColumnIndex(0);
                ImGui::Checkbox(ta::presentation::localization::tr("Trace").c_str(), &state.show_path);
                ImGui::SameLine();
                ImGui::Checkbox(ta::presentation::localization::tr("Info").c_str(), &state.show_info);
                ImGui::SameLine();
                ImGui::Checkbox(ta::presentation::localization::tr("Warnings").c_str(), &state.show_warnings);
                ImGui::SameLine();
                ImGui::Checkbox(ta::presentation::localization::tr("Errors").c_str(), &state.show_errors);
                ImGui::SameLine();
                ImGui::Checkbox(ta::presentation::localization::tr("Thread").c_str(), &state.show_thread);

                ImGui::TableSetColumnIndex(1);
                draw_log_actions();
                ImGui::EndTable();
            }

            if (compact)
                draw_log_actions();

            const std::filesystem::path persistent_path = ta::foundation::logger::file_output_path();
            if (!persistent_path.empty())
            {
                ImGui::PushTextWrapPos(0.0f);
                ImGui::TextColored(ta::presentation::theme::palette::muted, "%s: %s",
                                   ta::presentation::localization::tr("Persistent log").c_str(), persistent_path.string().c_str());
                ImGui::PopTextWrapPos();
            }
            if (!state.save_status.empty())
            {
                ImGui::PushTextWrapPos(0.0f);
                ImGui::TextColored(ta::presentation::theme::palette::muted, "%s", state.save_status.c_str());
                ImGui::PopTextWrapPos();
            }
        }

        const std::vector<ta::foundation::logger::Entry>& current_entries(DiagnosticsPageState& state)
        {
            if (state.paused && !state.was_paused)
                state.paused_entries = ta::foundation::logger::snapshot(1500);
            if (!state.paused)
                state.live_entries = ta::foundation::logger::snapshot(1500);
            state.was_paused = state.paused;
            return state.paused ? state.paused_entries : state.live_entries;
        }

        void draw_log_table(DiagnosticsPageState& state)
        {
            const std::vector<ta::foundation::logger::Entry>& entries = current_entries(state);
            const std::string filter = ta::foundation::text::lower_copy(state.filter);
            std::vector<std::size_t> visible;
            visible.reserve(entries.size());
            for (std::size_t i = 0; i < entries.size(); ++i)
            {
                if (entry_matches(entries[i], state, filter))
                    visible.push_back(i);
            }

            ImGui::Text("%s: %zu / %zu", ta::presentation::localization::tr("Visible entries").c_str(), visible.size(), entries.size());
            constexpr ImGuiTableFlags flags =
                ImGuiTableFlags_ScrollY |
                ImGuiTableFlags_RowBg |
                ImGuiTableFlags_BordersInnerV |
                ImGuiTableFlags_Resizable |
                ImGuiTableFlags_SizingStretchProp;

            const int column_count = state.show_thread ? 5 : 4;
            if (!ImGui::BeginTable("##execution_log_table", column_count, flags, ImGui::GetContentRegionAvail()))
                return;

            ImGui::TableSetupScrollFreeze(0, 1);
            const float scale = ta::presentation::runtime::scale_factor();
            ImGui::TableSetupColumn(ta::presentation::localization::tr("Time").c_str(), ImGuiTableColumnFlags_WidthFixed, 92.0f * scale);
            ImGui::TableSetupColumn(ta::presentation::localization::tr("Level").c_str(), ImGuiTableColumnFlags_WidthFixed, 68.0f * scale);
            ImGui::TableSetupColumn(ta::presentation::localization::tr("Component").c_str(), ImGuiTableColumnFlags_WidthFixed, 95.0f * scale);
            if (state.show_thread)
                ImGui::TableSetupColumn(ta::presentation::localization::tr("Thread").c_str(), ImGuiTableColumnFlags_WidthFixed, 82.0f * scale);
            ImGui::TableSetupColumn(ta::presentation::localization::tr("Message").c_str(), ImGuiTableColumnFlags_WidthStretch);
            ImGui::TableHeadersRow();

            const bool was_at_bottom = ImGui::GetScrollY() >= ImGui::GetScrollMaxY() - 2.0f;
            ImGuiListClipper clipper;
            clipper.Begin(static_cast<int>(visible.size()));
            while (clipper.Step())
            {
                for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; ++row)
                {
                    const ta::foundation::logger::Entry& entry = entries[visible[static_cast<std::size_t>(row)]];
                    ImGui::PushID(static_cast<int>(entry.sequence));
                    ImGui::TableNextRow();
                    ImGui::TableSetColumnIndex(0);
                    ImGui::TextUnformatted(entry.timestamp.c_str());
                    ImGui::TableSetColumnIndex(1);
                    ImGui::TextColored(level_color(entry.level), "%s", ta::foundation::logger::level_name(entry.level));
                    ImGui::TableSetColumnIndex(2);
                    ImGui::TextUnformatted(entry.channel.c_str());
                    int message_column = 3;
                    if (state.show_thread)
                    {
                        ImGui::TableSetColumnIndex(3);
                        ImGui::Text("T%llu", static_cast<unsigned long long>(entry.thread_id));
                        message_column = 4;
                    }
                    ImGui::TableSetColumnIndex(message_column);
                    ImGui::TextUnformatted(entry.message.c_str());
                    if (ImGui::IsItemHovered())
                        ImGui::SetTooltip("%s", entry.message.c_str());
                    if (ImGui::BeginPopupContextItem("##log_context"))
                    {
                        if (ImGui::MenuItem(ta::presentation::localization::tr("Copy message").c_str()))
                            ImGui::SetClipboardText(entry.message.c_str());
                        const std::string thread_text = state.show_thread ? "[T" + std::to_string(entry.thread_id) + "]" : std::string{};
                        const std::string row_text = entry.timestamp + " [" + ta::foundation::logger::level_name(entry.level) + "][" + entry.channel + "]" + thread_text + " " + entry.message;
                        if (ImGui::MenuItem(ta::presentation::localization::tr("Copy row").c_str()))
                            ImGui::SetClipboardText(row_text.c_str());
                        ImGui::EndPopup();
                    }
                    ImGui::PopID();
                }
            }

            if (state.auto_scroll && !state.paused && was_at_bottom)
                ImGui::SetScrollHereY(1.0f);
            ImGui::EndTable();
        }

        void draw_logs_tab(DiagnosticsPageState& state)
        {
            draw_log_toolbar(state);
            ImGui::Separator();
            draw_log_table(state);
        }
    }

    void draw_diagnostics_page(const MenuContext& ctx, UiState& state)
    {
        const DiagnosticsSnapshot& snapshot = ctx.diagnostics;

        ImGui::BeginChild("##diagnostics_page", ImGui::GetContentRegionAvail(), false);
        if (ImGui::BeginTabBar("##diagnostics_tabs", ImGuiTabBarFlags_FittingPolicyScroll))
        {
            if (ImGui::BeginTabItem(ta::presentation::localization::tr("Overview").c_str()))
            {
                draw_performance_diagnostics(ctx, state.diagnostics, snapshot);
                ImGui::Spacing();
                ImGui::Separator();
                ImGui::Spacing();
                draw_runtime_tab(snapshot);
                ImGui::EndTabItem();
            }
            if (ImGui::BeginTabItem(ta::presentation::localization::tr("Execution Logs").c_str()))
            {
                draw_logs_tab(state.diagnostics);
                ImGui::EndTabItem();
            }
            ImGui::EndTabBar();
        }
        ImGui::EndChild();
    }
}
