#include "presentation/pages/quests/QuestsPage.h"

#include <algorithm>
#include <string>
#include <vector>

#include <imgui.h>

#include "presentation/localization/UiLocalizationService.h"
#include "foundation/diagnostics/ExecutionPath.h"
#include "presentation/action_feedback/ActionFeedbackPresenter.h"
#include "presentation/theme/MenuTheme.h"
#include "presentation/runtime/Viewport.h"
#include "presentation/widgets/BasicWidgets.h"

namespace ta::presentation::pages::quests
{
    namespace
    {
        using ta::features::quests::contracts::QuestAction;
        using ta::features::quests::contracts::QuestCommandBatch;
        using ta::features::quests::contracts::QuestConditionEntry;
        using ta::features::quests::contracts::QuestEntry;

        QuestCommandBatch build_batch(const QuestSelectionModel& model, const QuestAction action)
        {
            QuestCommandBatch batch{};
            batch.action = action;
            batch.quest_ids = model.selected_ids();
            if (action == QuestAction::CompleteQuest)
                batch.condition_ids = model.selected_condition_ids();
            return batch;
        }

        std::size_t action_target_count(const QuestSelectionModel& model, const QuestAction action)
        {
            return action == QuestAction::CompleteQuest
                ? model.total_selection_count()
                : model.selected_count();
        }

        void submit_action(const QuestsPageContext& context,
                           const QuestSelectionModel& model,
                           const QuestAction action)
        {
            if (!context.in_raid || !context.commands || action_target_count(model, action) == 0)
                return;

            QuestCommandBatch batch = build_batch(model, action);
            batch.trace_id = ActionFeedbackPresenter::begin(
                ActionFeedbackPresenter::quest_action_key(batch.action),
                ta::presentation::localization::tr(std::string(ta::features::quests::contracts::to_string(batch.action))),
                "Quests",
                std::to_string(batch.selection_count()) + " selected");
            ta::foundation::execution_path::step(batch.trace_id, "QuestsPage", "submit quest command");
            context.commands->submit(std::move(batch));
        }

        void draw_action_button(const QuestsPageContext& context,
                                const QuestSelectionModel& model,
                                const QuestAction action,
                                const char* label,
                                const float width)
        {
            const char* key = ActionFeedbackPresenter::quest_action_key(action);
            const bool pending = ActionFeedbackPresenter::is_pending(key);
            ImGui::BeginDisabled(!context.in_raid || action_target_count(model, action) == 0 || pending);
            const std::string button_label = pending
                ? ta::presentation::localization::tr("Queued") + "...##" + key
                : ta::presentation::localization::tr(label) + "##" + key;
            if (ta::presentation::widgets::action_button(button_label, width, width * 0.72f))
                submit_action(context, model, action);
            ImGui::EndDisabled();
        }

        void draw_action_bar(const QuestsPageContext& context, QuestSelectionModel& model)
        {
            const float scale = ta::presentation::runtime::scale_factor();
            const bool compact = ImGui::GetContentRegionAvail().x < 760.0f * scale;

            ImGui::Text("%s: %zu", ta::presentation::localization::tr("Selected").c_str(), model.selected_count());
            if (!compact)
                ImGui::SameLine();
            ImGui::TextColored(ta::presentation::theme::palette::muted,
                               "%s: %zu",
                               ta::presentation::localization::tr("Conditions selected").c_str(),
                               model.selected_condition_count());

            if (!compact)
                ImGui::SameLine();
            ImGui::BeginDisabled(model.total_selection_count() == 0);
            if (ta::presentation::widgets::action_button(ta::presentation::localization::tr("Clear selection"), 120.0f, 100.0f))
                model.clear_selection();
            ImGui::EndDisabled();
            ImGui::SameLine();
            draw_action_button(context, model, QuestAction::CompleteQuest, "Complete selected", 140.0f);
            ImGui::SameLine();
            draw_action_button(context, model, QuestAction::SkipTask, "Skip", 95.0f);
        }

        const char* category_label_key(const int category)
        {
            switch (category)
            {
            case 0: return "Main Quests";
            case 1: return "Side Quests";
            case 2: return "Operational Tasks";
            case 3: return "Unknown Quests";
            default: return "Unknown Quests";
            }
        }

