// ---------------------------------------------------------------------------
// BT.Framework.Tests
// ObservableListTests.cs — ObservableList 단위 테스트
// ---------------------------------------------------------------------------
using System.Collections.Generic;
using NUnit.Framework;
using BurningTimes.Core.Container;

namespace BurningTimes.Tests.Core.Container
{
    public class ObservableListTests
    {
        [Test]
        public void Add_EmitsAddedWithIndex()
        {
            var list = new ObservableList<string>();
            int? capturedIndex = null;
            string capturedItem = null;
            list.Added += (i, v) => { capturedIndex = i; capturedItem = v; };

            list.Add("a");

            Assert.That(capturedIndex, Is.EqualTo(0));
            Assert.That(capturedItem, Is.EqualTo("a"));
        }

        [Test]
        public void Insert_EmitsAddedAtCorrectIndex()
        {
            var list = new ObservableList<int> { 10, 20, 30 };
            var events = new List<(int, int)>();
            list.Added += (i, v) => events.Add((i, v));

            list.Insert(1, 15);

            Assert.That(list, Is.EqualTo(new[] { 10, 15, 20, 30 }));
            Assert.That(events, Is.EqualTo(new[] { (1, 15) }));
        }

        [Test]
        public void RemoveAt_EmitsRemovedWithOldItem()
        {
            var list = new ObservableList<int> { 1, 2, 3 };
            var events = new List<(int, int)>();
            list.Removed += (i, v) => events.Add((i, v));

            list.RemoveAt(1);

            Assert.That(events, Is.EqualTo(new[] { (1, 2) }));
            Assert.That(list, Is.EqualTo(new[] { 1, 3 }));
        }

        [Test]
        public void Remove_ReturnsFalseForMissingItem()
        {
            var list = new ObservableList<int> { 1, 2 };
            int eventCount = 0;
            list.Removed += (_, __) => eventCount++;

            Assert.IsFalse(list.Remove(99));
            Assert.That(eventCount, Is.EqualTo(0));
        }

        [Test]
        public void Clear_EmitsReset()
        {
            var list = new ObservableList<int> { 1, 2, 3 };
            int resetCount = 0;
            list.Reset += () => resetCount++;

            list.Clear();

            Assert.That(resetCount, Is.EqualTo(1));
            Assert.That(list.Count, Is.EqualTo(0));
        }

        [Test]
        public void Clear_OnEmptyList_DoesNotEmitReset()
        {
            var list = new ObservableList<int>();
            int resetCount = 0;
            list.Reset += () => resetCount++;

            list.Clear();

            Assert.That(resetCount, Is.EqualTo(0));
        }

        [Test]
        public void Indexer_EmitsRemovedThenAdded()
        {
            var list = new ObservableList<int> { 10, 20, 30 };
            var sequence = new List<string>();
            list.Removed += (i, v) => sequence.Add($"-{i}:{v}");
            list.Added += (i, v) => sequence.Add($"+{i}:{v}");

            list[1] = 99;

            Assert.That(sequence, Is.EqualTo(new[] { "-1:20", "+1:99" }));
        }

        [Test]
        public void ReplaceAll_EmitsSingleReset()
        {
            var list = new ObservableList<int> { 1, 2 };
            int resetCount = 0;
            int addedCount = 0;
            list.Reset += () => resetCount++;
            list.Added += (_, __) => addedCount++;

            list.ReplaceAll(new[] { 10, 20, 30 });

            Assert.That(resetCount, Is.EqualTo(1));
            Assert.That(addedCount, Is.EqualTo(0), "대량 교체는 Added 를 발행하지 않는다");
            Assert.That(list, Is.EqualTo(new[] { 10, 20, 30 }));
        }

        [Test]
        public void HandlerReentrancy_DoesNotBreakCurrentCall()
        {
            var list = new ObservableList<int>();
            int innerAdds = 0;
            list.Added += (i, v) =>
            {
                if (v == 1) { /* 추가 호출 없음 */ }
                innerAdds++;
            };

            list.Add(1);
            list.Add(2);

            Assert.That(list.Count, Is.EqualTo(2));
            Assert.That(innerAdds, Is.EqualTo(2));
        }

        [Test]
        public void NullHandler_IsSafe()
        {
            var list = new ObservableList<int>();
            Assert.DoesNotThrow(() => list.Add(1));
            Assert.DoesNotThrow(() => list.Clear());
        }
    }
}
