using System;
using System.Collections;
using UnityEngine;
using UnityEngine.Events;

[RequireComponent(typeof(Rigidbody2D))]
public class Rocket : MonoBehaviour, IMonsterKiller
{
    #region Fields
    [Header("Rocket component")]
    [SerializeField] private Rigidbody2D _rigibody = null;
    [SerializeField] private Transform _rocketForward = null;
    [SerializeField] private GameObject _view = null;
	
	[Header("Rocket stats")]
    [SerializeField] private bool _isLaunched = false;
    [SerializeField] private float _healthPoints = 1.0f;
    [SerializeField] private int _damage = 1;
    [SerializeField] private float _currentPatternTime = 0.0f;
    [SerializeField] private AnimationCurve _trajectoryInfluence;

    [SerializeField] private float _scaleX = 1f;
    [SerializeField] private Transform _visualTransform = null;
    [SerializeField] private UnityEvent _onDrillDestroyed = null;
	
	[Header("Rocket sounds")]
	[SerializeField] private AudioSource RocketLaunchAudio;
	[SerializeField] private AudioSource RocketTrailAudio;
	[SerializeField] private AudioSource RocketExplosionAudio;

	[Header("Others")]
	[SerializeField] private float _surfacePoint = 4.8f;
    #endregion Fields

    #region Properties
    private Vector3 _direction = Vector3.up;
    private Vector3 _startingPosition = Vector3.zero;
    private Trajectory _trajectory = null;
    private float _launchSpeed = 0.0f;
    private TrajectoryType _type = TrajectoryType.Linear;
    private float _groundYsize = 4f;
	
    // Components
	private SpriteRenderer _spriteRedenrer;
	private Animator _animator;

    public int Damage => _damage;

    public bool Enable => true;
    #endregion Properties

	private Action _explodeEvent;
	public event Action ExplodeEvent
	{
		add
		{
			_explodeEvent -= value;
			_explodeEvent += value;
		}
		remove
		{
			_explodeEvent -= value;
		}
	}

    public void Start()
    {
        _rigibody = transform.GetComponent<Rigidbody2D>();
        _spriteRedenrer = _view.GetComponent<SpriteRenderer>();
        _animator = _view.GetComponent<Animator>();

		_groundYsize = _surfacePoint - transform.position.y;
    }

    public void Launch(Trajectory trajectory, Vector3 startingPosition, float launchSpeed)
    {
        _trajectory = trajectory;
        _startingPosition = startingPosition;
        _direction = _rocketForward.transform.up;

        Launch(launchSpeed, TrajectoryType.Mix);
    }

    public void Launch(float launchSpeed, TrajectoryType type)
    {
        _type = type;
        _launchSpeed = launchSpeed;
        _isLaunched = true;
		RocketLaunchAudio.Play();
		RocketTrailAudio.Play();
    }

    public void Update()
    {
        if (_isLaunched)
        {
			_animator.SetBool("Move", true);
            _currentPatternTime += Time.deltaTime * _launchSpeed;
            if (_currentPatternTime > 1.0f)
            {
                _currentPatternTime = 0.0f;
                DestroySelf();
                return;
            }

            float x = _startingPosition.x;
            //if (_type == TrajectoryType.Mix)
            //{
                x += _trajectory.Evaluate(_currentPatternTime) * _scaleX * _trajectoryInfluence.Evaluate(_currentPatternTime);
            //}
            //else
            //{
            //    x = ComputePositionOffset(_type, _currentPatternTime).x;
            //}

            float y = Mathf.Lerp(_startingPosition.y, _groundYsize, _currentPatternTime);
            //Debug.Log($"X: {x} and Y:{y} for time:{_currentPatternTime}");
            Vector2 nextPosition = ApplyRotation(x, y);

            Vector2 direction = nextPosition - _rigibody.position;
            float angle = Vector2.SignedAngle(Vector2.up, direction);
            _visualTransform.rotation = Quaternion.Euler(0f, 0f, angle);

            transform.position = new Vector3(x, y, 0);
        }
    }

    private Vector2 ComputePositionOffset(TrajectoryType type, float t)
    {
        switch (type)
        {
            case TrajectoryType.Linear:
                return new Vector2 (TrajectoryComputation.LinearFunction(t), t);

            case TrajectoryType.Sinewave:
                return TrajectoryComputation.SinusoidaleFunction(_rocketForward.transform.up, 1.0f, _launchSpeed, t);

            default:
                // Just for debug purpose and avoid Vector.zero.
                return Vector3.up;
        }
    }

    private Vector3 ApplyRotation(float x, float y)
    {
        float angle = Vector2.Dot(Vector2.right, _direction);
        //Debug.Log(Mathf.Abs(angle));

        // Apply rotation matrix based on angle
        float xRot = x * Mathf.Cos(angle) - y * Mathf.Sin(angle);
        float yRot = x * Mathf.Sin(angle) + y * Mathf.Cos(angle);

        return new Vector3(xRot, yRot);
    }

    //private void OnTriggerEnter2D(Collider2D collision)
    //{
    //    if (collision.gameObject.CompareTag("Monster"))
    //    {
    //        DestroySelf();
    //    }
    //}

    private void OnCollisionEnter2D(Collision2D collision)
    {
        // TODO: Make it take damage from a rock or take slow from something
        Debug.Log(collision.collider.gameObject.name);
    }

    private void DestroySelf()
    {
        Debug.Log("Drill getting destroyed");
        _isLaunched = false;
        _view.SetActive(false);
        _damage = 0;

        // Add Explosion VFX
        RocketTrailAudio.Stop();
        _onDrillDestroyed?.Invoke();
        RocketExplosionAudio.Play();
		_explodeEvent?.Invoke();
        Destroy(gameObject, 2.0f);
    }
}
