using System;
using Xunit;
using CncCollector.Core;

namespace CncCollector.Tests
{
    /// <summary>
    /// ProductionTracker 单元测试。
    /// ProductionTracker 直接使用 MySqlConnection，无法通过 Moq 注入，
    /// 因此使用无效连接字符串验证容错行为（不抛异常）。
    /// </summary>
    public class ProductionTrackerTests : IDisposable
    {
        /// <summary>无效连接字符串，用于触发错误处理路径</summary>
        private const string InvalidConnStr = "Server=invalid;Database=invalid;User Id=invalid;Password=invalid;";

        private ProductionTracker _tracker;

        public ProductionTrackerTests()
        {
            _tracker = new ProductionTracker(InvalidConnStr);
        }

        public void Dispose()
        {
            _tracker?.Dispose();
        }

        // ===== 构造函数测试 =====

        [Fact]
        public void 构造函数_正常创建()
        {
            var tracker = new ProductionTracker(InvalidConnStr);
            Assert.NotNull(tracker);
        }

        [Fact]
        public void 构造函数_null连接字符串_正常创建()
        {
            // 构造函数本身不做连接验证，允许 null
            var tracker = new ProductionTracker(null);
            Assert.NotNull(tracker);
        }

        // ===== Track 方法测试 =====

        [Fact]
        public void Track_无效DB连接_不抛异常()
        {
            // 使用无效连接字符串调用 Track，内部 DB 操作会失败但不应该向外抛出异常
            var ex = Record.Exception(() => _tracker.Track(1, "O0001", 100m, DateTime.Now));
            Assert.Null(ex);
        }

        [Fact]
        public void Track_空程序名_不抛异常()
        {
            // programName 为空时应提前返回，不做任何 DB 操作
            var ex = Record.Exception(() => _tracker.Track(1, "", 100m, DateTime.Now));
            Assert.Null(ex);
        }

        [Fact]
        public void Track_null程序名_不抛异常()
        {
            var ex = Record.Exception(() => _tracker.Track(1, null, 100m, DateTime.Now));
            Assert.Null(ex);
        }

        [Fact]
        public void Track_partCount为null_不抛异常()
        {
            var ex = Record.Exception(() => _tracker.Track(1, "O0001", null, DateTime.Now));
            Assert.Null(ex);
        }

        [Fact]
        public void Track_连续调用不同程序_不抛异常()
        {
            // 模拟程序切换场景
            var ex1 = Record.Exception(() => _tracker.Track(1, "O0001", 10m, DateTime.Now));
            Assert.Null(ex1);

            var ex2 = Record.Exception(() => _tracker.Track(1, "O0002", 5m, DateTime.Now));
            Assert.Null(ex2);
        }

        [Fact]
        public void Track_零件数下降_不抛异常()
        {
            // 模拟手动清零场景：同程序下 partCount 下降
            var ex1 = Record.Exception(() => _tracker.Track(1, "O0001", 100m, DateTime.Now));
            Assert.Null(ex1);

            var ex2 = Record.Exception(() => _tracker.Track(1, "O0001", 5m, DateTime.Now));
            Assert.Null(ex2);
        }

        [Fact]
        public void Track_多台机床并行_不抛异常()
        {
            var ex1 = Record.Exception(() => _tracker.Track(1, "O0001", 10m, DateTime.Now));
            Assert.Null(ex1);

            var ex2 = Record.Exception(() => _tracker.Track(2, "O0002", 20m, DateTime.Now));
            Assert.Null(ex2);

            var ex3 = Record.Exception(() => _tracker.Track(3, "O0003", 30m, DateTime.Now));
            Assert.Null(ex3);
        }

        // ===== CloseActiveSegment 测试 =====

        [Fact]
        public void CloseActiveSegment_无活跃段_不抛异常()
        {
            var ex = Record.Exception(() => _tracker.CloseActiveSegment(999, 100m, "program_change", DateTime.Now));
            Assert.Null(ex);
        }

        [Fact]
        public void CloseActiveSegment_null参数_不抛异常()
        {
            var ex = Record.Exception(() => _tracker.CloseActiveSegment(1, null, "manual_reset", DateTime.Now));
            Assert.Null(ex);
        }

        // ===== CloseAllActiveSegments 测试 =====

        [Fact]
        public void CloseAllActiveSegments_无活跃段_不抛异常()
        {
            var ex = Record.Exception(() => _tracker.CloseAllActiveSegments());
            Assert.Null(ex);
        }

        [Fact]
        public void CloseAllActiveSegments_有Track记录_不抛异常()
        {
            // 先 Track 产生内存缓存，再 CloseAll
            _tracker.Track(1, "O0001", 10m, DateTime.Now);

            var ex = Record.Exception(() => _tracker.CloseAllActiveSegments());
            Assert.Null(ex);
        }

        // ===== Dispose 测试 =====

        [Fact]
        public void Dispose_正常调用_不抛异常()
        {
            var tracker = new ProductionTracker(InvalidConnStr);
            var ex = Record.Exception(() => tracker.Dispose());
            Assert.Null(ex);
        }

        [Fact]
        public void Dispose_多次调用_不抛异常()
        {
            var tracker = new ProductionTracker(InvalidConnStr);
            tracker.Dispose();
            tracker.Dispose(); // 二次调用不应抛异常
        }
    }
}
