using DoomDeathmatch.Component.MVC.Enemy;
using DoomDeathmatch.Component.MVC.Health;
using DoomDeathmatch.Component.MVC.Weapon;
using DoomDeathmatch.Component.Physics.Collision;
using Engine.Input;
using Engine.Scene.Component.BuiltIn;
using Engine.Util;
using OpenTK.Mathematics;

namespace DoomDeathmatch.Component.MVC;

public class PlayerController : Engine.Scene.Component.Component
{
  public event Action? OnDeath;
  public bool IsAlive => _healthController.IsAlive;

  public HealthController HealthController => _healthController;
  public WeaponController WeaponController => _weaponController;
  public PerspectiveCamera Camera => _camera;

  private readonly IInputHandler _inputHandler = EngineUtil.InputHandler;

  private HealthController _healthController = null!;
  private WeaponController _weaponController = null!;
  private readonly PerspectiveCamera _camera;

  public PlayerController(PerspectiveCamera parCamera)
  {
    _camera = parCamera;
  }

  public override void Awake()
  {
    _healthController = GameObject.GetComponent<HealthController>()!;
    _weaponController = GameObject.GetComponent<WeaponController>()!;

    ArgumentNullException.ThrowIfNull(_healthController);
    ArgumentNullException.ThrowIfNull(_weaponController);

    _healthController.OnDeath += () => OnDeath?.Invoke();
  }

  public override void Update(double parDeltaTime)
  {
    if (!IsAlive || parDeltaTime == 0)
      return;

    for (var i = 0; i < 10; i++)
    {
      if (KeyboardButtonCode.D1 + i > KeyboardButtonCode.D0)
        break;

      if (!_inputHandler.IsKeyJustPressed(KeyboardButtonCode.D1 + i))
        continue;

      _weaponController.SelectWeapon(i);
      break;
    }

    if (_inputHandler.IsKeyJustPressed(KeyboardButtonCode.Space))
    {
      if (!_weaponController.TryShoot())
        return;

      var position = _camera.GameObject.Transform.GetFullTranslation();
      var forward = (_camera.Forward - position).Normalized();
      var right = Vector3.Cross(forward, Vector3.UnitZ).Normalized();

      var collisionManager = EngineUtil.SceneManager.CurrentScene!.FindFirstComponent<CollisionManagerComponent>();

      var offsets = _weaponController.WeaponData.ShootPattern.GetShootPattern(forward, Vector3.UnitZ, right);
      foreach (var offset in offsets)
      {
        var direction = forward + offset;
        if (!collisionManager!.Raycast(position, direction, ["enemy", "wall"], out var result))
          continue;

        var enemyController = result.HitObject.GetComponent<EnemyController>();
        enemyController?.HealthController.TakeDamage(_weaponController.WeaponData.Damage);
      }
    }
  }
}