using DoomDeathmatch.Component.MVC.Model.Enemy;
using DoomDeathmatch.Component.MVC.Model.Enemy.Attack;
using DoomDeathmatch.Component.MVC.View;
using DoomDeathmatch.Component.Util;

namespace DoomDeathmatch.Component.MVC.Controller;

public class EnemyController : Engine.Scene.Component.Component
{
  public HealthController HealthController => _healthController;

  private GameController _gameController = null!;
  private HealthController _healthController = null!;
  private EnemyView _enemyView = null!;
  private MovementController _movementController = null!;
  private AttackBehavior _attackBehavior = null!;

  private readonly EnemyData _enemyData;

  public EnemyController(EnemyData parEnemyData)
  {
    _enemyData = parEnemyData;
  }

  public override void Awake()
  {
    _gameController = GameObject.Scene!.FindFirstComponent<GameController>()!;
    _healthController = GameObject.GetComponent<HealthController>()!;
    _enemyView = GameObject.GetComponent<EnemyView>()!;
    _movementController = GameObject.GetComponent<MovementController>()!;

    ArgumentNullException.ThrowIfNull(_gameController);
    ArgumentNullException.ThrowIfNull(_healthController);
    ArgumentNullException.ThrowIfNull(_enemyView);
    ArgumentNullException.ThrowIfNull(_movementController);

    _attackBehavior = _enemyData.AttackBehaviorCreator.Create(this, _gameController.PlayerController.HealthController);

    _healthController.SetMaxHealth(_enemyData.BaseHealth);
    _healthController.OnDeath += OnDeath;
    _enemyView.UpdateView(_enemyData);
    _movementController.Speed = _enemyData.BaseSpeed;
  }

  public override void Start()
  {
    var billboardComponent = GameObject.GetComponentInChildren<BillboardComponent>();
    if (billboardComponent == null)
      return;

    billboardComponent.Target = _gameController.PlayerController.Camera.GameObject.Transform;
  }

  public override void Update(double parDeltaTime)
  {
    var playerPosition = _gameController.PlayerController.GameObject.Transform.Translation;
    var enemyPosition = GameObject.Transform.Translation;

    var nextPosition = _enemyData.MovementBehavior.GetNextPosition(enemyPosition, playerPosition);

    if (enemyPosition != nextPosition)
    {
      var direction = (nextPosition - enemyPosition).Normalized();
      _movementController.ApplyMovement(direction);
    }

    _attackBehavior.Attack(parDeltaTime);
  }

  private void OnDeath()
  {
    GameObject.Scene!.Remove(GameObject);
    _gameController.ScoreController.AddScore(_enemyData.BaseScore);
  }
}