// nau.cpp - Implementació de la nave del jugador
// © 1999 Visente i Sergi (versió Pascal)
// © 2025 Port a C++20 amb SDL3

#include "game/entities/nau.hpp"

#include <SDL3/SDL.h>

#include <cmath>
#include <iostream>

#include "core/defaults.hpp"
#include "core/graphics/shape_loader.hpp"
#include "core/input/input.hpp"
#include "core/rendering/shape_renderer.hpp"
#include "game/constants.hpp"

Nau::Nau(SDL_Renderer* renderer, const char* shape_file)
    : renderer_(renderer),
      centre_({0.0f, 0.0f}),
      angle_(0.0f),
      velocitat_(0.0f),
      esta_tocada_(false),
      brightness_(Defaults::Brightness::NAU),
      invulnerable_timer_(0.0f) {
    // [NUEVO] Carregar forma compartida des de fitxer
    forma_ = Graphics::ShapeLoader::load(shape_file);

    if (!forma_ || !forma_->es_valida()) {
        std::cerr << "[Nau] Error: no s'ha pogut carregar " << shape_file << std::endl;
    }
}

void Nau::inicialitzar(const Punt* spawn_point, bool activar_invulnerabilitat) {
    // Inicialització de la nau (triangle)
    // Basat en el codi Pascal original: lines 380-384
    // Copiat de joc_asteroides.cpp línies 30-44

    // [NUEVO] Ja no cal configurar punts polars - la geometria es carrega del
    // fitxer Només inicialitzem l'estat de la instància

    // Use custom spawn point if provided, otherwise use center
    if (spawn_point) {
        centre_.x = spawn_point->x;
        centre_.y = spawn_point->y;
    } else {
        // Default: center of play area
        float centre_x, centre_y;
        Constants::obtenir_centre_zona(centre_x, centre_y);
        centre_.x = static_cast<int>(centre_x);
        centre_.y = static_cast<int>(centre_y);
    }

    // Estat inicial
    angle_ = 0.0f;
    velocitat_ = 0.0f;

    // Activar invulnerabilidad solo si es respawn
    if (activar_invulnerabilitat) {
        invulnerable_timer_ = Defaults::Ship::INVULNERABILITY_DURATION;
    } else {
        invulnerable_timer_ = 0.0f;
    }

    esta_tocada_ = false;
}

void Nau::processar_input(float delta_time, uint8_t player_id) {
    // Processar input continu (com teclapuls() del Pascal original)
    // Basat en joc_asteroides.cpp línies 66-85
    // Només processa input si la nau està viva
    if (esta_tocada_)
        return;

    auto* input = Input::get();

    // Processar input segons el jugador
    if (player_id == 0) {
        // Jugador 1
        if (input->checkActionPlayer1(InputAction::RIGHT, Input::ALLOW_REPEAT)) {
            angle_ += Defaults::Physics::ROTATION_SPEED * delta_time;
        }

        if (input->checkActionPlayer1(InputAction::LEFT, Input::ALLOW_REPEAT)) {
            angle_ -= Defaults::Physics::ROTATION_SPEED * delta_time;
        }

        if (input->checkActionPlayer1(InputAction::THRUST, Input::ALLOW_REPEAT)) {
            if (velocitat_ < Defaults::Physics::MAX_VELOCITY) {
                velocitat_ += Defaults::Physics::ACCELERATION * delta_time;
                if (velocitat_ > Defaults::Physics::MAX_VELOCITY) {
                    velocitat_ = Defaults::Physics::MAX_VELOCITY;
                }
            }
        }
    } else {
        // Jugador 2
        if (input->checkActionPlayer2(InputAction::RIGHT, Input::ALLOW_REPEAT)) {
            angle_ += Defaults::Physics::ROTATION_SPEED * delta_time;
        }

        if (input->checkActionPlayer2(InputAction::LEFT, Input::ALLOW_REPEAT)) {
            angle_ -= Defaults::Physics::ROTATION_SPEED * delta_time;
        }

        if (input->checkActionPlayer2(InputAction::THRUST, Input::ALLOW_REPEAT)) {
            if (velocitat_ < Defaults::Physics::MAX_VELOCITY) {
                velocitat_ += Defaults::Physics::ACCELERATION * delta_time;
                if (velocitat_ > Defaults::Physics::MAX_VELOCITY) {
                    velocitat_ = Defaults::Physics::MAX_VELOCITY;
                }
            }
        }
    }
}

