using UnityEngine;

// ============================================================================
// HpBar
// ----------------------------------------------------------------------------
// SpriteRenderer 기반 HP바. Canvas보다 가벼움 (Canvas Rebuild 비용 없음).
//
// 폴링 방식:
//   이벤트 구독 대신 매 프레임 Update에서 Health.Ratio를 직접 읽어 반영한다.
//   - 구독/해제 생명주기가 없어 OnEnable 타이밍 버그가 원천적으로 없음
//   - Update는 항상 모든 Awake 뒤에 실행되므로 Health는 늘 초기화된 상태
//   - 비용: 매 프레임 float 비교 1회 + "비율이 바뀐 프레임"에만 시각 갱신
//
// 구성:
//   - Background와 Fill 두 SpriteRenderer
//   - Fill 스프라이트 피벗은 LEFT (0, 0.5) 여야 X 스케일 변경 시 왼쪽부터 줄어듦
//   - HP 비율에 따라 _fill.localScale.x 조정 + 임계값별 색상 변경
// ============================================================================
public class HpBar : MonoBehaviour
{
    [SerializeField] private Health _health;                       // 비워두면 _autoFindHealthInParent로 자동 검색
    [SerializeField] private Transform _fill;                      // 채움 sprite transform (스케일 조정 대상)
    [SerializeField] private bool _autoFindHealthInParent = true;  // _health가 null이면 부모에서 Health 자동 검색
    [SerializeField] private bool _hideWhenFull = true;            // HP 풀이거나 0일 때 HP바 숨김 (렌더러만 끔)
    [SerializeField] private float _smoothSpeed = 0f;              // 0이면 즉시 반영, 0보다 크면 보간 (ratio/sec)

    // ─── 임계값별 색상 ──────────────────────────────────────────────────
    // ratio > _midThreshold                   → _highColor (정상)
    // _lowThreshold < ratio <= _midThreshold  → _midColor  (주의)
    // ratio <= _lowThreshold                  → _lowColor  (위험)
    [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 Vector3 _baseFillScale;       // 풀체력 시 Fill 스케일 (Awake에 캐싱, 이후 ratio 곱해서 사용)
    private SpriteRenderer _fillRenderer; // Fill 색상 변경용
    private SpriteRenderer[] _renderers;  // 숨김 처리용 — Background + Fill 전부
    private float _currentRatio = 1f;     // 현재 표시 중인 HP 비율 (보간 시 점진적으로 수렴)
    private float _appliedRatio = -1f;    // 마지막으로 시각에 반영한 비율 (중복 갱신 방지, -1이면 첫 프레임 강제 갱신)

    private void Awake()
    {
        if (_health == null && _autoFindHealthInParent)
            _health = GetComponentInParent<Health>();

        if (_fill != null)
        {
            _baseFillScale = _fill.localScale;
            _fillRenderer = _fill.GetComponent<SpriteRenderer>();
        }

        // 숨김 토글 대상: 이 HP바 계층의 모든 SpriteRenderer (Background + Fill).
        _renderers = GetComponentsInChildren<SpriteRenderer>(true);
    }

    // 매 프레임 Health 상태를 폴링해서 반영.
    // 비율이 실제로 바뀐 프레임에만 transform/color를 건드린다 (정지 시 비용 거의 0).
    private void Update()
    {
        if (_health == null) return;

        float target = _health.Ratio;

        if (_smoothSpeed > 0f)
            _currentRatio = Mathf.MoveTowards(_currentRatio, target, _smoothSpeed * Time.deltaTime);
        else
            _currentRatio = target;

        if (Mathf.Approximately(_currentRatio, _appliedRatio)) return;
        _appliedRatio = _currentRatio;

        ApplyScale();
        ApplyColor(_currentRatio);
        ApplyVisibility();
    }

    // Fill의 X 스케일 = baseScale.x × ratio. 피벗이 LEFT여야 왼쪽부터 채워짐.
    private void ApplyScale()
    {
        if (_fill == null) return;

        Vector3 scale = _baseFillScale;
        scale.x = _baseFillScale.x * Mathf.Clamp01(_currentRatio);
        _fill.localScale = scale;
    }

    // 비율 구간 매핑으로 색상 결정. 임계값 교차 시 즉시 바뀜 (보간 안 함).
    private void ApplyColor(float ratio)
    {
        if (_fillRenderer == null) return;

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

    // HP가 풀(1)이거나 사망(0)이면 HP바를 숨김.
    // GameObject가 아니라 SpriteRenderer의 enabled만 끈다 — GameObject를 끄면
    // Update가 멈춰 폴링이 중단되고 다시 켤 수 없게 되기 때문.
    private void ApplyVisibility()
    {
        if (!_hideWhenFull || _renderers == null) return;

        bool visible = _currentRatio > 0f && _currentRatio < 1f;
        for (int i = 0; i < _renderers.Length; i++)
        {
            if (_renderers[i] != null)
                _renderers[i].enabled = visible;
        }
    }
}
