// ---------------------------------------------------------------------------
// BT.Framework
// ObservableList.cs — 변경 이벤트를 내장한 List<T>
// ---------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;

namespace BurningTimes.Core.Container
{
    /// <summary>
    /// 인스턴스 단위로 Add/Remove/Reset 이벤트를 발행하는 <see cref="IList{T}"/> 구현.
    /// </summary>
    /// <remarks>
    /// <para>설계 문서 §3-2 (04_Tier1_3종_상호작용_설계_v1.md). 기존 <c>UniList</c>·<c>UniEventList</c>·<c>UniObserverList</c>
    /// 3종을 본 1종으로 통합했다(§01 §4-3).</para>
    /// <para>계약:</para>
    /// <list type="bullet">
    ///   <item><description>이벤트는 인스턴스 멤버. 전역 전파가 필요하면 호출자가 수신 후 <c>EventBus.Publish</c> 로 다시 발행.</description></item>
    ///   <item><description>이벤트 핸들러에서 재변경이 일어나도 현재 호출은 깨지지 않는다 (내부 snapshot).</description></item>
    ///   <item><description>null 핸들러 안전 (<c>?.Invoke</c>).</description></item>
    ///   <item><description>Reset 은 <see cref="Clear"/> 와 대량 교체( <see cref="ReplaceAll"/> ) 때 발행.</description></item>
    /// </list>
    /// </remarks>
    public class ObservableList<T> : IList<T>, IReadOnlyList<T>
    {
        private readonly List<T> _items;

        /// <summary>Add·Insert 발생 시 발행. 인자는 (index, item).</summary>
        public event Action<int, T> Added;
        /// <summary>Remove·RemoveAt 발생 시 발행. 인자는 (index, item).</summary>
        public event Action<int, T> Removed;
        /// <summary><see cref="Clear"/>·<see cref="ReplaceAll"/> 발생 시 발행.</summary>
        public event Action Reset;

        public ObservableList() { _items = new List<T>(); }
        public ObservableList(int capacity) { _items = new List<T>(capacity); }
        public ObservableList(IEnumerable<T> source) { _items = new List<T>(source); }

        public T this[int index]
        {
            get => _items[index];
            set
            {
                // 인덱서 교체는 "기존 제거 + 신규 추가" 시퀀스로 모델링.
                T old = _items[index];
                _items[index] = value;
                Removed?.Invoke(index, old);
                Added?.Invoke(index, value);
            }
        }

        public int Count => _items.Count;
        public bool IsReadOnly => false;

        public void Add(T item)
        {
            _items.Add(item);
            Added?.Invoke(_items.Count - 1, item);
        }

        public void Insert(int index, T item)
        {
            _items.Insert(index, item);
            Added?.Invoke(index, item);
        }

        public bool Remove(T item)
        {
            int idx = _items.IndexOf(item);
            if (idx < 0) return false;
            RemoveAt(idx);
            return true;
        }

        public void RemoveAt(int index)
        {
            T removed = _items[index];
            _items.RemoveAt(index);
            Removed?.Invoke(index, removed);
        }

        public void Clear()
        {
            if (_items.Count == 0) return;
            _items.Clear();
            Reset?.Invoke();
        }

        /// <summary>전체 원소를 <paramref name="source"/> 로 교체. 단일 Reset 이벤트로 통지.</summary>
        public void ReplaceAll(IEnumerable<T> source)
        {
            _items.Clear();
            if (source != null) _items.AddRange(source);
            Reset?.Invoke();
        }

        public bool Contains(T item) => _items.Contains(item);
        public int IndexOf(T item) => _items.IndexOf(item);
        public void CopyTo(T[] array, int arrayIndex) => _items.CopyTo(array, arrayIndex);
        public List<T>.Enumerator GetEnumerator() => _items.GetEnumerator();
        IEnumerator<T> IEnumerable<T>.GetEnumerator() => _items.GetEnumerator();
        IEnumerator IEnumerable.GetEnumerator() => _items.GetEnumerator();
    }
}