void Nau::actualitzar(float delta_time) {
    // Només actualitzar si la nau està viva
    if (esta_tocada_)
        return;

    // Decrementar timer de invulnerabilidad
    if (invulnerable_timer_ > 0.0f) {
        invulnerable_timer_ -= delta_time;
        if (invulnerable_timer_ < 0.0f) {
            invulnerable_timer_ = 0.0f;
        }
    }

    // Aplicar física (moviment + fricció)
    aplicar_fisica(delta_time);
}

void Nau::dibuixar() const {
    // Només dibuixar si la nau està viva
    if (esta_tocada_)
        return;

    // Si invulnerable, parpadear (toggle on/off)
    if (es_invulnerable()) {
        // Calcular ciclo de parpadeo
        float blink_cycle = Defaults::Ship::BLINK_VISIBLE_TIME +
            Defaults::Ship::BLINK_INVISIBLE_TIME;
        float time_in_cycle = std::fmod(invulnerable_timer_, blink_cycle);

        // Si estamos en fase invisible, no dibujar
        if (time_in_cycle < Defaults::Ship::BLINK_INVISIBLE_TIME) {
            return;  // No dibujar durante fase invisible
        }
    }

    if (!forma_)
        return;

    // Escalar velocitat per l'efecte visual (200 px/s → ~6 px d'efecte)
    // El codi Pascal original sumava velocitat (0-6) al radi per donar
    // sensació de "empenta". Ara velocitat està en px/s (0-200).
    // Basat en joc_asteroides.cpp línies 127-134
    //
    // [NUEVO] Convertir suma de velocitat_visual a escala multiplicativa
    // Radio base del ship = 12 px
    // velocitat_visual = 0-6 → r = 12-18 → escala = 1.0-1.5
    float velocitat_visual = velocitat_ / 33.33f;
    float escala = 1.0f + (velocitat_visual / 12.0f);

    Rendering::render_shape(renderer_, forma_, centre_, angle_, escala, true, 1.0f, brightness_);
}

void Nau::aplicar_fisica(float delta_time) {
    // Aplicar física de moviment
    // Basat en joc_asteroides.cpp línies 87-113

    // Calcular nova posició basada en velocitat i angle
    // S'usa (angle - PI/2) perquè angle=0 apunta cap amunt, no cap a la dreta
    // velocitat_ està en px/s, així que multipliquem per delta_time
    float dy =
        (velocitat_ * delta_time) * std::sin(angle_ - Constants::PI / 2.0f) +
        centre_.y;
    float dx =
        (velocitat_ * delta_time) * std::cos(angle_ - Constants::PI / 2.0f) +
        centre_.x;

    // Boundary checking amb radi de la nau
    // CORRECCIÓ: Usar límits segurs i inequalitats inclusives
    float min_x, max_x, min_y, max_y;
    Constants::obtenir_limits_zona_segurs(Defaults::Entities::SHIP_RADIUS,
        min_x,
        max_x,
        min_y,
        max_y);

    // Inequalitats inclusives (>= i <=)
    if (dy >= min_y && dy <= max_y) {
        centre_.y = dy;
    }

    if (dx >= min_x && dx <= max_x) {
        centre_.x = dx;
    }

    // Fricció - desacceleració gradual (time-based)
    if (velocitat_ > 0.1f) {
        velocitat_ -= Defaults::Physics::FRICTION * delta_time;
        if (velocitat_ < 0.0f) {
            velocitat_ = 0.0f;
        }
    }
}
