using GatherAndDefend;
using System.Collections;
using System.Collections.Generic;
using UnityEditor.SceneManagement;
using UnityEngine;

public abstract class Entity : LevelObject
{
    [SerializeField]
    private WorldSlider _lifeBar;
    //Attribut
    [SerializeField]
    private int _hp;
    private int _maxHp;
    [SerializeField]
    private float _speed;
    [SerializeField]
    private int _attack_damage = 2;
    [SerializeField]
    private float _attack_interval = 2;
    private float _attack_speed_wait = 0f;
    private AnimationEntity _animation;
    private Shader _shaderGUItext;
    private Shader _shaderSpritesDefault;
    private SpriteRenderer[] _spriteRenderers;
    private AudioPlayerComponent _audioPlayerComponent;
    private StatusHandler _statusHandler;

    // status modifiers
    private float _speedStatusModifier = 1f;

    //Enemy Spotted
    private bool _isEnemyDetected = false;
    [SerializeField]
    private Entity _enemy;

    //Methods
    public virtual void Start()
    {
        _maxHp = _hp;
        _spriteRenderers = GetComponentsInChildren<SpriteRenderer>(true);
        _audioPlayerComponent = GetComponent<AudioPlayerComponent>();
        Animation = gameObject.AddComponent<AnimationEntity>();
        _statusHandler = gameObject.AddComponent<StatusHandler>();

        if (_audioPlayerComponent == null)
        {
            _audioPlayerComponent = gameObject.AddComponent<AudioPlayerComponent>();
        }
    }
    public virtual void Update()
    {
        Animation.AttackSpeedMultiplier = AttackSpeedMultiplier;
        Animation.SpeedMultiplier = SpeedMultiplier * SpeedStatusModifier;

        _lifeBar.gameObject.SetActive(_lifeBar.value <= 0.99f);
    }
    //Start the animation of death and the fading of the entity
    public virtual void Death()
    {
        _animation.PlayDieAnim();
        Invoke("Dying", 0.1f);
    }

    //Recursive method that fade the dying entity
    private void Dying()
    {
        foreach (SpriteRenderer renderer in _spriteRenderers)
        {
            Color currentColor = renderer.color;
            currentColor.a = currentColor.a - 0.1f;
            renderer.color = currentColor;
        }

        if (_spriteRenderers[0].color.a > 0f)
        {
            Invoke("Dying", 0.1f);
        }
        else
        {
            Destroy(gameObject);
        }

    }

    //When hit : get damage and start a flash of light 
    public void Hit(int damage)
    {
        _hp -= damage;

        _lifeBar.value = _hp / (float)_maxHp;

        _shaderGUItext = Shader.Find("GUI/Text Shader");
        _shaderSpritesDefault = Shader.Find("Sprites/Default");

        foreach (SpriteRenderer renderer in _spriteRenderers)
        {
            renderer.material.shader = _shaderGUItext;
        }
        Invoke("ReturnNormalColor", 0.1f);
    }

    //End the flash of light from the method above
    private void ReturnNormalColor()
    {
        foreach (SpriteRenderer renderer in _spriteRenderers)
        {
            renderer.material.shader = _shaderSpritesDefault;
        }
    }

    public void Move()
    {
        if (!_animation.IsWalking)
        {
            _animation.PlayWalkAnim();
        }
    }

    public void PlaySound(string soundName, float volumeMultiplier = 1f, float overrideVolume = -1f)
    {
        _audioPlayerComponent.PlaySound(soundName, volumeMultiplier, overrideVolume);
    }

    public void PlaySound(AudioTemplate sound, float volumeMultiplier = 1f, float overrideVolume = -1f)
    {
        _audioPlayerComponent.PlaySound(sound, volumeMultiplier, overrideVolume);
    }

    //GETTERS AND SETTERS

    public abstract Vector2 RangeMultiplier { get; }
    public abstract float HpMultiplier { get; }
    public abstract float SpeedMultiplier { get; }
    public abstract float DamageMultiplier { get; }
    public abstract float AttackSpeedMultiplier { get; }

    public int Hp => (int)(_hp * HpMultiplier);

    public float Speed => _speed * SpeedMultiplier * SpeedStatusModifier;

    public int AttackDamage
    {
        get { return (int)(_attack_damage * DamageMultiplier); }
        set { _attack_damage = value; }
    }

    public float AttackInterval => _attack_interval / AttackSpeedMultiplier;

    public float AttackSpeedWait
    {
        get { return _attack_speed_wait; }
        set { _attack_speed_wait = value; }
    }

    public bool IsEnemyDetected
    {
        get { return _isEnemyDetected; }
        set { _isEnemyDetected = value; }
    }

    public Entity Enemy
    {
        get { return _enemy; }
        set { _enemy = value; }
    }

    public AnimationEntity Animation
    {
        get { return _animation; }
        set { _animation = value; }
    }

    public SpriteRenderer[] SpriteRenderers { get { return _spriteRenderers; } }

    public StatusHandler StatusHandler { 
        get => _statusHandler; 
    }
    public float SpeedStatusModifier { get => _speedStatusModifier; set => _speedStatusModifier = value; }

    #region [LevelManager code]
    public override bool Equals(ILevelObject other)
    {
        return other is Entity otherEntity
            && base.Equals(otherEntity)
            && otherEntity._hp == _hp
            && otherEntity._speed == _speed
            && otherEntity._attack_interval == _attack_interval
            && otherEntity._attack_damage == _attack_damage;
    }
    public override Dictionary<string, object> ToDictionary()
    {
        var dict = base.ToDictionary();

        dict[nameof(_hp)] = _hp;
        dict[nameof(_speed)] = _speed;
        dict[nameof(_attack_interval)] = _attack_interval;
        dict[nameof(_attack_damage)] = _attack_damage;

        return dict;
    }
    public override void LoadDictionary(Dictionary<string, object> dict)
    {
        base.LoadDictionary(dict);

        _hp = dict[nameof(_hp)].ToInt();
        _speed = dict[nameof(_speed)].ToFloat();
        _attack_interval = dict[nameof(_attack_interval)].ToFloat();
        _attack_damage = dict[nameof(_attack_damage)].ToInt();
    }
    #endregion
}