        void draw_filters(QuestSelectionModel& model)
        {
            ta::presentation::widgets::section_header(ta::presentation::localization::tr("Quest Category"));
            int category = model.category_filter();
            if (ImGui::RadioButton(ta::presentation::localization::tr("Main Quests").c_str(), category == 0))
                category = 0;
            if (ImGui::RadioButton(ta::presentation::localization::tr("Side Quests").c_str(), category == 1))
                category = 1;
            if (ImGui::RadioButton(ta::presentation::localization::tr("Operational Tasks").c_str(), category == 2))
                category = 2;
            if (ImGui::RadioButton(ta::presentation::localization::tr("Unknown Quests").c_str(), category == 3))
                category = 3;
            model.category_filter() = category;

            ImGui::Spacing();
            if (ta::presentation::widgets::action_button(ta::presentation::localization::tr("Select visible"), 140.0f, 110.0f))
                model.select_visible();
        }

        std::pair<int, int> condition_progress(const QuestEntry& quest)
        {
            const int total = static_cast<int>(quest.conditions.size());
            const int completed = static_cast<int>(std::ranges::count_if(quest.conditions, [](const auto& condition)
            {
                return condition.completed;
            }));
            return {completed, total};
        }

        void draw_quest_row(QuestSelectionModel& model, const QuestEntry& quest)
        {
            ImGui::PushID(quest.id.c_str());
            bool selected = model.selected(quest);
            if (ImGui::Checkbox("##selected", &selected))
                model.set_selected(quest, selected);
            ImGui::SameLine();

            const std::string& name = quest.name;
            const bool detail_selected = model.selected_detail_id() == quest.id;
            if (ImGui::Selectable((name + "##detail").c_str(), detail_selected,
                                  ImGuiSelectableFlags_AllowDoubleClick))
            {
                model.select_detail(quest.id);
            }

            const auto [completed, total] = condition_progress(quest);
            if (total > 0)
                ImGui::TextColored(ta::presentation::theme::palette::muted, "%d/%d", completed, total);

            const std::size_t selected_conditions = model.selected_condition_count(quest);
            if (selected_conditions > 0)
            {
                ImGui::SameLine();
                ImGui::TextColored(ta::presentation::theme::palette::accent, "+%zu", selected_conditions);
            }

            if (total > 0)
            {
                ImGui::ProgressBar(static_cast<float>(completed) / static_cast<float>(total),
                                   ImVec2(-1.0f, 3.0f), "");
            }
            ImGui::Separator();
            ImGui::PopID();
        }

        void draw_quest_list(QuestSelectionModel& model)
        {
            ta::presentation::widgets::section_header(
                ta::presentation::localization::tr(category_label_key(model.category_filter())));
            if (model.visible().empty())
            {
                ta::presentation::widgets::empty_state("No matching quests");
                return;
            }

            ImGui::BeginChild("##filtered_quest_list", ImVec2(0.0f, 0.0f), false);
            std::string current_trader;
            for (const QuestEntry* quest : model.visible())
            {
                if (!quest)
                    continue;

                const std::string trader = quest->trader_name.empty()
                    ? ta::presentation::localization::tr("Unknown Trader")
                    : quest->trader_name;
                if (trader != current_trader)
                {
                    current_trader = trader;
                    ImGui::Spacing();
                    ImGui::TextColored(ta::presentation::theme::palette::accent2, "%s", current_trader.c_str());
                    ImGui::Separator();
                }

                draw_quest_row(model, *quest);
            }
            ImGui::EndChild();
        }

