#pragma once

#include "core/script.hpp"

#include "constants.hpp"


struct ball_script : frog::script
{
    frog::geo::vec3 vector{ 0 };

    void init(frog::game_object& obj, frog::engine&) override
    {
        using namespace frog;

        obj.model().pos = { 0, Ball::Radius, 0 };
    }

    void stable_update(frog::game_object& obj, frog::engine& engine) override
    {
        using namespace frog;

        obj.model().pos += vector * engine.global->stable_frame_time();

        float radius = Ball::Radius;

        auto polar_pos = geo::to_cylindrical(obj.model().pos);

        bool bounced = false;

        auto bounce = [&](auto& wall)
        {
            if (bounced)
                return;

            auto found = wall.get_script<bounce_script>();

            if (!found)
                return;

            auto paddle = found->paddle;

            auto collision = geo::collision_2D(paddle, polar_pos, radius);

            if (collision)
            {
                bounced = true;

                float len = vector.length();
                vector = geo::reflect(vector, collision->normal);
                vector.normalize() *= len;

                obj.model().pos = collision->resolved;

                auto is_wall = wall.get_script<wall_script>();
                if (is_wall)
                {
                    wall.destroy();
                }
            }
        };

        engine.scenes->current()
            .for_each_object(frog::by_tag("paddle"), bounce);

        engine.scenes->current()
            .for_each_object(frog::by_tag("wall"), bounce);
    }

    void shoot(frog::geo::vec3 normal)
    {
        vector = normal;
        vector.normalize() *= Ball::Speed;
    }

    void frame_update(frog::game_object&, frog::engine&) override {}

    void destroyed(frog::game_object&, frog::engine&) override {}
};
