using UnityEngine;
using UnityEngine.UI;

// Screen-space HP bar for the player HUD.
// Enemy HP bars can keep using the SpriteRenderer-based HpBar.
public class PlayerHpBarUI : MonoBehaviour
{
    [SerializeField] private Health _health;
    [SerializeField] private Image _fillImage;
    [SerializeField] private bool _autoFindPlayerHealth = true;
    [SerializeField] private bool _autoFindFillImageInChildren = true;
    [SerializeField] private bool _configureAsFilledImage = true;
    [SerializeField] private float _smoothSpeed = 0f;

    [Header("Color Thresholds")]
    [SerializeField] private Color _highColor = new Color(0.2f, 0.9f, 0.3f, 1f);
    [SerializeField] private Color _midColor = new Color(1f, 0.85f, 0.2f, 1f);
    [SerializeField] private Color _lowColor = new Color(0.95f, 0.25f, 0.25f, 1f);
    [SerializeField, Range(0f, 1f)] private float _midThreshold = 0.5f;
    [SerializeField, Range(0f, 1f)] private float _lowThreshold = 0.2f;

    private float _currentRatio = 1f;
    private float _targetRatio = 1f;

    private void Awake()
    {
        ResolveFillImage();
        ResolveHealth();
        ConfigureFillImage();
    }

    private void OnEnable()
    {
        ResolveFillImage();
        ResolveHealth();
        ConfigureFillImage();

        if (_health == null) return;

        _health.OnHealthChanged += HandleHealthChanged;
        HandleHealthChanged(_health.CurrentHealth, _health.MaxHealth);
    }

    private void OnDisable()
    {
        if (_health != null)
            _health.OnHealthChanged -= HandleHealthChanged;
    }

    private void Start()
    {
        ResolveFillImage();
        ResolveHealth();
        ConfigureFillImage();

        if (_health != null)
            HandleHealthChanged(_health.CurrentHealth, _health.MaxHealth);
    }

    private void Update()
    {
        if (_fillImage == null || _smoothSpeed <= 0f) return;
        if (Mathf.Approximately(_currentRatio, _targetRatio)) return;

        _currentRatio = Mathf.MoveTowards(_currentRatio, _targetRatio, _smoothSpeed * Time.deltaTime);
        ApplyFill();
    }

    public void Bind(Health health)
    {
        if (_health == health) return;

        if (isActiveAndEnabled && _health != null)
            _health.OnHealthChanged -= HandleHealthChanged;

        _health = health;

        if (isActiveAndEnabled && _health != null)
        {
            _health.OnHealthChanged += HandleHealthChanged;
            HandleHealthChanged(_health.CurrentHealth, _health.MaxHealth);
        }
    }

    private void HandleHealthChanged(int current, int max)
    {
        _targetRatio = max > 0 ? Mathf.Clamp01((float)current / max) : 0f;

        if (_smoothSpeed <= 0f)
        {
            _currentRatio = _targetRatio;
            ApplyFill();
        }

        ApplyColor(_targetRatio);
    }

    private void ApplyFill()
    {
        if (_fillImage == null) return;
        _fillImage.fillAmount = Mathf.Clamp01(_currentRatio);
    }

    private void ApplyColor(float ratio)
    {
        if (_fillImage == null) return;

        if (ratio <= _lowThreshold)
            _fillImage.color = _lowColor;
        else if (ratio <= _midThreshold)
            _fillImage.color = _midColor;
        else
            _fillImage.color = _highColor;
    }

    private void ResolveHealth()
    {
        if (_health != null || !_autoFindPlayerHealth) return;

        PlayerController player = FindFirstObjectByType<PlayerController>();
        if (player != null)
            _health = player.GetComponent<Health>();
    }

    private void ResolveFillImage()
    {
        if (_fillImage != null || !_autoFindFillImageInChildren) return;

        Transform fill = FindChildByName(transform, "Fill");
        if (fill != null)
            _fillImage = fill.GetComponent<Image>();
    }

    private Transform FindChildByName(Transform parent, string childName)
    {
        if (parent == null) return null;

        for (int i = 0; i < parent.childCount; i++)
        {
            Transform child = parent.GetChild(i);
            if (child.name == childName)
                return child;

            Transform nested = FindChildByName(child, childName);
            if (nested != null)
                return nested;
        }

        return null;
    }

    private void ConfigureFillImage()
    {
        if (_fillImage == null || !_configureAsFilledImage) return;

        _fillImage.type = Image.Type.Filled;
        _fillImage.fillMethod = Image.FillMethod.Horizontal;
        _fillImage.fillOrigin = (int)Image.OriginHorizontal.Left;
    }
}
