using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.EntityFrameworkCore;
using Xunit;
using Haoliang.Models.Device;
using Haoliang.Data.Repositories;
using Haoliang.Data.Entities;

namespace Haoliang.Tests
{
    public class DeviceRepositoryTests
    {
        [Fact]
        public void GetAllDevices_WhenNoDevices_ReturnsEmptyList()
        {
            // Arrange
            var options = CreateNewDbContextOptions();
            using var context = new CNCBusinessDbContext(options);
            var repository = new DeviceRepository(context);

            // Act
            var devices = repository.GetAllDevices();

            // Assert
            Assert.Empty(devices);
        }

        [Fact]
        public void CreateDevice_WithValidDevice_ReturnsCreatedDevice()
        {
            // Arrange
            var options = CreateNewDbContextOptions();
            using var context = new CNCBusinessDbContext(options);
            var repository = new DeviceRepository(context);

            var device = new CNCDevice
            {
                DeviceCode = "TEST001",
                DeviceName = "测试设备",
                IPAddress = "192.168.1.100",
                HttpUrl = "http://192.168.1.100/api/status",
                CollectionInterval = 30,
                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);
            Assert.True(createdDevice.CreatedAt > DateTime.MinValue);
            Assert.True(createdDevice.UpdatedAt > DateTime.MinValue);
        }

        [Fact]
        public void GetDeviceById_WithExistingDevice_ReturnsDevice()
        {
            // Arrange
            var options = CreateNewDbContextOptions();
            using var context = new CNCBusinessDbContext(options);
            var repository = new DeviceRepository(context);

            var device = new CNCDevice
            {
                DeviceCode = "TEST002",
                DeviceName = "测试设备2",
                IPAddress = "192.168.1.101",
                HttpUrl = "http://192.168.1.101/api/status",
                CollectionInterval = 60,
                TemplateId = 1,
                IsAvailable = true,
                IsOnline = true
            };

            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);
            Assert.Equal("测试设备2", retrievedDevice.DeviceName);
        }

        [Fact]
        public void GetDeviceById_WithNonExistingId_ReturnsNull()
        {
            // Arrange
            var options = CreateNewDbContextOptions();
            using var context = new CNCBusinessDbContext(options);
            var repository = new DeviceRepository(context);

            // Act
            var device = repository.GetDeviceById(999);

            // Assert
            Assert.Null(device);
        }

        [Fact]
        public void GetDeviceByCode_WithExistingCode_ReturnsDevice()
        {
            // Arrange
            var options = CreateNewDbContextOptions();
            using var context = new CNCBusinessDbContext(options);
            var repository = new DeviceRepository(context);

            var device = new CNCDevice
            {
                DeviceCode = "TEST003",
                DeviceName = "测试设备3",
                IPAddress = "192.168.1.102",
                HttpUrl = "http://192.168.1.102/api/status",
                CollectionInterval = 45,
                TemplateId = 1,
                IsAvailable = false,
                IsOnline = false
            };

            repository.CreateDevice(device);

            // Act
            var retrievedDevice = repository.GetDeviceByCode("TEST003");

            // Assert
            Assert.NotNull(retrievedDevice);
            Assert.Equal("TEST003", retrievedDevice.DeviceCode);
        }

        [Fact]
        public void GetOnlineDevices_WithMixedDevices_ReturnsOnlyOnlineDevices()
        {
            // Arrange
            var options = CreateNewDbContextOptions();
            using var context = new CNCBusinessDbContext(options);
            var repository = new DeviceRepository(context);

            // Create online device
            var onlineDevice = new CNCDevice
            {
                DeviceCode = "ONLINE001",
                DeviceName = "在线设备",
                IsOnline = true,
                IsAvailable = true
            };
            repository.CreateDevice(onlineDevice);

            // Create offline device
            var offlineDevice = new CNCDevice
            {
                DeviceCode = "OFFLINE001",
                DeviceName = "离线设备",
                IsOnline = false,
                IsAvailable = true
            };
            repository.CreateDevice(offlineDevice);

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

            // Assert
            Assert.Single(onlineDevices);
            Assert.Equal("ONLINE001", onlineDevices.First().DeviceCode);
        }

        [Fact]
        public void UpdateDevice_WithValidDevice_UpdatesDevice()
        {
            // Arrange
            var options = CreateNewDbContextOptions();
            using var context = new CNCBusinessDbContext(options);
            var repository = new DeviceRepository(context);

            var device = new CNCDevice
            {
                DeviceCode = "TEST004",
                DeviceName = "原始名称",
                IPAddress = "192.168.1.103",
                HttpUrl = "http://192.168.1.103/api/status",
                CollectionInterval = 30,
                TemplateId = 1,
                IsAvailable = true,
                IsOnline = true
            };

            var createdDevice = repository.CreateDevice(device);

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

            // Assert
            Assert.NotNull(updatedDevice);
            Assert.Equal("更新后的名称", updatedDevice.DeviceName);
            Assert.False(updatedDevice.IsAvailable);
            Assert.True(updatedDevice.UpdatedAt > createdDevice.CreatedAt);
        }

        [Fact]
        public void DeleteDevice_WithExistingId_DeletesDevice()
        {
            // Arrange
            var options = CreateNewDbContextOptions();
            using var context = new CNCBusinessDbContext(options);
            var repository = new DeviceRepository(context);

            var device = new CNCDevice
            {
                DeviceCode = "DELETE001",
                DeviceName = "待删除设备",
                IPAddress = "192.168.1.104",
                HttpUrl = "http://192.168.1.104/api/status",
                CollectionInterval = 30,
                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);
        }

        private static Microsoft.EntityFrameworkCore.DbContextOptions<CNCBusinessDbContext> CreateNewDbContextOptions()
        {
            var optionsBuilder = new Microsoft.EntityFrameworkCore.DbContextOptionsBuilder<CNCBusinessDbContext>();
            optionsBuilder.UseInMemoryDatabase("TestDatabase_" + Guid.NewGuid().ToString());
            return optionsBuilder.Options;
        }
    }
}