#include "boxes3d.hpp"

#include "../component_batch_adapter_builtins.hpp" // TODO(#3991): Should not leak into public header.

// #define EDIT_EXTENSION

namespace rerun {
    namespace archetypes {

#ifdef EDIT_EXTENSION
        // [CODEGEN COPY TO HEADER START]

        /// Creates new `Boxes3D` with `half_sizes` centered around the local origin.
        static Boxes3D from_half_sizes(ComponentBatch<components::HalfSizes3D> half_sizes) {
            Boxes3D boxes;
            boxes.half_sizes = std::move(half_sizes);
            return boxes;
        }

        /// Creates new `Boxes3D` with `centers` and `half_sizes`.
        static Boxes3D from_centers_and_half_sizes(
            ComponentBatch<components::Position3D> centers,
            ComponentBatch<components::HalfSizes3D> half_sizes
        ) {
            Boxes3D boxes;
            boxes.half_sizes = std::move(half_sizes);
            boxes.centers = std::move(centers);
            return boxes;
        }

        /// Creates new `Boxes3D` with `half_sizes` created from (full) sizes.
        ///
        /// TODO(#3285): Does *not* preserve data as-is and instead creates half-sizes from the
        /// input data.
        /// TODO(#3794): This should not take an std::vector.
        static Boxes3D from_sizes(const std::vector<datatypes::Vec3D>& sizes);

        /// Creates new `Boxes3D` with `centers` and `half_sizes` created from centers and (full)
        /// sizes.
        ///
        /// TODO(#3285): Does *not* preserve data as-is and instead creates centers and half-sizes
        /// from the input data.
        /// TODO(#3794): This should not take an std::vector.
        static Boxes3D from_centers_and_sizes(
            ComponentBatch<components::Position3D> centers,
            const std::vector<datatypes::Vec3D>& sizes
        ) {
            Boxes3D boxes = from_sizes(std::move(sizes));
            boxes.centers = std::move(centers);
            return boxes;
        }

        /// Creates new `Boxes3D` with `half_sizes` and `centers` created from minimums and (full)
        /// sizes.
        ///
        /// TODO(#3285): Does *not* preserve data as-is and instead creates centers and half-sizes
        /// from the input data.
        /// TODO(#3794): This should not take an std::vector.
        static Boxes3D from_mins_and_sizes(
            const std::vector<datatypes::Vec3D>& mins, const std::vector<datatypes::Vec3D>& sizes
        );

        // [CODEGEN COPY TO HEADER END]
#endif
        Boxes3D Boxes3D::from_sizes(const std::vector<datatypes::Vec3D>& sizes) {
            std::vector<components::HalfSizes3D> half_sizes;
            half_sizes.reserve(sizes.size());
            for (const auto& size : sizes) {
                half_sizes.emplace_back(size.x() / 2.0f, size.y() / 2.0f, size.z() / 2.0f);
            }

            // Move the vector into a component batch.
            return Boxes3D::from_half_sizes(std::move(half_sizes));
        }

        Boxes3D Boxes3D::from_mins_and_sizes(
            const std::vector<datatypes::Vec3D>& mins, const std::vector<datatypes::Vec3D>& sizes
        ) {
            auto num_components = std::min(mins.size(), sizes.size());

            std::vector<components::HalfSizes3D> half_sizes;
            std::vector<components::Position3D> centers;
            half_sizes.reserve(num_components);
            centers.reserve(num_components);

            for (size_t i = 0; i < num_components; ++i) {
                float half_size_x = sizes[i].x() * 0.5f;
                float half_size_y = sizes[i].y() * 0.5f;
                float half_size_z = sizes[i].z() * 0.5f;

                half_sizes.emplace_back(half_size_x, half_size_y, half_size_z);
                centers.emplace_back(
                    mins[i].x() + half_size_x,
                    mins[i].y() + half_size_y,
                    mins[i].z() + half_size_z
                );
            }

            Boxes3D boxes;
            boxes.half_sizes = std::move(half_sizes);
            boxes.centers = std::move(centers);
            return boxes;
        }
    } // namespace archetypes
} // namespace rerun
