using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CNCSystem.Data.Repositories;
using CNCSystem.Models.Device;
using CNCSystem.Models.Template;
using CNCSystem.Models.Production;

namespace CNCSystem.Tests
{
    public class DeviceTests
    {
        [Fact]
        public void CreateDevice_ShouldCreateNewDevice()
        {
            // Arrange
            var context = new CNCBusinessDbContext();
            var repository = new DeviceRepository(context);
            var device = new CNCDevice
            {
                DeviceCode = "TEST001",
                DeviceName = "测试设备",
                IPAddress = "192.168.1.100",
                HttpUrl = "http://192.168.1.100/data",
                CollectionInterval = 60,
                TemplateId = 1,
                IsAvailable = true,
                IsOnline = true
            };

            // Act
            var createdDevice = repository.CreateDevice(device);

            // Assert
            Assert.NotNull(createdDevice);
            Assert.True(createdDevice.Id > 0);
            Assert.Equal("TEST001", createdDevice.DeviceCode);
            Assert.Equal("测试设备", createdDevice.DeviceName);
        }

        [Fact]
        public void GetDeviceById_ShouldReturnCorrectDevice()
        {
            // Arrange
            var context = new CNCBusinessDbContext();
            var repository = new DeviceRepository(context);
            var device = new CNCDevice
            {
                DeviceCode = "TEST002",
                DeviceName = "测试设备2",
                IPAddress = "192.168.1.101",
                HttpUrl = "http://192.168.1.101/data",
                CollectionInterval = 60,
                TemplateId = 1,
                IsAvailable = true,
                IsOnline = false
            };

            var createdDevice = repository.CreateDevice(device);

            // Act
            var retrievedDevice = repository.GetDeviceById(createdDevice.Id);

            // Assert
            Assert.NotNull(retrievedDevice);
            Assert.Equal(createdDevice.Id, retrievedDevice.Id);
            Assert.Equal("TEST002", retrievedDevice.DeviceCode);
        }

        [Fact]
        public void UpdateDevice_ShouldUpdateSuccessfully()
        {
            // Arrange
            var context = new CNCBusinessDbContext();
            var repository = new DeviceRepository(context);
            var device = new CNCDevice
            {
                DeviceCode = "TEST003",
                DeviceName = "测试设备3",
                IPAddress = "192.168.1.102",
                HttpUrl = "http://192.168.1.102/data",
                CollectionInterval = 60,
                TemplateId = 1,
                IsAvailable = false,
                IsOnline = false
            };

            var createdDevice = repository.CreateDevice(device);

            // Act
            createdDevice.DeviceName = "更新后的设备名称";
            createdDevice.IsAvailable = true;
            var updatedDevice = repository.UpdateDevice(createdDevice);

            // Assert
            Assert.NotNull(updatedDevice);
            Assert.Equal("更新后的设备名称", updatedDevice.DeviceName);
            Assert.True(updatedDevice.IsAvailable);
        }

        [Fact]
        public void DeleteDevice_ShouldDeleteSuccessfully()
        {
            // Arrange
            var context = new CNCBusinessDbContext();
            var repository = new DeviceRepository(context);
            var device = new CNCDevice
            {
                DeviceCode = "TEST004",
                DeviceName = "测试设备4",
                IPAddress = "192.168.1.103",
                HttpUrl = "http://192.168.1.103/data",
                CollectionInterval = 60,
                TemplateId = 1,
                IsAvailable = true,
                IsOnline = true
            };

            var createdDevice = repository.CreateDevice(device);

            // Act
            repository.DeleteDevice(createdDevice.Id);

            // Assert
            var deletedDevice = repository.GetDeviceById(createdDevice.Id);
            Assert.Null(deletedDevice);
        }

        [Fact]
        public void GetOnlineDevices_ShouldReturnOnlineDevicesOnly()
        {
            // Arrange
            var context = new CNCBusinessDbContext();
            var repository = new DeviceRepository(context);
            
            // 创建一些测试数据
            var onlineDevice = new CNCDevice
            {
                DeviceCode = "ONLINE001",
                DeviceName = "在线设备",
                IPAddress = "192.168.1.100",
                HttpUrl = "http://192.168.1.100/data",
                CollectionInterval = 60,
                TemplateId = 1,
                IsAvailable = true,
                IsOnline = true
            };

            var offlineDevice = new CNCDevice
            {
                DeviceCode = "OFFLINE001",
                DeviceName = "离线设备",
                IPAddress = "192.168.1.101",
                HttpUrl = "http://192.168.1.101/data",
                CollectionInterval = 60,
                TemplateId = 1,
                IsAvailable = true,
                IsOnline = false
            };

            repository.CreateDevice(onlineDevice);
            repository.CreateDevice(offlineDevice);

            // Act
            var onlineDevices = repository.GetOnlineDevices();

            // Assert
            Assert.NotEmpty(onlineDevices);
            Assert.All(onlineDevices, d => Assert.True(d.IsOnline));
            Assert.DoesNotContain(onlineDevices, d => d.DeviceCode == "OFFLINE001");
        }
    }

