using System;
using System.Collections.Generic;
namespace Engine.Core;
/// 
/// Represents an Axis-Aligned Bounding Box (AABB) in 2D space.
/// 
/// The lower boundary of the .
/// The upper boundary of the .
/// 
/// Initializes a new instance of the  struct with the specified lower and upper boundaries.
/// 
[System.Diagnostics.DebuggerDisplay("LowerBoundary: {LowerBoundary.ToString(), nq}, UpperBoundary: {UpperBoundary.ToString(), nq}")]
public readonly struct AABB2D(Vector2D lowerBoundary, Vector2D upperBoundary) : IEquatable
{
    /// 
    /// The lower boundary of the .
    /// 
    public readonly Vector2D LowerBoundary = lowerBoundary;
    /// 
    /// The upper boundary of the .
    /// 
    public readonly Vector2D UpperBoundary = upperBoundary;
    /// 
    /// Gets the center point of the .
    /// 
    public readonly Vector2D Center => (LowerBoundary + UpperBoundary) * .5f;
    /// 
    /// Gets the size of the .
    /// 
    public readonly Vector2D Size => LowerBoundary.FromTo(UpperBoundary).Abs();
    /// 
    /// Gets half the size of the .
    /// 
    public readonly Vector2D SizeHalf => Size * .5f;
    public static bool operator ==(AABB2D left, AABB2D right) => left.UpperBoundary == right.UpperBoundary && left.LowerBoundary == right.LowerBoundary;
    public static bool operator !=(AABB2D left, AABB2D right) => left.UpperBoundary != right.UpperBoundary || left.LowerBoundary != right.LowerBoundary;
    public static implicit operator AABB2D(Circle circle) => new(circle.Center - new Vector2D(circle.Radius, circle.Radius), circle.Center + new Vector2D(circle.Radius, circle.Radius));
    public static implicit operator AABB2D(Shape2D shape) => FromVectors(shape.Vertices);
    /// 
    /// Creates an  from a collection of s.
    /// 
    /// The collection of s.
    /// An  that bounds all the s.
    public static AABB2D FromVectors(IEnumerable vectors)
    {
        int counter = 0;
        Vector2D lowerBoundary = new(float.MaxValue, float.MaxValue);
        Vector2D upperBoundary = new(float.MinValue, float.MinValue);
        foreach (Vector2D vector in vectors)
        {
            lowerBoundary = Vector2D.Min(lowerBoundary, vector);
            upperBoundary = Vector2D.Max(upperBoundary, vector);
            counter++;
        }
        if (counter < 2)
            throw new ArgumentException($"Parameter {nameof(vectors)} must have at least 2 items.");
        return new(lowerBoundary, upperBoundary);
    }
    /// 
    /// Checks if two s are approximately equal.
    /// 
    /// The first .
    /// The second .
    /// The epsilon range.
    ///  if the s are approximately equal; otherwise, .
    public static bool ApproximatelyEquals(AABB2D left, AABB2D right, float epsilon = float.Epsilon)
        => left.LowerBoundary.ApproximatelyEquals(right.LowerBoundary, epsilon) && left.UpperBoundary.ApproximatelyEquals(right.UpperBoundary, epsilon);
    /// 
    /// Determines whether the specified object is equal to the current .
    /// 
    /// The object to compare with the current .
    ///  if the specified object is equal to the current ; otherwise, .
    public override bool Equals(object? obj) => obj is AABB2D aabb && this == aabb;
    public bool Equals(AABB2D other) => this == other;
    /// 
    /// Generates a hash code for the .
    /// 
    /// A hash code for the .
    public override int GetHashCode() => System.HashCode.Combine(LowerBoundary, UpperBoundary);
    /// 
    /// Converts the  to its string representation.
    /// 
    /// A string representation of the .
    public override string ToString() => $"{nameof(AABB2D)}({LowerBoundary}, {UpperBoundary})";
}
/// 
/// Provides extension methods for the  struct.
/// 
public static class AABBExtensions
{
    /// 
    public static AABB2D ToAABB(this IEnumerable vectors) => AABB2D.FromVectors(vectors);
    /// 
    public static bool ApproximatelyEquals(this AABB2D left, AABB2D right, float epsilon = float.Epsilon) => AABB2D.ApproximatelyEquals(left, right, epsilon);
}