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

namespace Rokojori
{
  [Tool]
  [GlobalClass]
  public partial class AreaCaster:Caster, iNodeState
  {
    [Export]
    public Area3D area;

    [Export]
    public Action onCollisionsChanged;

    [Export]
    public Action onCollisionEntered;

    [Export]
    public Action onCollisionExited;


    [ExportGroup( "Debugging")]
    [Export]
    public Node collider;

    [Export]
    public bool printColliderNames = false;



    public override void _Ready()
    {
      if ( area == null )
      { 
        return;
      }

      area.AreaEntered += TriggerOnEnter;
      area.BodyEntered += TriggerOnEnter;

      area.AreaExited  += _TriggerOnExited;
      area.BodyExited  += _TriggerOnExited;
    }     

    public void TriggerOnEnter( Node3D node3D )
    {
      this.LogInfo( HierarchyName.Of( node3D ) );
      _TriggerOnEnter( node3D );
    }

    public void TriggerOnExited( Node3D node3D )
    {
      this.LogInfo( HierarchyName.Of( node3D ) );
      _TriggerOnExited( node3D );
    }

    void _TriggerOnEnter( Node3D n )
    {
      if ( n == null )
      {
        return;
      }
      
      if ( area != null && ! Math3D.IsValid( area.GlobalPosition ) )
      {
        return;
      } 

      var selected = IsSelected( n );

      if ( ! selected )
      {
        // this.LogInfo( "Not selected", HierarchyName.Of( n ) );
        return;
      }

      var collisionData = new CollisionData();
      collisionData.hasCollision = true;
      collisionData.collider = n;     
      
      collisionData.position = ( area.GlobalPosition + n.GlobalPosition ) / 2f;
      collisionData.normal = ( n.GlobalPosition - area.GlobalPosition ).Normalized();
     
      collisions.Add( collisionData );     

      numCollisions = collisions.Count;

      // this.LogInfo( "Selected", HierarchyName.Of( n ) );

      SortCollisions();

      onCollisionEntered?.Trigger();
      onCollisionsChanged?.Trigger();
      
    }

    void _TriggerOnExited( Node n )
    {
      if ( n == null )
      {
        return;
      }
      
      var insideIndex = collisions.FindIndex( c => c.collider == n );

      if ( insideIndex == -1 )
      {
        return;
      }

      collisions.RemoveAt( insideIndex );

      numCollisions = collisions.Count;

      SortCollisions();

      onCollisionExited?.Trigger();
      onCollisionsChanged?.Trigger();

    }

    public void OnNodeStateChanged()
    {
      if ( ! IsProcessing() || ! IsPhysicsProcessing() || Node.ProcessModeEnum.Disabled == this.ProcessMode )
      {
        // this.LogInfo( "Clearing nodes" );
        collisions.Clear();
        numCollisions = 0;
      }
    }

    

  }
}