#pragma once

#include "engine/prefabs/includes.h"
#include "entities/song.h"
#include "entities/song_catalog.h"
#include "rapidjson/filereadstream.h"
#include <cstdio>
#include <vector>

extern std::string SELECTED_SONG_PATH;
extern int SELECTED_TRACK_OVERRIDE;

struct SongEntry
{
    std::string name;
    std::string artist;
    std::string path;
    int track_override;
};

inline std::vector<SongEntry> build_song_list(const std::vector<SongCatalogEntry>& catalog)
{
    std::vector<SongEntry> entries;
    for (const auto& entry : catalog)
    {
        const std::string& path = entry.first;
        int track_override = entry.second;
        std::FILE* fp = std::fopen(path.c_str(), "rb");
        if (!fp)
            continue;
        char read_buf[65536];
        rapidjson::FileReadStream is(fp, read_buf, sizeof(read_buf));
        rapidjson::Document doc;
        if (doc.ParseStream(is).HasParseError())
        {
            std::fclose(fp);
            continue;
        }
        std::fclose(fp);
        Song song = parseSong(doc);
        entries.push_back(
            {song.header.name.empty() ? path : song.header.name, song.header.artist, path,
             track_override});
    }
    while (entries.size() < 4)
    {
        for (size_t i = 0; i < entries.size() && entries.size() < 4; i++)
            entries.push_back(entries[i]);
    }
    return entries;
}

class SongSelectScreen : public Scene
{
public:
    static constexpr int VISIBLE_SLOTS = 4;

    Font font = {0};
    std::vector<SongEntry> songs;
    int selected_index = 0;
    int scroll_offset = 0;

    void init() override
    {
        auto font_manager = game->get_manager<FontManager>();
        font = font_manager->get_font("Roboto");
        songs = build_song_list(get_song_catalog());
        selected_index = 0;
        scroll_offset = 0;
    }

    void update(float delta_time) override
    {
        bool up = IsKeyPressed(KEY_UP);
        bool down = IsKeyPressed(KEY_DOWN);
        for (int gp = 0; gp < 4; gp++)
        {
            if (IsGamepadAvailable(gp))
            {
                if (IsGamepadButtonPressed(gp, GAMEPAD_BUTTON_LEFT_FACE_UP))
                    up = true;
                if (IsGamepadButtonPressed(gp, GAMEPAD_BUTTON_LEFT_FACE_DOWN))
                    down = true;
            }
        }
        int n = static_cast<int>(songs.size());
        if (up)
        {
            if (selected_index > 0)
                selected_index--;
            else if (scroll_offset > 0)
                scroll_offset--;
            else
            {
                scroll_offset = n > VISIBLE_SLOTS ? n - VISIBLE_SLOTS : 0;
                selected_index = n > VISIBLE_SLOTS ? VISIBLE_SLOTS - 1 : n - 1;
            }
        }
        if (down)
        {
            if (selected_index < VISIBLE_SLOTS - 1 && scroll_offset + selected_index < n - 1)
                selected_index++;
            else if (scroll_offset + VISIBLE_SLOTS < n)
                scroll_offset++;
            else
            {
                scroll_offset = 0;
                selected_index = 0;
            }
        }

        bool confirm = IsKeyPressed(KEY_ENTER);
        for (int gp = 0; gp < 4; gp++)
        {
            if (IsGamepadAvailable(gp) && IsGamepadButtonPressed(gp, GAMEPAD_BUTTON_MIDDLE_RIGHT))
                confirm = true;
        }
        if (confirm && !songs.empty())
        {
            int idx = scroll_offset + selected_index;
            if (idx >= 0 && idx < static_cast<int>(songs.size()))
            {
                SELECTED_SONG_PATH = songs[idx].path;
                SELECTED_TRACK_OVERRIDE = songs[idx].track_override;
                game->go_to_scene("instrument_select");
            }
        }
    }

    void draw() override
    {
        float w = static_cast<float>(GetScreenWidth());
        float h = static_cast<float>(GetScreenHeight());

        ClearBackground(SKYBLUE);

        const char* title_text = "Select Song";
        float title_size = 48.0f;
        float title_w = MeasureTextEx(font, title_text, title_size, 1.0f).x;
        DrawTextEx(font, title_text, Vector2{(w - title_w) * 0.5f, 60.0f}, title_size, 1.0f, WHITE);

        float row_height = 80.0f;
        float start_y = 180.0f;
        float list_center_x = w * 0.5f;
        float name_size = 28.0f;
        float artist_size = 18.0f;
        float artist_offset_x = 0.0f;
        Color highlight_bg = {60, 80, 120, 220};
        Color highlight_border = {100, 130, 180, 255};
        float content_height = name_size + 4.0f + artist_size;
        float box_pad_v = 6.0f;
        float highlight_height = content_height + box_pad_v * 2.0f;

        for (int i = 0; i < VISIBLE_SLOTS; i++)
        {
            int list_idx = scroll_offset + i;
            float y = start_y + i * row_height;
            bool selected = (i == selected_index);

            if (list_idx < static_cast<int>(songs.size()))
            {
                const SongEntry& e = songs[list_idx];
                if (selected)
                {
                    float box_w = w * 0.45f;
                    float box_x = (w - box_w) * 0.5f;
                    float box_y = y - box_pad_v;
                    DrawRectangleRounded(
                        Rectangle{box_x, box_y, box_w, highlight_height}, 0.2f, 12, highlight_bg);
                    DrawRectangleRoundedLines(
                        Rectangle{box_x, box_y, box_w, highlight_height}, 0.2f, 12,
                        highlight_border);
                }
                float name_w = MeasureTextEx(font, e.name.c_str(), name_size, 1.0f).x;
                DrawTextEx(font, e.name.c_str(),
                          Vector2{list_center_x - name_w * 0.5f, y}, name_size, 1.0f, WHITE);
                if (!e.artist.empty())
                {
                    float artist_w = MeasureTextEx(font, e.artist.c_str(), artist_size, 1.0f).x;
                    DrawTextEx(font, e.artist.c_str(),
                              Vector2{list_center_x - artist_w * 0.5f + artist_offset_x,
                                      y + name_size + 4.0f},
                              artist_size, 1.0f, Color{200, 200, 200, 255});
                }
            }
        }

        const char* hint = "D-Pad Up/Down  |  Start to confirm";
        float hint_size = 20.0f;
        float hint_w = MeasureTextEx(font, hint, hint_size, 1.0f).x;
        DrawTextEx(font, hint, Vector2{(w - hint_w) * 0.5f, h - 50.0f}, hint_size, 1.0f, WHITE);
    }
};
