// Copyright (c) FIRST and other WPILib contributors.
// Open Source Software; you can modify and/or share it under the terms of
// the WPILib BSD license file in the root directory of this project.

#pragma once

#include <concepts>
#include <limits>

#include "wpi/math/geometry/Rectangle2d.hpp"
#include "wpi/math/geometry/Translation2d.hpp"
#include "wpi/math/trajectory/constraint/TrajectoryConstraint.hpp"

namespace wpi::math {

/**
 * Enforces a particular constraint only within a rectangular region.
 */
template <std::derived_from<TrajectoryConstraint> Constraint>
class RectangularRegionConstraint : public TrajectoryConstraint {
 public:
  /**
   * Constructs a new RectangularRegionConstraint.
   *
   * @param rectangle The rectangular region in which to enforce the constraint.
   * @param constraint The constraint to enforce when the robot is within the
   *     region.
   */
  constexpr RectangularRegionConstraint(const Rectangle2d& rectangle,
                                        const Constraint& constraint)
      : m_rectangle{rectangle}, m_constraint{constraint} {}

  constexpr wpi::units::meters_per_second_t MaxVelocity(
      const Pose2d& pose, wpi::units::curvature_t curvature,
      wpi::units::meters_per_second_t velocity) const override {
    if (m_rectangle.Contains(pose.Translation())) {
      return m_constraint.MaxVelocity(pose, curvature, velocity);
    } else {
      return wpi::units::meters_per_second_t{
          std::numeric_limits<double>::infinity()};
    }
  }

  constexpr MinMax MinMaxAcceleration(
      const Pose2d& pose, wpi::units::curvature_t curvature,
      wpi::units::meters_per_second_t velocity) const override {
    if (m_rectangle.Contains(pose.Translation())) {
      return m_constraint.MinMaxAcceleration(pose, curvature, velocity);
    } else {
      return {};
    }
  }

 private:
  Rectangle2d m_rectangle;
  Constraint m_constraint;
};

}  // namespace wpi::math
