#pragma once

// ==========================================================
// world_to_screen.hpp - 3D World To Screen 4x4 Projection Math
// Poe2VisualTool v1.2.0 Pro In-Game HUD Engine
// C++23 Native - High-precision SIMD / Scalar Projection
// ==========================================================

#include <cmath>
#include <cstdint>
#include <cstring>
#include <algorithm>

namespace visual {

struct Vector2 {
    float x = 0.0f;
    float y = 0.0f;

    constexpr Vector2() = default;
    constexpr Vector2(float x_, float y_) : x(x_), y(y_) {}

    float LengthSquared() const { return x * x + y * y; }
    float Length() const { return std::sqrt(LengthSquared()); }
};

struct Vector3 {
    float x = 0.0f;
    float y = 0.0f;
    float z = 0.0f;

    constexpr Vector3() = default;
    constexpr Vector3(float x_, float y_, float z_) : x(x_), y(y_), z(z_) {}

    float DistanceTo(const Vector3& other) const {
        float dx = x - other.x;
        float dy = y - other.y;
        float dz = z - other.z;
        return std::sqrt(dx * dx + dy * dy + dz * dz);
    }

    float Distance2D(const Vector3& other) const {
        float dx = x - other.x;
        float dy = y - other.y;
        return std::sqrt(dx * dx + dy * dy);
    }
};

struct Vector4 {
    float x = 0.0f;
    float y = 0.0f;
    float z = 0.0f;
    float w = 0.0f;

    constexpr Vector4() = default;
    constexpr Vector4(float x_, float y_, float z_, float w_) : x(x_), y(y_), z(z_), w(w_) {}
};

struct Matrix4x4 {
    float m[16] = {
        1.0f, 0.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f, 0.0f,
        0.0f, 0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 0.0f, 1.0f
    };

    constexpr Matrix4x4() = default;
    explicit Matrix4x4(const float raw[16]) {
        for (int i = 0; i < 16; ++i) m[i] = raw[i];
    }

    float At(int row, int col) const {
        return m[row * 4 + col];
    }
};

// ==========================================================
// WorldToScreen Calculator
// ==========================================================
class WorldToScreen {
public:
    // Transforms 3D world coordinates (x, y, z) into 2D viewport coordinates (outX, outY).
    // Returns true if the object is in front of the camera and successfully projected.
    // Returns false if object is behind camera (W <= 0.001f).
    static bool Project(
        const Matrix4x4& viewProj,
        const Vector3& worldPos,
        int screenWidth,
        int screenHeight,
        Vector2& outScreenPos,
        bool columnMajor = false
    );

    static bool Project(
        const float matrix[16],
        float x, float y, float z,
        int screenWidth,
        int screenHeight,
        float& outX,
        float& outY,
        bool columnMajor = false
    );

    // Checks if the projected point is inside the active screen bounds
    static bool IsOnScreen(const Vector2& screenPos, int screenWidth, int screenHeight, float margin = 0.0f);

    // Computes 2D minimap radar offset vector from player to target given map zoom and rotation
    static Vector2 ProjectToMinimapRadar(
        const Vector3& playerPos,
        const Vector3& targetPos,
        float cameraYawRad,
        float radarScale,
        float maxRadiusPixels
    );
};

} // namespace visual
