#include <AchievementFilter/AchievementFilter.hpp>
#include <Color/Color.hpp>
#include <Material/Material.hpp>
#include <Widget/Builder/Builder.hpp>
#include <Widget/Label/Label.hpp>
#include <Widget/Layout/Center/Center.hpp>
#include <Widget/Layout/Column/Column.hpp>
#include <Widget/Layout/CompoundWidget/AchievementsTab/AchievementsTab.hpp>
#include <Widget/Layout/CompoundWidget/Deck/Deck.hpp>
#include <Widget/Layout/CompoundWidget/DocView/DocView.hpp>
#include <Widget/Layout/CompoundWidget/IconText/IconText.hpp>
#include <Widget/Layout/CompoundWidget/MilestoneListView/MilestoneListView.hpp>
#include <Widget/Layout/Frame/Frame.hpp>
#include <Widget/Layout/Margin/Margin.hpp>
#include <MilestoneRegistry/MilestoneRegistry.hpp>
#include <Widget/Layout/Row/Row.hpp>
#include <Widget/Layout/ScrollPanel/ScrollPanel.hpp>
#include <Widget/Panel/Panel.hpp>
#include <Widget/IconLabel/IconLabel.hpp>
#include <Widget/ProgressIcon/ProgressIcon.hpp>
#include <Widget/Layout/MenuButton/MenuButton.hpp>
#include <Widget/Switch/Switch.hpp>
#include <Widget/TextField/TextField.hpp>
#include <optional>
#include <RuntimeStateCache/RuntimeStateCache.hpp>

AchievementsTab::AchievementsTab(std::shared_ptr<Player> player)
{
    state = RuntimeStateCache::get<State>("/escape-menu/achievements-tab");

    addChildren(
        new Column(
            new Builder<std::optional<std::string>>(
                state->selectedMilestone,
                [this, player](const std::optional<std::string> &milestoneId) -> Widget*
                {
                    if (milestoneId.has_value())
                    {
                        Milestone &milestone = milestoneRegistry.getMilestone(*milestoneId);

                        return new Row(
                            new MenuButton(
                                new Deck<Row, Center>(
                                    new IconLabel(Material::achievementsTab),
                                    new Label("Achievements", Color::navLink)
                                ),
                                [this]()
                                {
                                    state->selectedMilestone = std::nullopt;
                                    state->selectedAchievement = std::nullopt;
                                }
                            ),

                            new Center(new Label(">>", Color::faded)),

                            new Builder<std::optional<int>>(
                                state->selectedAchievement,
                                [this, &milestone, player](const std::optional<int> &achievementId) -> Widget*
                                {
                                    if (achievementId.has_value())
                                    {
                                        auto &achievement = milestone.achievements[*achievementId];

                                        return new Margin<1>(
                                            new Deck<Row, Center>(
                                                new IconLabel(
                                                    player->hasCompletedAchievement(*state->selectedMilestone, *achievementId) ?
                                                        achievement->doneIcon :
                                                        achievement->todoIcon
                                                ),
                                                new Label(achievement->title)
                                            )
                                        );
                                    }
                                    else
                                    {
                                        return new Label("Invalid state!");
                                    }
                                }
                            )
                        );
                    }
                    else
                    {
                        return new Margin<1>(
                            new Row(
                                new Center(new IconLabel(Material::achievementsTab)),
                                new Center(new Label("Achievements")),

                                new Panel(glm::ivec2(20, 0)),

                                Layout::WithProportion<1>(),
                                new Column(
                                    Layout::WithProportion<1>(),
                                    new Panel(),
                                    (new TextField(state->filter.query))
                                        ->withPlaceholder("Search..."),
                                    Layout::WithProportion<1>(),
                                    new Panel()
                                ),

                                new Panel(glm::ivec2(2, 0)),

                                new Center(
                                    new Frame(
                                        Color::sectionBackground,
                                        new Row(
                                            new IconLabel(Material::accept),
                                            new Panel(glm::ivec2(2, 0)),
                                            new Switch(state->filter.showCompleted)
                                        )
                                    )
                                )
                            )
                        );
                    }
                }
            ),

            new Panel(glm::ivec2(0, 1)),

            Layout::WithProportion<1>(),
            new Builder<std::optional<std::string>>(
                state->selectedMilestone,
                [this, player](const std::optional<std::string> &milestoneId) -> Widget*
                {
                    if (milestoneId.has_value())
                    {
                        Milestone &milestone = milestoneRegistry.getMilestone(*milestoneId);

                        return new Builder<std::optional<int>>(
                            state->selectedAchievement,
                            [this, &milestone, player](const std::optional<int> &achievementId) -> Widget*
                            {
                                if (achievementId.has_value())
                                {
                                    auto &achievement = milestone.achievements[*achievementId];
                                    bool done = player->hasCompletedAchievement(*state->selectedMilestone, *achievementId);

                                    return new ScrollPanel(
                                        formatString("/achievements/$+/$+/doc-view-scroll-panel", *state->selectedMilestone, *achievementId),
                                        100,
                                        new Frame(
                                            glm::vec4(0.0f, 0.0f, 0.0f, 1.0f),
                                            new Column(
                                                done ?
                                                    new Label("COMPLETED", Color::positiveStat) :
                                                    new Label("IN PROGRESS", Color::faded),

                                                new Panel(glm::ivec2(0, 4)),

                                                new DocView(maxLineWidth, achievement->description)
                                            )
                                        )
                                    );
                                }
                                else
                                {
                                    return new Label("Invalid state!");
                                }
                            }
                        );
                    }
                    else
                    {
                        return new ScrollPanel(
                            state->listScrollPos,
                            100,
                            new Builder<AchievementFilter>(
                                state->filter,
                                [this, player](const AchievementFilter &filter) -> Widget*
                                {
                                    return new MilestoneListView(
                                        *player,
                                        [this](std::string milestoneId, int achievementId)
                                        {
                                            state->selectedMilestone = milestoneId;
                                            state->selectedAchievement = achievementId;
                                        },
                                        state->filter
                                    );
                                }
                            )

                        );
                    }
                }
            )
        )
    );
}