using System.Collections;
using System.Collections.Generic;
using Godot;

namespace Rokojori
{
	public class Box2
	{
    public Vector2 min = Vector2.Zero;
    public Vector2 max = Vector2.Zero;

    public Box2( Vector2 min, Vector2 max )
    {
      this.min = min;
      this.max = max;
    } 

    public static Box2 Create( Vector2 min, Vector2 max )
    {
      return new Box2( min, max );
    }

    public static Box2 With( float width, float height, float x = 0, float y = 0 )
    {
      return new Box2( new Vector2( x, y ), new Vector2( x + width, y + height ) );
    }

    public static Box2 FromPointWithSize( Vector2 position, float size )
    {
      return new Box2( position - Vector2.One * size / 2f, position + Vector2.One * size / 2f ); 
    }

    public static Box2 FromPoints( List<Vector2> p )
    {
      var bx = new Box2( p[ 0 ], p[ 1 ] );
      bx.EnsureCorrectness();

      for ( int i = 2; i < p.Count; i++ )
      {
        bx.GrowByPoint( p[ i ] );
      }

      return bx;
    }

    public Vector2 ToLocal( Vector2 worldPoint )
    {
      return ( worldPoint - min ) / ( max - min );
    }

    public Box2()
    {}

    public bool ContainsPoint( Vector2 point )
    {
      return ContainsPoint( min, max, point );
    }

    public Box2 Clone()
    {
      return new Box2( min, max );
    }


    
    public Vector2 center => ( min + max ) / 2;
    public Vector2 size =>  max - min;
    public void UnionWith( Box2 other )
    {
      min = min.Min( other.min );
      max = max.Max( other.max );
    }

    public void Grow( Vector2 abs )
    {     
      min -= abs;
      max += abs;
    } 

    public void GrowByPoint( Vector2 p )
    {
      min = min.Min( p );
      max = max.Max( p );
    }


    public void GrowRelativeToSize( float amount )
    {     
      Grow( size * amount );
    }

    public static bool ContainsPoint( Vector2 min, Vector2 max, Vector2 point )
    {
      if ( ! Range.Contains( min.X, max.X, point.X ) )
      {
        return false;
      }

      if ( ! Range.Contains( min.Y, max.Y, point.Y ) )
      {
        return false;
      }

      return true;
    }

    public float DistanceTo( Vector2 point )
    {
      if ( ContainsPoint( point ) )
      {
        return 0;
      }

      var c = center;
      var s = size;

      var dx = Mathf.Max( Mathf.Abs( point.X - c.X) - s.X / 2, 0);
      var dy = Mathf.Max( Mathf.Abs( point.Y - c.Y) - s.Y / 2, 0);
      
      return Mathf.Sqrt( dx * dx + dy * dy ); 
    }


    public void EnsureCorrectness()
    {
      if ( max.X < min.X )
      {
        var b = max.X; max.X = min.X; min.X = b;
      }

      if ( max.Y < min.Y )
      {
        var b = max.Y; max.Y = min.Y; min.Y = b;
      }

    }

    public bool Overlaps( Box2 other )
    {
      return Overlap2D.Has( this, other );
    }

  }

}