#include "programmer.h"
#include "debuggers.h"
#include "olcPGEX_Sound.h"
#include <iostream>

namespace pabloader {
Programmer::Programmer(Debuggers* game)
    : Entity(game, &game->playerSprite)
{
    pos = { (float)(game->ScreenWidth() - size.x) / 2, (float)size.y / 2 };

#ifdef _DEBUG
    DEBUG_COLOR = olc::GREEN;
#endif
}

void Programmer::Think()
{
    Bug* closest = nullptr;
    float dist = 1e100;
    for (auto& bug : game->bugs) {
        float d = bug->Dist(this);
        if (d < dist && bug->IsInScreen() && bug->IsAlive()) {
            dist = d;
            closest = bug;
        }
    }

    if (closest != nullptr) {
#ifdef _DEBUG
        target.x = closest->GetX();
        target.y = closest->GetY();
#endif
        doJump = closest->GetY() < pos.y;
        moveDown = closest->GetY() > pos.y;
        walkLeft = closest->GetX() < pos.x;
        walkRight = closest->GetX() > pos.x;
    } else {
#ifdef _DEBUG
        target.x = 0;
        target.y = 0;
#endif
        doJump = false;
        walkLeft = false;
        walkRight = false;
        moveDown = false;
    }
}

void Programmer::Update(float dt)
{
    pos += vel * dt;

    vel.x *= 1 - 0.2 * dt;

    if (!onGround) {
        vel.y += (70 + tile.x * 30) * dt;
        vel.y *= 1 - 0.05 * dt;
    } else {
        vel.x *= 1 - 3 * dt;
    }

    transform.Reset();

    bool userInput = false;

    if (doJump && onGround) {
        vel.y = -100 - tile.x * 30;
        userInput = true;
    }

    if (walkLeft) {
        vel.x -= (150 + tile.x * 30) * dt;
        userInput = true;
    }

    if (walkRight) {
        vel.x += (150 + tile.x * 30) * dt;
        userInput = true;
    }

    if (moveDown) {
        if (!onGround) {
            vel.y += (150 + tile.x * 30) * dt;
        }
        userInput = true;
    }

    if (pos.x > game->ScreenWidth() - size.x / 2) {
        vel.x *= -0.3;
        pos.x = game->ScreenWidth() - size.x / 2;
        if (game->GetState() == STATE_GAME)
            olc::SOUND::PlaySample(game->playerFallSample);
    }

    if (pos.x < size.x / 2) {
        vel.x *= -0.3;
        pos.x = size.x / 2;
        if (game->GetState() == STATE_GAME)
            olc::SOUND::PlaySample(game->playerFallSample);
    }

    auto groundLevel = game->GameScreenHeight() - size.y / 2 - 1;

    if (pos.y > groundLevel) {
        vel.y *= -0.3;

        if (std::abs(vel.y) < 2) {
            vel.y = 0;
        }
        pos.y = groundLevel;
    }

    bool newOnGround = pos.y >= groundLevel;
    if (newOnGround && !onGround && game->GetState() == STATE_GAME) {
        olc::SOUND::PlaySample(game->playerFallSample);
    }
    onGround = newOnGround;

    if (onGround) {
        tile.y = 2;
        tileCounter = static_cast<uint32_t>(0.1 / dt);
    } else if (tileCounter <= 0) {
        tile.y = 0;
    } else {
        tileCounter--;
    }

    if (!userInput && std::abs(vel.x) < 2) {
        vel.x = 0;
    }
    if (walkLeft) {
        transform.Scale(-1, 1);
    }
    transform.Translate(pos.x, pos.y);
}

void Programmer::Draw()
{
    game->SetPixelMode(olc::Pixel::MASK);
    int xOff = walkLeft ? -1 : 0;
    if (walkLeft || walkRight) {
        olc::GFX2D::DrawPartialSprite(&game->playerSprite, tile.x * size.x + xOff, 0 + tile.y * size.y, size.x - xOff, size.y, transform, true);
    } else {
        olc::GFX2D::DrawPartialSprite(&game->playerSprite, tile.x * size.x + xOff, size.y + tile.y * size.y, size.x - xOff, size.y, transform, true);
    }
    game->SetPixelMode(olc::Pixel::NORMAL);
#ifdef _DEBUG
    if (game->debug) {
        game->DrawRect(pos.x - size.x / 2, pos.y - size.y / 2, size.x, size.y, DEBUG_COLOR);
        if (target.x != 0 || target.y != 0) {
            game->DrawLine(pos.x, pos.y, target.x, target.y, DEBUG_COLOR);
        }
    }
#endif
}
}