using Syntriax.Engine.Core;
using Syntriax.Engine.Core.Abstract;
using Syntriax.Engine.Physics2D.Abstract;

namespace Syntriax.Engine.Physics2D;

public abstract class Collider2DBehaviourBase : Behaviour2D, ICollider2D
{
    public event ICollider2D.CollisionDetectedEventHandler? OnCollisionDetected = null;
    public event ICollider2D.CollisionResolvedEventHandler? OnCollisionResolved = null;
    public event ICollider2D.TriggeredEventHandler? OnTriggered = null;

    protected bool NeedsRecalculation { get; private set; } = true;
    protected IRigidBody2D? _rigidBody2D = null;

    public IRigidBody2D? RigidBody2D => _rigidBody2D;
    public bool IsTrigger { get; set; } = false;

    public void Recalculate()
    {
        if (!NeedsRecalculation)
            return;

        CalculateCollider();
        NeedsRecalculation = false;
    }

    public abstract void CalculateCollider();

    protected override void OnInitialize()
    {
        BehaviourController.TryGetBehaviourInParent(out _rigidBody2D);

        BehaviourController.OnBehaviourAdded += OnBehaviourAddedToController;
        BehaviourController.OnBehaviourRemoved += OnBehaviourRemovedFromController;

        Transform.OnPositionChanged += SetNeedsRecalculationFromPosition;
        Transform.OnRotationChanged += SetNeedsRecalculationFromRotation;
        Transform.OnScaleChanged += SetNeedsRecalculationFromScale;
        HierarchyObject.OnParentChanged += UpdateRigidBody2D;
    }

    private void UpdateRigidBody2D(IHierarchyObject sender, IHierarchyObject? previousParent, IHierarchyObject? newParent)
    {
        BehaviourController.TryGetBehaviourInParent(out _rigidBody2D);
    }

    private void OnBehaviourAddedToController(IBehaviourController _, IBehaviour behaviour)
    {
        if (behaviour is IRigidBody2D rigidBody)
            _rigidBody2D = rigidBody;
    }

    private void OnBehaviourRemovedFromController(IBehaviourController _, IBehaviour behaviour)
    {
        if (behaviour is IRigidBody2D _)
            _rigidBody2D = null;
    }

    private void SetNeedsRecalculationFromScale(ITransform2D sender, Vector2D previousScale) => NeedsRecalculation = true;
    private void SetNeedsRecalculationFromPosition(ITransform2D sender, Vector2D previousPosition) => NeedsRecalculation = true;
    private void SetNeedsRecalculationFromRotation(ITransform2D sender, float previousRotation) => NeedsRecalculation = true;

    protected override void OnFinalize()
    {
        BehaviourController.OnBehaviourAdded -= OnBehaviourAddedToController;
        BehaviourController.OnBehaviourRemoved -= OnBehaviourRemovedFromController;
        Transform.OnScaleChanged -= SetNeedsRecalculationFromScale;

        Transform.OnPositionChanged -= SetNeedsRecalculationFromPosition;
        Transform.OnRotationChanged -= SetNeedsRecalculationFromRotation;
    }

    public void Detect(CollisionDetectionInformation collisionDetectionInformation) => OnCollisionDetected?.Invoke(this, collisionDetectionInformation);
    public void Resolve(CollisionDetectionInformation collisionDetectionInformation) => OnCollisionResolved?.Invoke(this, collisionDetectionInformation);
    public void Trigger(ICollider2D initiator) => OnTriggered?.Invoke(this, initiator);
}