using DoomDeathmatch.Component.MVC;
using DoomDeathmatch.Component.Physics.Collision;
using DoomDeathmatch.Script.Consumable;
using Engine.Graphics.Texture;
using Engine.Scene.Component.BuiltIn.Renderer;
using Engine.Util;
using OpenTK.Mathematics;

namespace DoomDeathmatch.Component;

public class ConsumableComponent : Engine.Scene.Component.Component
{
  private readonly IConsumable _consumable;
  private readonly AABBColliderComponent _collider;
  private readonly Box2DRenderer _box2DRenderer;

  private readonly Random _random = new();

  private MovementController _movementController = null!;

  public ConsumableComponent(IConsumable parConsumable, AABBColliderComponent parCollider,
    Box2DRenderer parBox2DRenderer)
  {
    _consumable = parConsumable;
    _collider = parCollider;
    _box2DRenderer = parBox2DRenderer;
  }

  public override void Awake()
  {
    _collider.OnCollision += OnCollision;
    _box2DRenderer.Texture = EngineUtil.AssetResourceManager.Load<Texture>(_consumable.Icon);

    _movementController = GameObject.GetComponent<MovementController>()!;

    ArgumentNullException.ThrowIfNull(_movementController);
  }

  private void OnCollision(AABBColliderComponent parCollider)
  {
    if (parCollider.ColliderGroups.Contains("player"))
      TryConsume(parCollider);
    else if (parCollider.ColliderGroups.Contains("consumable"))
      MoveAway(parCollider);
  }

  private void TryConsume(AABBColliderComponent parCollider)
  {
    var playerController = parCollider.GameObject.GetComponent<PlayerController>();
    if (playerController == null)
      return;

    _consumable.Consume(playerController);

    EngineUtil.SceneManager.CurrentScene!.Remove(GameObject);
  }

  private void MoveAway(AABBColliderComponent parCollider)
  {
    var direction = _collider.GameObject.Transform.GetFullTranslation() -
                    parCollider.GameObject.Transform.GetFullTranslation();

    if (direction.LengthSquared <= float.Epsilon)
      direction = GetRandomDirection();
    else
      direction.Normalize();

    _movementController.ApplyMovement(direction);
  }

  private Vector3 GetRandomDirection()
  {
    var x = _random.NextSingle() * 2 - 1;
    var y = _random.NextSingle() * 2 - 1;

    return new Vector3(x, y, 0).Normalized();
  }
}