// collision_system.cpp - Implementación del sistema de colisiones

#include "game/systems/collision_system.hpp"

#include <cstdint>

#include "core/audio/audio.hpp"
#include "core/physics/collision.hpp"
#include "core/types.hpp"

namespace Systems::Collision {

void detectBulletEnemy(Context& ctx) {
    constexpr float AMPLIFIER = Defaults::Game::COLLISION_BULLET_ENEMY_AMPLIFIER;
    constexpr float VELOCITAT_EXPLOSIO = 80.0F;  // px/s (explosión suau)

    for (auto& bullet : ctx.bullets) {
        for (auto& enemy : ctx.enemies) {
            if (!Physics::check_collision(bullet, enemy, AMPLIFIER)) {
                continue;
            }

            // *** COLISIÓN bullet → enemy ***
            const Vec2& POS_ENEMIC = enemy.getCenter();

            // 1. Puntos según tipo
            int points = 0;
            switch (enemy.getType()) {
                case EnemyType::PENTAGON:
                    points = Defaults::Enemies::Scoring::PENTAGON_SCORE;
                    break;
                case EnemyType::QUADRAT:
                    points = Defaults::Enemies::Scoring::QUADRAT_SCORE;
                    break;
                case EnemyType::MOLINILLO:
                    points = Defaults::Enemies::Scoring::MOLINILLO_SCORE;
                    break;
            }

            uint8_t owner_id = bullet.getOwnerId();
            ctx.score_per_player[owner_id] += points;
            ctx.floating_score_manager.crear(points, POS_ENEMIC);

            // 2. Destruir enemy + crear explosión (debris hereda color del enemy)
            SDL_Color enemy_color{};
            switch (enemy.getType()) {
                case EnemyType::PENTAGON:  enemy_color = Defaults::Palette::PENTAGON;  break;
                case EnemyType::QUADRAT:   enemy_color = Defaults::Palette::QUADRAT;   break;
                case EnemyType::MOLINILLO: enemy_color = Defaults::Palette::MOLINILLO; break;
            }
            enemy.destruir();
            Vec2 vel_enemic = enemy.getVelocityVector();
            ctx.debris_manager.explode(
                enemy.getShape(),
                POS_ENEMIC,
                0.0F,                  // angle (la rotación es interna del enemy)
                1.0F,                  // escala
                VELOCITAT_EXPLOSIO,
                enemy.getBrightness(),
                vel_enemic,
                enemy.getRotationDelta(),
                0.0F,                  // sin herencia visual
                Defaults::Sound::EXPLOSION,
                enemy_color
            );

            // 3. Desactivar bullet (solo destruye 1 enemy)
            bullet.desactivar();
            break;
        }
    }
}

void detectShipEnemy(Context& ctx) {
    constexpr float AMPLIFIER = Defaults::Game::COLLISION_SHIP_ENEMY_AMPLIFIER;

    for (uint8_t i = 0; i < 2; i++) {
        // Skip si ya tocado / muerto / invulnerable
        if (ctx.hit_timer_per_player[i] > 0.0F ||
            !ctx.ships[i].isAlive() ||
            ctx.ships[i].isInvulnerable()) {
            continue;
        }

        for (const auto& enemy : ctx.enemies) {
            if (enemy.isInvulnerable()) {
                continue;
            }
            if (Physics::check_collision(ctx.ships[i], enemy, AMPLIFIER)) {
                ctx.on_player_hit(i);
                break;  // Solo una colisión por player por frame
            }
        }
    }
}

void detectBulletPlayer(Context& ctx) {
    if (!Defaults::Game::FRIENDLY_FIRE_ENABLED) {
        return;
    }

    constexpr float AMPLIFIER = Defaults::Game::COLLISION_BULLET_PLAYER_AMPLIFIER;

    for (auto& bullet : ctx.bullets) {
        if (!bullet.esta_activa() || bullet.getGraceTimer() > 0.0F) {
            continue;
        }
        const uint8_t BULLET_OWNER = bullet.getOwnerId();

        for (uint8_t player_id = 0; player_id < 2; player_id++) {
            if (ctx.hit_timer_per_player[player_id] > 0.0F ||
                !ctx.ships[player_id].isAlive() ||
                ctx.ships[player_id].isInvulnerable()) {
                continue;
            }
            const bool JUGADOR_ACTIU = (player_id == 0)
                ? ctx.match_config.jugador1_actiu
                : ctx.match_config.jugador2_actiu;
            if (!JUGADOR_ACTIU) {
                continue;
            }

            if (!Physics::check_collision(bullet, ctx.ships[player_id], AMPLIFIER)) {
                continue;
            }

            // *** FRIENDLY FIRE HIT ***
            if (BULLET_OWNER == player_id) {
                // Self-hit: víctima pierde 1 vida.
                ctx.on_player_hit(player_id);
            } else {
                // Teammate hit: víctima pierde 1, atacante gana 1.
                ctx.on_player_hit(player_id);
                ctx.lives_per_player[BULLET_OWNER]++;
            }

            Audio::get()->playSound(Defaults::Sound::FRIENDLY_FIRE_HIT, Audio::Group::GAME);
            bullet.desactivar();
            break;  // Una bullet solo impacta una vez por frame
        }
    }
}

void detectAll(Context& ctx) {
    detectBulletEnemy(ctx);
    detectShipEnemy(ctx);
    detectBulletPlayer(ctx);
}

}  // namespace Systems::Collision
