#include "gui.hpp"

#include "../model/utils/utils.hpp"

#include <SFML/Graphics/Color.hpp>
#include <SFML/System/Vector2.hpp>

GUI::GUI() {
    window.create(sf::VideoMode(WINDOW_SIZE, WINDOW_SIZE), "Chess Board");
    load_textures();

    font.loadFromFile("res/arial.ttf");
}

void GUI::update_board(
    const Board& b, int8_t selected_square, std::vector<int8_t> targets
) {
    window.clear();
    draw_board(selected_square, targets);
    draw_pieces(b);
    window.display();
}

void GUI::notify_stalemate(Colour col) {
    std::cout << "Stalemate for " << to_string(col) << std::endl;
}

void GUI::notify_checkmate(Colour col) {
    std::cout << "Checkmate for " << to_string(col) << std::endl;
}

void GUI::handle_events() {
    sf::Event event;
    while (window.pollEvent(event))
        if (event.type == sf::Event::Closed)
            window.close();
        else if (event.type == sf::Event::MouseButtonPressed)
            handle_click(event.mouseButton.x, event.mouseButton.y);
}

void GUI::load_textures() {
    const std::string names[6] =
        {"rook", "knight", "bishop", "queen", "king", "pawn"
        }; // don't touch the order, it's reflecting the one in the Piece enum
    for (int i = 0; i < 6; ++i) {
        textures[i][0].loadFromFile("res/pieces/white-" + names[i] + ".png");
        textures[i][1].loadFromFile("res/pieces/black-" + names[i] + ".png");
    }
}

void GUI::handle_click(int x, int y) {
    int file = x / TILE_SIZE;
    int rank = 7 - (y / TILE_SIZE);
    controller->on_tile_selected(file, rank);
}

void GUI::draw_annotation(int file, int rank) {
    if (file == 0) {
        sf::Text annotation(std::to_string(rank + 1), font);
        annotation.setStyle(sf::Text::Bold);
        annotation.setCharacterSize(16);
        annotation.setFillColor(rank % 2 == 0 ? colours[1] : colours[0]);
        annotation.setPosition(
            (file + .05) * TILE_SIZE,
            (7 - rank + .05) * TILE_SIZE
        );
        window.draw(annotation);
    }

    if (rank == 0) {
        sf::Text annotation("abcdefgh"[file], font);
        annotation.setCharacterSize(16);
        annotation.setOrigin(16, 16);
        annotation.setStyle(sf::Text::Bold);
        annotation.setFillColor(file % 2 == 0 ? colours[1] : colours[0]);
        annotation.setPosition(
            (file + 1) * TILE_SIZE,
            (7 - rank + .95) * TILE_SIZE
        );
        window.draw(annotation);
    }
}

void GUI::draw_board(int selected_square, std::vector<int8_t> targets) {
    sf::RectangleShape square(sf::Vector2f(TILE_SIZE, TILE_SIZE));
    for (int rank = 0; rank < 8; ++rank) {
        for (int file = 0; file < 8; ++file) {
            int8_t index = Coords{file, rank}.to_index();
            square.setPosition(file * TILE_SIZE, (7 - rank) * TILE_SIZE);
            if (index == selected_square)
                square.setFillColor(
                    (file + rank) % 2 == 0 ? alt_colours[0] : alt_colours[1]
                );
            else
                square.setFillColor(
                    (file + rank) % 2 == 0 ? colours[0] : colours[1]
                );
            window.draw(square);
            draw_annotation(file, rank);

            if (std::find(targets.begin(), targets.end(), index)
                != targets.end()) {
                float r = .15 * TILE_SIZE;
                sf::CircleShape circle{r};
                sf::Color c(0x00000055);
                circle.setFillColor(c);
                circle.setOrigin(r, r);
                circle.setPosition(
                    (file + .5) * TILE_SIZE,
                    (7 - rank + .5) * TILE_SIZE
                );
                window.draw(circle);
            }
        }
    }
}

void GUI::draw_pieces(const Board& board) {
    for (int i = 0; i < 64; ++i) {
        int piece = board.piece_at(i);
        if (piece != Piece::None) {
            int colour = board.colour_at(i) == Colour::White ? 0 : 1;
            pieces[i].setTexture(textures[piece - 1][colour]);

            sf::Vector2 center = textures[piece - 1][colour].getSize() / 2u;
            pieces[i].setOrigin(center.x, center.y);

            pieces[i].setPosition(
                (i % 8 + .5) * TILE_SIZE,
                (7 - (int) (i / 8) + .5) * TILE_SIZE
            );
            window.draw(pieces[i]);
        }
    }
}

int GUI::show_popup(
    const std::string& message, const std::vector<std::string>& options
) {
    sf::RenderWindow popup(sf::VideoMode(300, 200), "Choice");
    sf::Font font;

    if (!font.loadFromFile("res/arial.ttf")) {
        std::cerr << "Error: Could not load font!" << std::endl;
        return -1;
    }

    sf::Text text(message, font, 20);
    text.setPosition(20, 20);
    text.setFillColor(sf::Color::Black);

    std::vector<sf::RectangleShape> buttonShapes;
    std::vector<sf::Text> buttonTexts;

    for (size_t i = 0; i < options.size(); ++i) {
        sf::RectangleShape button(sf::Vector2f(200, 30));
        button.setPosition(50, 70 + i * 40);
        button.setFillColor(sf::Color(150, 150, 150));
        buttonShapes.push_back(button);

        sf::Text buttonText(options[i], font, 18);
        buttonText.setPosition(60, 75 + i * 40);
        buttonText.setFillColor(sf::Color::Black);
        buttonTexts.push_back(buttonText);
    }

    while (popup.isOpen()) {
        sf::Event event;
        while (popup.pollEvent(event)) {
            if (event.type == sf::Event::Closed)
                popup.close();
            else if (event.type == sf::Event::MouseButtonPressed) {
                for (size_t i = 0; i < buttonShapes.size(); ++i) {
                    if (buttonShapes[i].getGlobalBounds().contains(
                            event.mouseButton.x,
                            event.mouseButton.y
                        )) {
                        popup.close();
                        return i;
                    }
                }
            }
        }

        popup.clear(sf::Color::White);
        popup.draw(text);
        for (size_t i = 0; i < buttonShapes.size(); ++i) {
            popup.draw(buttonShapes[i]);
            popup.draw(buttonTexts[i]);
        }
        popup.display();
    }
    return -1;
}

Piece GUI::ask_about_promotion() {
    std::vector<std::string> options = {"Queen", "Rook", "Bishop", "Knight"};
    int idx = show_popup("Please choose a promotion for your pawn", options);
    switch (idx) {
    case 0:
        return Queen;
    case 1:
        return Rook;
    case 2:
        return Bishop;
    case 3:
        return Knigt;
    };
    return Piece::None;
}

void GUI::show() {
    while (window.isOpen())
        handle_events();
}