    public class TemplateTests
    {
        [Fact]
        public void CreateTemplate_ShouldCreateNewTemplate()
        {
            // Arrange
            var context = new CNCBusinessDbContext();
            var repository = new TemplateRepository(context);
            var template = new CNCBrandTemplate
            {
                BrandName = "发那科",
                Description = "发那科CNC设备模板",
                IsEnabled = true,
                FieldMappings = new List<TemplateFieldMapping>
                {
                    new TemplateFieldMapping
                    {
                        SourceFieldPath = "device.tags[0].id",
                        StandardFieldId = "_io_status",
                        StandardFieldDesc = "设备状态",
                        DataType = "string",
                        ConversionRule = new ConversionRule
                        {
                            Type = "direct"
                        }
                    }
                }
            };

            // Act
            var createdTemplate = repository.CreateTemplate(template);

            // Assert
            Assert.NotNull(createdTemplate);
            Assert.True(createdTemplate.Id > 0);
            Assert.Equal("发那科", createdTemplate.BrandName);
            Assert.True(createdTemplate.IsEnabled);
        }

        [Fact]
        public void GetEnabledTemplates_ShouldReturnEnabledTemplatesOnly()
        {
            // Arrange
            var context = new CNCBusinessDbContext();
            var repository = new TemplateRepository(context);
            
            // 创建一些测试数据
            var enabledTemplate = new CNCBrandTemplate
            {
                BrandName = "西门子",
                Description = "西门子CNC设备模板",
                IsEnabled = true,
                FieldMappings = new List<TemplateFieldMapping>()
            };

            var disabledTemplate = new CNCBrandTemplate
            {
                BrandName = "三菱",
                Description = "三菱CNC设备模板",
                IsEnabled = false,
                FieldMappings = new List<TemplateFieldMapping>()
            };

            repository.CreateTemplate(enabledTemplate);
            repository.CreateTemplate(disabledTemplate);

            // Act
            var enabledTemplates = repository.GetEnabledTemplates();

            // Assert
            Assert.NotEmpty(enabledTemplates);
            Assert.All(enabledTemplates, t => Assert.True(t.IsEnabled));
            Assert.DoesNotContain(enabledTemplates, t => t.BrandName == "三菱");
        }
    }

    public class ProductionTests
    {
        [Fact]
        public void CreateProductionRecord_ShouldCreateNewRecord()
        {
            // Arrange
            var context = new CNCBusinessDbContext();
            var repository = new ProductionRepository(context);
            var record = new ProductionRecord
            {
                DeviceId = 1,
                NCProgram = "TEST_PROGRAM_001",
                ProductionDate = DateTime.Today,
                Quantity = 100,
                QualityRate = 99.5m
            };

            // Act
            var createdRecord = repository.CreateProductionRecord(record);

            // Assert
            Assert.NotNull(createdRecord);
            Assert.True(createdRecord.Id > 0);
            Assert.Equal("TEST_PROGRAM_001", createdRecord.NCProgram);
            Assert.Equal(100, createdRecord.Quantity);
            Assert.Equal(99.5m, createdRecord.QualityRate);
        }

        [Fact]
        public void GetProductionRecords_ShouldFilterByDeviceId()
        {
            // Arrange
            var context = new CNCBusinessDbContext();
            var repository = new ProductionRepository(context);
            
            // 创建一些测试数据
            var device1Record = new ProductionRecord
            {
                DeviceId = 1,
                NCProgram = "PROGRAM_001",
                ProductionDate = DateTime.Today,
                Quantity = 50,
                QualityRate = 99.0m
            };

            var device2Record = new ProductionRecord
            {
                DeviceId = 2,
                NCProgram = "PROGRAM_002",
                ProductionDate = DateTime.Today,
                Quantity = 75,
                QualityRate = 98.5m
            };

            repository.CreateProductionRecord(device1Record);
            repository.CreateProductionRecord(device2Record);

            // Act
            var device1Records = repository.GetProductionRecords(deviceId: 1);

            // Assert
            Assert.NotEmpty(device1Records);
            Assert.All(device1Records, r => Assert.Equal(1, r.DeviceId));
            Assert.DoesNotContain(device1Records, r => r.DeviceId == 2);
        }

        [Fact]
        public void CalculateProduction_ShouldCalculateCorrectly()
        {
            // Arrange
            var lastStatus = new DeviceCurrentStatus
            {
                DeviceId = 1,
                NCProgram = "PROGRAM_001",
                CumulativeCount = 1000,
                RecordTime = DateTime.Now.AddMinutes(-10)
            };

            var currentStatus = new DeviceCurrentStatus
            {
                DeviceId = 1,
                NCProgram = "PROGRAM_001",
                CumulativeCount = 1050,
                RecordTime = DateTime.Now
            };

            // Act
            var production = ProductionCalculator.CalculateProduction(currentStatus, lastStatus);

            // Assert
            Assert.Equal(50, production); // 1050 - 1000 = 50
        }
    }

    public static class TestUtils
    {
        public static void ClearTestDatabase()
        {
            try
            {
                var context = new CNCBusinessDbContext();
                
                // 清理测试数据
                context.ProductionRecords.RemoveRange(context.ProductionRecords);
                context.DeviceStatus.RemoveRange(context.DeviceStatus);
                context.Devices.RemoveRange(context.Devices);
                context.CNCTemplates.RemoveRange(context.CNCTemplates);
                context.TemplateFieldMappings.RemoveRange(context.TemplateFieldMappings);
                
                context.SaveChanges();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"清理测试数据库时发生错误: {ex.Message}");
            }
        }
    }
}