#include <cmath>
#include <iostream>

#include "bonus.hpp"
#include "arkanoid.hpp"
#include "ball.hpp"
#include "paddle.hpp"

/* =============
 * ===Bonuses===
 * =============
 * */

Bonus::Bonus(sf::Vector2f position): m_position(position)
{
    m_time = 0;
}

void Bonus::update(float dt)
{
    m_time += dt;
    m_position.y += speed * dt;
}

bool Bonus::isColiding(const Paddle& paddle) const
{
    bool result = paddle.getBorder().intersects({m_position.x - radius, m_position.y - radius, 2 * radius, 2 * radius});
    return result;
}

/* 
 * TripleBallBonus 
 * */
void TripleBallBonus::draw(sf::RenderWindow& window) const
{
    static sf::CircleShape shape(radius);
    shape.setOrigin(radius, radius);
    shape.setFillColor(sf::Color{100, 200, 100});
    shape.setPosition(m_position);
    window.draw(shape);

    float angle = 0;

    static Ball ball {5, {0, 0}, {0, 0}};
    float ballRotationRadius = 7;
    ball.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle));
    ball.draw(window);
    angle += 2.0 * M_PI / 3.0;
    ball.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle));
    ball.draw(window);
    angle += 2.0 * M_PI / 3.0;
    ball.position = m_position + ballRotationRadius * sf::Vector2f(std::cos(angle), std::sin(angle));
    ball.draw(window);
}

void TripleBallBonus::activate(Arkanoid& game)
{
    int numBalls = game.m_balls.size();
    std::list<Ball>::iterator it = game.m_balls.begin();

    bool isSlowed = false;
    bool toApply = true;

    Effect* slowing_effect = nullptr;
    for (auto it = game.m_effects.begin(); it != game.m_effects.end();) {
        if ((*it)->effectId == _EFFECT_SLOWING_ID) {
            isSlowed = true;
            slowing_effect = *it;
            break;
        }
        it++;
    }
    for (int i = 0; i < numBalls; i++)
    {
        float angle, vx, vy;
        if (game.isMaxBalls()) {
            toApply = false;
        }

        if (toApply) {
            angle = rand() % 1000 * (2 * M_PI / 1000);
            vx = Ball::initialVelocity * sin(angle);
            vy = Ball::initialVelocity * cos(angle);
            game.addBall({game.m_initialBall.radius, (*it).position, {vx, vy}});
            
            if (isSlowed) {
                slowing_effect->activate(game.m_balls.back()); 
            }
        }

        if (game.isMaxBalls()) {
            toApply = false;
        }

        if (toApply) {
            angle = rand() % 1000 * (2 * M_PI / 1000);
            vx = Ball::initialVelocity * sin(angle);
            vy = Ball::initialVelocity * cos(angle);
            game.addBall({game.m_initialBall.radius, (*it).position, {vx, vy}});
            if (isSlowed) {
                slowing_effect->activate(game.m_balls.back()); 
            }
        }

        it++;
    }
}

/* 
 * EnlargePaddleBonus 
 * */
void EnlargePaddleBonus::draw(sf::RenderWindow& window) const
{
    static sf::CircleShape shape(radius);
    shape.setOrigin(radius, radius);
    shape.setFillColor(sf::Color{100, 200, 100});
    shape.setPosition(m_position);
    window.draw(shape);

    static sf::RectangleShape rect(sf::Vector2f{radius, radius / 2}); 
    rect.setFillColor(sf::Color::Green);
    rect.setPosition(m_position - sf::Vector2f{radius /2, radius / 4});
    window.draw(rect);
}

void EnlargePaddleBonus::activate(Arkanoid& game)
{
   if (game.m_paddle.size.x < 300) {
       game.m_paddle.size.x *= 1.5; 
   }
}

/*
 * ShrinkPaddleBonus
 * */
void ShrinkPaddleBonus::draw(sf::RenderWindow& window) const
{
    static sf::CircleShape shape(radius);
    shape.setOrigin(radius, radius);
    shape.setFillColor(sf::Color{100, 200, 100});
    shape.setPosition(m_position);
    window.draw(shape);

    static sf::RectangleShape rect(sf::Vector2f{radius, radius / 2});
    rect.setFillColor(sf::Color::Red);
    rect.setPosition(m_position - sf::Vector2f{radius /2, radius / 4});
    window.draw(rect);
}
void ShrinkPaddleBonus::activate(Arkanoid& game)
{
   if (game.m_paddle.size.x > 40) {
        game.m_paddle.size.x *= 0.8;
   }
}

/*
 * SlowingBonus
 * */

void SlowingBonus::draw(sf::RenderWindow& window) const
{
    static sf::CircleShape shape(radius);
    shape.setOrigin(radius, radius);
    shape.setFillColor(sf::Color{100, 200, 100});
    shape.setPosition(m_position);
    window.draw(shape);

    static sf::CircleShape clock(radius / 2);
    clock.setOutlineColor(sf::Color::Red);
    clock.setOutlineThickness(3);
    clock.setPosition(m_position - sf::Vector2f{radius /2, radius / 2});
    window.draw(clock);
}

void SlowingBonus::activate(Arkanoid& game)
{
    bool isAlreadySlowed = false;
    for (auto it = game.m_effects.begin(); it != game.m_effects.end();) {
        if ((*it)->effectId == _EFFECT_SLOWING_ID) {
            (*it)->mDuration += mDuration;
            isAlreadySlowed = true;
            break;
        }
        it++;
    }
    if (!isAlreadySlowed) {
        game.m_effects.push_back(new SlowingEffect(game.m_time, mDuration));
        game.m_effects.back()->activate(game);
    }
}

/* =============
 * ===Effects===
 * =============
 * */

Effect::Effect(char id, double start_time, double duration) : effectId(id), mStartTime(start_time), mDuration(duration) {};

bool Effect::isExpired(double time) {
    if (mStartTime + mDuration > time)
            return false;
    return true;
} 

SlowingEffect::SlowingEffect(double start_time, double duration) : Effect(_EFFECT_SLOWING_ID, start_time, duration) {};

void SlowingEffect::activate(Arkanoid& game) {
    for (Ball& ball : game.m_balls) {
            ball.velocity = sf::Vector2f{ball.velocity.x * mSlowingFactor, ball.velocity.y * mSlowingFactor};
    }
}
void SlowingEffect::activate(Ball& ball) {
    ball.velocity = sf::Vector2f{ball.velocity.x * mSlowingFactor, ball.velocity.y * mSlowingFactor};
}

void SlowingEffect::deactivate(Arkanoid& game) {
    for (Ball& ball : game.m_balls) {
        ball.velocity = sf::Vector2f{ball.velocity.x / mSlowingFactor, ball.velocity.y / mSlowingFactor};
    }
}

