using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace NavisworksTransport.UnitTests
{
    /// <summary>
    /// ThreadSafeObservableCollection基础功能测试
    /// 只包含可以在控制台环境下稳定运行的纯数据操作测试，不涉及事件
    /// </summary>
    [TestClass]
    public class ThreadSafeObservableCollectionBasicTests
    {
        private ThreadSafeObservableCollection<string> _collection;

        [TestInitialize]
        public void Setup()
        {
            _collection = new ThreadSafeObservableCollection<string>();
        }

        [TestCleanup]
        public void Cleanup()
        {
            _collection = null;
        }

        #region 构造函数测试

        [TestMethod]
        public void Constructor_ShouldCreateEmptyCollection()
        {
            // Arrange & Act
            var collection = new ThreadSafeObservableCollection<int>();

            // Assert
            Assert.AreEqual(0, collection.Count, "新创建的集合应该为空");
        }

        [TestMethod]
        public void Constructor_WithInitialItems_ShouldContainAllItems()
        {
            // Arrange
            var initialItems = new[] { "A", "B", "C" };

            // Act
            var collection = new ThreadSafeObservableCollection<string>(initialItems);

            // Assert
            Assert.AreEqual(3, collection.Count, "集合应该包含所有初始元素");
            var snapshot = collection.ToSnapshot();
            CollectionAssert.AreEqual(initialItems, snapshot, "集合内容应该与初始元素相同");
        }

        #endregion

        #region 基础数据操作测试

        [TestMethod]
        public void Add_ShouldIncreaseCount()
        {
            // Arrange
            var item = "TestItem";

            // Act
            _collection.Add(item);

            // Assert
            Assert.AreEqual(1, _collection.Count, "添加元素后集合计数应该增加");
            Assert.IsTrue(_collection.Contains(item), "集合应该包含添加的元素");
        }

        [TestMethod]
        public void Remove_ShouldDecreaseCount()
        {
            // Arrange
            var item = "TestItem";
            _collection.Add(item);

            // Act
            var result = _collection.Remove(item);

            // Assert
            Assert.IsTrue(result, "移除已存在的元素应该返回true");
            Assert.AreEqual(0, _collection.Count, "移除元素后集合计数应该减少");
            Assert.IsFalse(_collection.Contains(item), "集合不应该包含已移除的元素");
        }

        [TestMethod]
        public void Insert_ShouldInsertAtCorrectPosition()
        {
            // Arrange
            _collection.Add("A");
            _collection.Add("C");

            // Act
            _collection.Insert(1, "B");

            // Assert
            Assert.AreEqual(3, _collection.Count, "插入元素后集合计数应该增加");
            Assert.AreEqual("B", _collection[1], "元素应该被插入到正确位置");
            var snapshot = _collection.ToSnapshot();
            CollectionAssert.AreEqual(new[] { "A", "B", "C" }, snapshot, "集合顺序应该正确");
        }

        [TestMethod]
        public void Clear_ShouldRemoveAllItems()
        {
            // Arrange
            _collection.Add("A");
            _collection.Add("B");
            _collection.Add("C");

            // Act
            _collection.Clear();

            // Assert
            Assert.AreEqual(0, _collection.Count, "清空后集合应该为空");
        }

        #endregion

        #region 批量操作测试

        [TestMethod]
        public void AddRange_ShouldAddAllItems()
        {
            // Arrange
            var items = new[] { "A", "B", "C" };

            // Act
            _collection.AddRange(items);

            // Assert
            Assert.AreEqual(3, _collection.Count, "AddRange应该添加所有元素");
            var snapshot = _collection.ToSnapshot();
            CollectionAssert.AreEqual(items, snapshot, "集合内容应该与添加的元素相同");
        }

        [TestMethod]
        public void AddRange_WithEmptyCollection_ShouldNotChangeCount()
        {
            // Arrange
            var emptyItems = new string[0];

            // Act
            _collection.AddRange(emptyItems);

            // Assert
            Assert.AreEqual(0, _collection.Count, "添加空集合不应该改变计数");
        }

        [TestMethod]
        public void RemoveRange_ShouldRemoveMatchingItems()
        {
            // Arrange
            _collection.AddRange(new[] { "A", "B", "C", "D" });
            var itemsToRemove = new[] { "B", "D" };

            // Act
            var removedCount = _collection.RemoveRange(itemsToRemove);

            // Assert
            Assert.AreEqual(2, removedCount, "应该移除2个元素");
            Assert.AreEqual(2, _collection.Count, "移除后集合应该包含2个元素");
            var snapshot = _collection.ToSnapshot();
            CollectionAssert.AreEqual(new[] { "A", "C" }, snapshot, "剩余元素应该正确");
        }

        [TestMethod]
        public void ClearAndAddRange_ShouldReplaceAllItems()
        {
            // Arrange
            _collection.AddRange(new[] { "Old1", "Old2" });
            var newItems = new[] { "New1", "New2", "New3" };

            // Act
            _collection.ClearAndAddRange(newItems);

            // Assert
            Assert.AreEqual(3, _collection.Count, "替换后集合应该包含新元素的数量");
            var snapshot = _collection.ToSnapshot();
            CollectionAssert.AreEqual(newItems, snapshot, "集合内容应该是新元素");
        }

        #endregion

        #region 查询操作测试

        [TestMethod]
        public void FirstOrDefault_ShouldReturnCorrectItem()
        {
            // Arrange
            _collection.AddRange(new[] { "Apple", "Banana", "Cherry" });

            // Act
            var result = _collection.FirstOrDefault(item => item.StartsWith("B"));

            // Assert
            Assert.AreEqual("Banana", result, "FirstOrDefault应该返回第一个匹配的元素");
        }

        [TestMethod]
        public void Count_WithPredicate_ShouldReturnCorrectCount()
        {
            // Arrange
            _collection.AddRange(new[] { "Apple", "Banana", "Apricot", "Cherry" });

            // Act
            var count = _collection.Count(item => item.StartsWith("A"));

            // Assert
            Assert.AreEqual(2, count, "Count应该返回满足条件的元素数量");
        }

        [TestMethod]
        public void Any_WithPredicate_ShouldReturnCorrectResult()
        {
            // Arrange
            _collection.AddRange(new[] { "Apple", "Banana", "Cherry" });

            // Act
            var hasZ = _collection.Any(item => item.StartsWith("Z"));
            var hasA = _collection.Any(item => item.StartsWith("A"));

            // Assert
            Assert.IsFalse(hasZ, "不存在以Z开头的元素时Any应该返回false");
            Assert.IsTrue(hasA, "存在以A开头的元素时Any应该返回true");
        }

        [TestMethod]
        public void ToSnapshot_ShouldReturnCurrentState()
        {
            // Arrange
            _collection.AddRange(new[] { "A", "B", "C" });

            // Act
            var snapshot1 = _collection.ToSnapshot();
            _collection.Add("D");
            var snapshot2 = _collection.ToSnapshot();

            // Assert
            CollectionAssert.AreEqual(new[] { "A", "B", "C" }, snapshot1, "第一个快照应该不包含后添加的元素");
            CollectionAssert.AreEqual(new[] { "A", "B", "C", "D" }, snapshot2, "第二个快照应该包含后添加的元素");
        }

        #endregion

        #region 异常处理测试

        [TestMethod]
        public void Add_WithNull_ShouldThrowArgumentNullException()
        {
            // Act & Assert
            Assert.ThrowsException<ArgumentNullException>(() =>
            {
                _collection.Add(null);
            }, "添加null元素应该抛出ArgumentNullException");
        }

        [TestMethod]
        public void AddRange_WithNull_ShouldThrowArgumentNullException()
        {
            // Act & Assert
            Assert.ThrowsException<ArgumentNullException>(() =>
            {
                _collection.AddRange(null);
            }, "AddRange传入null应该抛出ArgumentNullException");
        }

        [TestMethod]
        public void IndexAccess_WithInvalidIndex_ShouldThrowArgumentOutOfRangeException()
        {
            // Arrange
            _collection.Add("OnlyItem");

            // Act & Assert
            Assert.ThrowsException<ArgumentOutOfRangeException>(() =>
            {
                var item = _collection[5]; // 无效索引
            }, "访问无效索引应该抛出ArgumentOutOfRangeException");
        }

        #endregion
    }
}