// camera3d.hpp - Càmera 3D amb projecció en perspectiva en CPU
// © 2026 JailDesigner
//
// La càmera viu en l'espai mundial (X dreta, Y amunt, Z davant). El mètode
// project() pren un Vec3 mundial i torna les coordenades 2D en píxels lògics
// de pantalla, més el factor d'escala focal/depth (útil per renderShape).
// Si el punt queda darrere del near plane, torna std::nullopt.

#pragma once

#include <optional>

#include "core/types.hpp"

namespace Graphics {

    class Camera3D {
       public:
        struct ProjectedPoint {
            Vec2 screen;  // Píxels lògics
            float scale;  // focal / depth (escala visual a aquesta Z)
            float depth;  // Profunditat en l'espai de càmera (cz)
        };

        Camera3D(const Vec3& position, const Vec3& target, const Vec3& up_world, float fov_y_rad, float viewport_w, float viewport_h, float near_plane = 0.1F, float far_plane = 2000.0F);

        void setPosition(const Vec3& p);
        void setTarget(const Vec3& t);
        void setUpWorld(const Vec3& u);
        void setViewport(float w, float h);
        void setFovY(float fov_y_rad);

        [[nodiscard]] auto project(const Vec3& world) const -> std::optional<ProjectedPoint>;

        [[nodiscard]] auto position() const -> const Vec3& { return position_; }
        [[nodiscard]] auto forward() const -> const Vec3& { return forward_; }
        [[nodiscard]] auto nearPlane() const -> float { return near_; }
        [[nodiscard]] auto farPlane() const -> float { return far_; }

       private:
        void recomputeBasis();
        void recomputeFocal();

        Vec3 position_{};
        Vec3 target_{};
        Vec3 up_world_{};
        Vec3 right_{.x = 1.0F, .y = 0.0F, .z = 0.0F};
        Vec3 up_{.x = 0.0F, .y = 1.0F, .z = 0.0F};
        Vec3 forward_{.x = 0.0F, .y = 0.0F, .z = 1.0F};
        float fov_y_rad_{0.0F};
        float viewport_w_{0.0F};
        float viewport_h_{0.0F};
        float near_{0.1F};
        float far_{2000.0F};
        float focal_{0.0F};
        float centre_x_{0.0F};
        float centre_y_{0.0F};
    };

}  // namespace Graphics
