#include "game_logic.h"

#include <algorithm>
#include <cstdlib>

#include <consts.h>

void update_snake(GameState &state) {
    std::array<int, 3> headpos = state.snake.front();
    std::array<int, 3> newHead = headpos;

    if (state.snakeDirection == 0) {
        newHead = { headpos[0], headpos[1] - 1, state.snakeDirection };
    } else if (state.snakeDirection == 1) {
        newHead = { headpos[0] + 1, headpos[1], state.snakeDirection };
    } else if (state.snakeDirection == 2) {
        newHead = { headpos[0], headpos[1] + 1, state.snakeDirection };
    } else if (state.snakeDirection == 3) {
        newHead = { headpos[0] - 1, headpos[1], state.snakeDirection };
    }

    if (newHead[0] > X_MAX) {
        newHead[0] = 0;
    }
    if (newHead[1] > Y_MAX) {
        newHead[1] = 0;
    }
    if (newHead[0] < 0) {
        newHead[0] = X_MAX;
    }
    if (newHead[1] < 0) {
        newHead[1] = Y_MAX;
    }

    state.snake.push_front(newHead);
    state.snake.resize(state.snakelength);
}

bool check_collision_self(GameState &state) {
    if (state.snake.size() < 2 || state.gameOver) {
        return false;
    }

    const std::array<int, 3> headpos = state.snake.front();

    for (auto it = state.snake.begin() + 1; it != state.snake.end(); ++it) {
        if ((*it)[0] == headpos[0] && (*it)[1] == headpos[1]) {
            state.gameOver = true;
            return true;
        }
    }

    return false;
}

bool check_collision_apples(GameState &state) {
    const std::array<int, 3> headpos = state.snake.front();

    auto it = std::find_if(state.apples.begin(), state.apples.end(), [&](const std::array<int, 2> &apple) {
        return apple[0] == headpos[0] && apple[1] == headpos[1];
    });

    if (it == state.apples.end()) {
        return false;
    }

    state.score += APPLE_SCORE;
    state.snakelength++;
    state.apples.erase(it);
    return true;
}

bool check_collision_apples_rotten(GameState &state) {
    const std::array<int, 3> headpos = state.snake.front();

    auto it = std::find_if(state.bad_apples.begin(), state.bad_apples.end(), [&](const std::array<int, 2> &apple) {
        return apple[0] == headpos[0] && apple[1] == headpos[1];
    });

    if (it == state.bad_apples.end()) {
        return false;
    }

    state.snakelength--;
    state.bad_apples.erase(it);
    if (state.snakelength < 2) {
        state.gameOver = true;
    }
    return true;
}

void spawn_apples(GameState &state) {
    if (state.apples.size() < 1) {
        std::array<int, 2> apple = { rand() % (X_MAX + 1), rand() % (Y_MAX + 1) };
        state.apples.push_back(apple);
    }
}

void spawn_apples_rotten(GameState &state) {
    if ((state.ticks % 10 == 0) && state.hardMode && ((rand() % 10) < 10) && (state.bad_apples.size() < 20)) {
        std::array<int, 2> badApple = { rand() % (X_MAX + 1), rand() % (Y_MAX + 1) };
        state.bad_apples.push_back(badApple);
    }
}