        void draw_condition_row(QuestSelectionModel& model,
                                const QuestEntry& quest,
                                const QuestConditionEntry& condition)
        {
            const float scale = ta::presentation::runtime::scale_factor();
            ImGui::PushID(condition.id.c_str());
            if (condition.depth > 0)
                ImGui::Indent(14.0f * scale * static_cast<float>(condition.depth));

            bool selected = model.condition_selected(quest, condition);
            ImGui::BeginDisabled(condition.completed || model.selected(quest));
            if (ImGui::Checkbox("##condition_selected", &selected))
                model.set_condition_selected(quest, condition, selected);
            ImGui::EndDisabled();
            ImGui::SameLine();

            std::string text = condition.text;
            if (condition.required > 0)
                text += "  " + std::to_string(condition.current) + "/" + std::to_string(condition.required);
            ImGui::PushStyleColor(
                ImGuiCol_Text,
                condition.completed
                    ? ta::presentation::theme::palette::success
                    : ta::presentation::theme::palette::text);
            ImGui::PushTextWrapPos(0.0f);
            ImGui::TextUnformatted(text.c_str());
            ImGui::PopTextWrapPos();
            ImGui::PopStyleColor();

            if (condition.depth > 0)
                ImGui::Unindent(14.0f * scale * static_cast<float>(condition.depth));
            ImGui::PopID();
        }

        void draw_details(QuestSelectionModel& model, const QuestEntry* quest)
        {
            ta::presentation::widgets::section_header(ta::presentation::localization::tr("Quest Details"));
            if (!quest)
            {
                ta::presentation::widgets::empty_state("Select a quest to view details");
                return;
            }

            const std::string& name = quest->name;
            ImGui::TextWrapped("%s", name.c_str());
            ImGui::TextColored(ta::presentation::theme::palette::muted, "%s", quest->trader_name.empty()
                ? ta::presentation::localization::tr("Unknown Trader").c_str()
                : quest->trader_name.c_str());
            ImGui::TextDisabled("%s", quest->id.c_str());

            ImGui::Spacing();
            if (quest->conditions.empty())
            {
                ta::presentation::widgets::empty_state("No conditions");
                return;
            }

            ImGui::BeginDisabled(model.selected(*quest));
            if (ta::presentation::widgets::action_button(ta::presentation::localization::tr("Select incomplete"), 130.0f, 105.0f))
                model.select_incomplete_conditions(*quest);
            ImGui::SameLine();
            ImGui::BeginDisabled(model.selected_condition_count(*quest) == 0);
            if (ta::presentation::widgets::action_button(ta::presentation::localization::tr("Clear conditions"), 125.0f, 100.0f))
                model.clear_condition_selection(*quest);
            ImGui::EndDisabled();
            ImGui::EndDisabled();

            ImGui::Spacing();
            for (const auto& condition : quest->conditions)
                draw_condition_row(model, *quest, condition);
        }
    }

    void draw_quest_workspace(const MenuContext& context, UiState& state)
    {
        const auto snapshot = context.quests.queries
            ? context.quests.queries->latest_snapshot()
            : std::shared_ptr<const ta::features::quests::contracts::QuestListSnapshot>{};
        state.quests.refresh(snapshot);

        ImGui::BeginChild("##quests_page", ImGui::GetContentRegionAvail(), false);
        draw_action_bar(context.quests, state.quests);
        ImGui::Separator();
        ImGui::Spacing();

        const float scale = ta::presentation::runtime::scale_factor();
        const float gap = ta::presentation::theme::ui_metrics().spacing_sm;
        const float total = ImGui::GetContentRegionAvail().x;
        const float height = ImGui::GetContentRegionAvail().y;
        const float filters_width = 150.0f * scale;
        const float details_width = 300.0f * scale;
        const float list_width = (std::max)(1.0f, total - filters_width - details_width - gap * 2.0f);

        const auto draw_results = [&]()
        {
            if (!snapshot)
                ta::presentation::widgets::empty_state("Quest module unavailable");
            else if (snapshot->quests.empty())
                ta::presentation::widgets::empty_state("No active quests");
            else
                draw_quest_list(state.quests);
        };

        ImGui::BeginChild("##quest_filters", ImVec2(filters_width, height), true);
        draw_filters(state.quests);
        ImGui::EndChild();

        ImGui::SameLine(0.0f, gap);
        ImGui::BeginChild("##quest_results", ImVec2(list_width, height), true);
        draw_results();
        ImGui::EndChild();

        ImGui::SameLine(0.0f, gap);
        ImGui::BeginChild("##quest_details", ImVec2(details_width, height), true);
        draw_details(state.quests, state.quests.selected_detail());
        ImGui::EndChild();

        ImGui::EndChild();
    }

    void draw_quests_page(const MenuContext& context, UiState& state)
    {
        draw_quest_workspace(context, state);
    }

}
