#nullable enable

using AGXUnity;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace PolyBag
{

  /// <summary>
  /// This class is responsible for removing any Shape (and parent RigidBody) when it get into contact
  /// with the Shape component
  /// </summary>
  public class ObjectSink : ScriptComponent
  {
    private agxCollide.Geometry ?m_sensorGeometry;

    static Dictionary<uint, PolyBag> m_geomPolyBagHash = new Dictionary<uint, PolyBag>();


    public static void RegisterPolyBag(GameObject bag)
    {

      var polybag = bag.GetComponent<PolyBag>();
      if (polybag == null) {
        return;
      }      

      m_geomPolyBagHash.Add(polybag.UniqueGroupID, polybag);
    }

    static void UnregisterPolyBag(PolyBag polybag)
    {
      m_geomPolyBagHash.Remove(polybag.UniqueGroupID);
    }


    static PolyBag? GetPolyBag(agxCollide.Geometry geometry)
    {

      var ids = geometry.findGroupIdCollection();
      PolyBag ?polybag = null;

      foreach (var id in ids.getIds())
      {
        if (m_geomPolyBagHash.TryGetValue(id, out polybag))
          break;
      }

      return polybag;
    }

    // Start is called before the first frame update
    protected override void OnEnable()
    {
      // Get the shape that is attached as a Component together with this script
      var sensor = GetComponent<AGXUnity.Collide.Shape>();

      // Register a callback when anything collides with this sensor shape
      AGXUnity.Simulation.Instance.ContactCallbacks.OnContact(RemoveObject, sensor);

      m_sensorGeometry = sensor.NativeGeometry;
    }

    /// <summary>
    /// This method will be called upon contact between the "Remove" sensor and any other Shape
    /// </summary>
    /// <param name="contactData"></param>
    /// <returns></returns>
    private bool RemoveObject(ref AGXUnity.ContactData contactData)
    {
      var geometry = contactData.Geometry1;

      // We do not want to remove the sensor, so the other shape is the one we want
      if (m_sensorGeometry == contactData.Geometry2)
      {
        geometry = contactData.Geometry2;
      }

      var polybag = GetPolyBag(geometry);
      if (polybag != null)
      {
        UnregisterPolyBag(polybag);

        Destroy(polybag.gameObject);

      }

      return false;

    }
  }
}
  