#include "hero.hpp"
// #include <render/primitives.h>
#include <app.hpp>
#include <color.h>
#include "../world.hpp"
#include "../equipment/regularGun.h"
#include "../equipment/burstGun.hpp"
#include "../equipment/tripleGun.hpp"
#include "enemyBullet.hpp"
#include "powerup.hpp"

namespace game {
namespace entity {

Hero::Hero(World *world) noexcept: Entity(world)
{
    this->position = vec2f(2, 8.5);
    this->speed = 10;
    this->direction = false;

    this->body = world->CreateBody(this->position, b2_dynamicBody);

    b2CircleShape shape;
    shape.m_radius = 0.2;

    b2FixtureDef fixDef;
    fixDef.filter.categoryBits = TYPE_HERO;
    fixDef.filter.maskBits = TYPE_WALL | TYPE_ENEMY | TYPE_EBULLET;
    fixDef.shape = &shape;
    fixDef.density = 1.0f;
    fixDef.userData = this;

    this->fixture = this->body->CreateFixture(&fixDef);

    b2PolygonShape powerUpTrigger;
    powerUpTrigger.SetAsBox(1, 0.5);

    fixDef.filter.categoryBits = TYPE_TRIGGER;
    fixDef.filter.maskBits = TYPE_POWERUP;
    fixDef.shape = &powerUpTrigger;
    fixDef.density = 1.0f;
    fixDef.userData = this;
    fixDef.isSensor = true;

    this->body->CreateFixture(&fixDef);

    this->weapon = new equipment::RegularGun();

    this->health = 3;
    this->damageUpTimer = 0;
    this->invisibleTimer = 5;

    App::atlas->getIcon("hero.png", this->icons[0]);
    App::atlas->getIcon("hero-hurt.png", this->icons[1]);
    App::atlas->getIcon("health.png", this->icons[2]);
    App::atlas->getIcon("dmgup.png", this->icons[3]);

    for (auto &i: this->icons) {
        i.scale = vec2f(1 / 16.0);
    }
}

Hero::~Hero() noexcept
{
    delete this->weapon;
}

void Hero::Update() noexcept
{
    vec2f velocity;

    this->weapon->Update();

    b2Filter filter = this->fixture->GetFilterData();

    uint16 oldMask = filter.maskBits;

    if (this->invisibleTimer > 0) {
        this->invisibleTimer -= App::GetInput()->deltaTime;
        filter.maskBits = TYPE_WALL;
    } else {
        filter.maskBits = TYPE_WALL | TYPE_ENEMY | TYPE_EBULLET;
    }

    this->fixture->SetFilterData(filter);

    if (this->damageUpTimer > 0) {
        this->damageUpTimer -= App::GetInput()->deltaTime;
    }

    const Input *input = App::GetInput();



    if (input->IsButtonPressed(SCE_CTRL_UP)) {
        velocity.y -= 1;
    }
    if (input->IsButtonPressed(SCE_CTRL_DOWN)) {
        velocity.y += 1;
    }

    if (input->IsButtonPressed(SCE_CTRL_LEFT)) {
        velocity.x -= 1;
    }
    if (input->IsButtonPressed(SCE_CTRL_RIGHT)) {
        velocity.x += 1;
    }

    if (input->IsButtonJustPressed(SCE_CTRL_CIRCLE)) {
        this->direction = !this->direction;
    }

    if (input->IsButtonPressed(SCE_CTRL_CROSS)) {
        this->weapon->Shoot(this->position + vec2f{0.5, 0}, this->direction, this->world, this->damageUpTimer > 0);
    }

    if (velocity.length() > 0.1) {
        velocity = velocity.normalize() * this->speed;
        this->body->SetLinearVelocity(b2Vec2(velocity.x, velocity.y));
    } else {
        this->body->SetLinearVelocity(b2Vec2(0,0));
    }

    this->position.x = this->body->GetPosition().x;
    this->position.y = this->body->GetPosition().y;
}

vec2f Hero::GetPosition() const noexcept
{
    return this->position;
}

void Hero::OnCollide(Entity *entity)
{

    if (this->invisibleTimer <= 0) {
        if (dynamic_cast<Enemy*>(entity) || dynamic_cast<EnemyBullet*>(entity)) {
            this->invisibleTimer = 5;
            this->health--;

            if (this->health < 0) {
                this->world->GameOver();
            }

            return;
        }
    }

    PowerUp *powerup = dynamic_cast<PowerUp*>(entity);

    if (powerup) {
        switch (powerup->type) {
        case POWERUP_WEAPON_1:
            delete this->weapon;
            this->weapon = new equipment::RegularGun();
            break;
        case POWERUP_WEAPON_2:
            delete this->weapon;
            this->weapon = new equipment::BurstGun();
            break;
        case POWERUP_WEAPON_3:
            delete this->weapon;
            this->weapon = new equipment::TripleGun();
            break;
        case POWERUP_DAMAGE_UP:
            this->damageUpTimer = 20;
            break;
        case POWERUP_HEAL:
            if (this->health < 6) {
                this->health++;
            }
            break;
        }
    }

}

void Hero::Render() noexcept
{
    for (int i = 0; i < this->health; i++) {
        this->icons[2].draw(vec2f{i + 1, 0.5});
    }

    // render::primitives2d::quad(this->position - vec2f(1, 0.5), vec2f(2, 1), color::cyan);

    // this->shield->Render(this->position, vec2f(2, 1));

    int iconNumber = 0;

    if (this->invisibleTimer > 0) {
        iconNumber = 1;
    }
    if (this->direction && this->icons[iconNumber].scale.x > 0 || !this->direction && this->icons[iconNumber].scale.x < 0) {
        this->icons[iconNumber].scale.x *= -1;
    }

    this->icons[iconNumber].draw(this->position);

    if (this->damageUpTimer > 0) {
        this->icons[3].draw(this->position);
    }

    /*if (this->direction) {
        render::primitives2d::quad(this->position + vec2f(-1, -.25), vec2f(0.1, 0.5), color::red);
    } else {
        render::primitives2d::quad(this->position + vec2f(.9, -.25), vec2f(0.1, 0.5), color::red);
    }*/
}


}
}
