#include "missile.hpp"

#include <cmath>

#include "state.hpp"
#include "player.hpp"
#include "ship.hpp"
#include "planet.hpp"
#include "trace.hpp"

#include <glm/gtx/norm.hpp>

namespace game {
    Missile::Missile(size_t id, Player *player, const glm::vec2 &pos, float angle, float speed)
        : Object(id, pos)
        , player(player)
    {
        velocity = speed * glm::vec2(std::sin(angle), std::cos(angle));

        //std::cout << "spawned missile for player " << playerId << " @ ("
        //    << pos.x << ", " << pos.y << ") speed = " << speed << std::endl;
    }

    Missile::~Missile()
    {
        //std::cout<<"~Missile" << std::endl;
    }

    Missile::Event Missile::advance(const game::State *state, float dt)
    {
        glm::vec2 gravityForce = glm::vec2(0.0, 0.0);

        for (const Player *other : state->players) {
            if (other->ship != nullptr && other != player) {
                glm::vec2 diff = other->ship->position - position;
                float dist = glm::length(diff);
                if (dist <= other->ship->radius) {
                    // TODO: collect all hits and return the first one only
                    // TODO: find exact hit position!
                    return Missile::Event(position, velocity, player->id, other->id);
                }
            }
        }

        // get forces
        for (const Planet *planet : state->planets) {
            glm::vec2 diff = planet->position - position;
            float dist = glm::length(diff);
            if (dist <= planet->radius) {
                // TODO: collect all hits and return the first one only
                // TODO: find exact hit position!
                return Missile::Event(position, velocity, planet->id);
            }

            dist *= 20.0;
            if (dist > 0.001) {
                float G = 0.1;
                gravityForce += G * diff / (1.0f + dist*dist);
            }
        }

        // simple (and bad) euler integration.
        position += 0.5f * gravityForce*dt*dt + velocity*dt;
        velocity += gravityForce * dt;

        //const float thr = 0.01;
        //float s = glm::length(velocity);
        //if (s > thr) {
        //    velocity = glm::normalize(velocity) * thr;
        //}

        glm::vec2 nextPos = position + velocity;

        // TODO: collision checks
        position = nextPos;

        // check if distance to center of the universe is getting too big
        float distToCenter = glm::length(position);
        if (distToCenter > state->maxMissileDistance()) {
            return Missile::Event(position, velocity, Hit::BorderOfUniverse);
        }

        return Missile::Event(position, velocity);
    }
}
