using audit_logs.Models.DTO;
using audit.Model;
using Newtonsoft.Json;

namespace audit_test.Repository;

using audit_logs.Models;
using audit_logs.Services;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

public class AuditServiceFilterTests
{
        private AuditService _service;

        [SetUp]
        public void Setup()
        {
            // Limpia la base de datos antes de cada prueba
            IntegrationDb.Database.DropCollectionAsync("audit_records").Wait();
            _service = new AuditService(IntegrationDb.Database);
           
        }

        [Test]
        public async Task GetAuditLogsAsync_FilterByUserId_ReturnsMatchingRecords()
        {
            // Arrange
            var records = new List<AuditRecord>
            {
                new AuditRecord
                {
                    EntityType = "User",
                    RecordId = "1",
                    UserId = "User123",
                    ActionType = "Create",
                    ActionTime = DateTime.UtcNow.AddMinutes(-10),
                    Reason = "Testing filter",
                    Changes = new List<AuditRecord.Change>()
                },
                new AuditRecord
                {
                    EntityType = "Admin",
                    RecordId = "2",
                    UserId = "User456",
                    ActionType = "Delete",
                    ActionTime = DateTime.UtcNow,
                    Reason = "Testing filter",
                    Changes = new List<AuditRecord.Change>()
                }
            };

            foreach (var record in records)
            {
                await _service.AuditLogRepository.InsertOneAsync(record);
            }
            SpecificAuditLogFilterDto auditLogParametersDto = new SpecificAuditLogFilterDto();
            auditLogParametersDto.pageNumber=1;
            auditLogParametersDto.pageSize = 10;
            auditLogParametersDto.userId="User123";

            // Act
            var paginatedResult = await _service.GetAuditLogsBySpecificFilterAsync(auditLogParametersDto);

            // Assert
            // Assert
            Assert.That(paginatedResult.Records.Count(), Is.EqualTo(1), "Should return only records matching the UserId.");
            var result = paginatedResult.Records.First();
            Assert.That(result.UserId, Is.EqualTo("User123"), "The UserId should match the filter.");

        }

        [Test]
        public async Task GetAuditLogsAsync_FilterByRecordId_ReturnsMatchingRecords()
        {
            // Arrange
            var records = new List<AuditRecord>
            {
                new AuditRecord
                {
                    EntityType = "User",
                    RecordId = "Record123",
                    UserId = "User123",
                    ActionType = "Create",
                    ActionTime = DateTime.UtcNow.AddMinutes(-10),
                    Reason = "Testing filter",
                    Changes = new List<AuditRecord.Change>()
                },
                new AuditRecord
                {
                    EntityType = "Admin",
                    RecordId = "Record456",
                    UserId = "User456",
                    ActionType = "Delete",
                    ActionTime = DateTime.UtcNow,
                    Reason = "Testing filter",
                    Changes = new List<AuditRecord.Change>()
                }
            };

            foreach (var record in records)
            {
                await _service.AuditLogRepository.InsertOneAsync(record);
            }
            SpecificAuditLogFilterDto auditLogParametersDto = new SpecificAuditLogFilterDto();
            auditLogParametersDto.pageNumber=1;
            auditLogParametersDto.pageSize = 10;
            auditLogParametersDto.userId="User123";

            // Act
            var paginatedResult = await _service.GetAuditLogsBySpecificFilterAsync(auditLogParametersDto);

            // Assert
            // Assert
            Assert.That(paginatedResult.Records.Count(), Is.EqualTo(1), "Should return only records matching the RecordId.");
            var result = paginatedResult.Records.First();
            Assert.That(result.RecordId, Is.EqualTo("Record123"), "The RecordId should match the filter.");

        }

        [Test]
        public async Task GetAuditLogsAsync_FilterByDateRange_ReturnsMatchingRecords()
        {
            // Arrange
            var now = DateTime.UtcNow;
            var records = new List<AuditRecord>
            {
                new AuditRecord
                {
                    EntityType = "User",
                    RecordId = "1",
                    UserId = "User1",
                    ActionType = "Create",
                    ActionTime = now.AddDays(-2),
                    Reason = "Old record",
                    Changes = new List<AuditRecord.Change>()
                },
                new AuditRecord
                {
                    EntityType = "Admin",
                    RecordId = "2",
                    UserId = "User2",
                    ActionType = "Update",
                    ActionTime = now,
                    Reason = "Current record",
                    Changes = new List<AuditRecord.Change>()
                }
            };

            foreach (var record in records)
            {
                await _service.AuditLogRepository.InsertOneAsync(record);
            }
            SpecificAuditLogFilterDto auditLogParametersDto = new SpecificAuditLogFilterDto();
            auditLogParametersDto.pageNumber=1;
            auditLogParametersDto.pageSize = 10;
            auditLogParametersDto.startDate=now.AddDays(-1);
            auditLogParametersDto.endDate=now;

            // Act
            var paginatedResult = await _service.GetAuditLogsBySpecificFilterAsync(auditLogParametersDto);

            // Assert
            // Assert
            Assert.That(paginatedResult.Records.Count(), Is.EqualTo(1), "Should return only records within the date range.");
            var result = paginatedResult.Records.First();
            Assert.That(result.RecordId, Is.EqualTo("2"), "Only the record within the date range should be returned.");

        }

        [Test]
        public async Task GetAuditLogsAsync_CombinationOfFilters_ReturnsMatchingRecords()
        {
            // Arrange
            var now = DateTime.UtcNow;
            var records = new List<AuditRecord>
            {
                new AuditRecord
                {
                    EntityType = "User",
                    RecordId = "123",
                    UserId = "User123",
                    ActionType = "Create",
                    ActionTime = now.AddDays(-1),
                    Reason = "Testing combinatoin filter",
                    Changes = new List<AuditRecord.Change>()
                },
                new AuditRecord
                {
                    EntityType = "Admin",
                    RecordId = "456",
                    UserId = "User456",
                    ActionType = "Delete",
                    ActionTime = now,
                    Reason = "Testng combination filter",
                    Changes = new List<AuditRecord.Change>()
                }
            };

            foreach (var record in records)
            {
                await _service.AuditLogRepository.InsertOneAsync(record);
            }

            SpecificAuditLogFilterDto auditLogParametersDto = new SpecificAuditLogFilterDto();
            auditLogParametersDto.pageNumber=1;
            auditLogParametersDto.pageSize = 10;
            auditLogParametersDto.userId="User123";
            auditLogParametersDto.startDate=now.AddDays(-2);
            auditLogParametersDto.endDate=now;

            // Act
            var paginatedResult = await _service.GetAuditLogsBySpecificFilterAsync(auditLogParametersDto);

            // Assert
            // Assert
            Assert.That(paginatedResult.Records.Count(), Is.EqualTo(1), "Should return only records matching all filters.");
            var result = paginatedResult.Records.First();
            Assert.That(result.RecordId, Is.EqualTo("123"), "The record should match all filters.");
            Assert.That(result.UserId, Is.EqualTo("User123"), "The UserId should match the filter.");

        }
        [Test]
        public async Task GetAuditLogsAsync_FilterByEntityType_ReturnsMatchingRecords()
        {
            // Arrange
            var records = new List<AuditRecord>
            {
                new AuditRecord
                {
                    EntityType = "User",
                    RecordId = "1",
                    UserId = "User123",
                    ActionType = "Create",
                    ActionTime = DateTime.UtcNow.AddMinutes(-10),
                    Reason = "Testing filter by EntityType",
                    Changes = new List<AuditRecord.Change>()
                },
                new AuditRecord
                {
                    EntityType = "Admin",
                    RecordId = "2",
                    UserId = "User456",
                    ActionType = "Delete",
                    ActionTime = DateTime.UtcNow,
                    Reason = "Testing filter by EntityType",
                    Changes = new List<AuditRecord.Change>()
                }
            };
            SpecificAuditLogFilterDto auditLogParametersDto = new SpecificAuditLogFilterDto();
            auditLogParametersDto.pageNumber=1;
            auditLogParametersDto.pageSize = 10;
            auditLogParametersDto.entityType = "User";

            foreach (var record in records)
            {
                await _service.AuditLogRepository.InsertOneAsync(record);
            }

            // Act
            var paginatedResult = await _service.GetAuditLogsBySpecificFilterAsync(auditLogParametersDto);

            // Assert
            Assert.That(paginatedResult.Records.Count(), Is.EqualTo(1), "Should return only records matching the EntityType filter.");
            var result = paginatedResult.Records.First();
            Assert.That(result.EntityType, Is.EqualTo("User"), "The EntityType should match the filter.");

        }
        
        [Test]
public async Task GetAuditLogsMatchingTextAsync_WithSearchText_ReturnsMatchingRecords()
{
    // Arrange
    var records = new List<AuditRecord>
    {
        new AuditRecord
        {
            EntityType = "User",
            RecordId = "nhc1",
            UserId = "User123",
            ActionType = "Create",
            ActionTime = DateTime.UtcNow,
            Reason = "Include this record",
            UserIpAddress = "192.168.1.1"
        },
        new AuditRecord
        {
            EntityType = "Admin",
            RecordId = "nhc2",
            UserId = "User456",
            ActionType = "Delete",
            ActionTime = DateTime.UtcNow,
            Reason = "Do not include this record",
            UserIpAddress = "192.168.1.2"
        }
    };

    foreach (var record in records)
    {
        await _service.AuditLogRepository.InsertOneAsync(record);
    }

    AuditLogTextOrDateSearchDTO orDateSearchTextOrDateDto = new AuditLogTextOrDateSearchDTO
    {
        pageNumber = 1,
        pageSize = 10,
        searchText = "nhc2"
    };

    // Act
    var result = await _service.GetAuditLogsMatchingTextOrDateAsync(orDateSearchTextOrDateDto);

    // Assert
    Assert.That(result.Records.Count, Is.EqualTo(1), "Should return only records matching the search text.");
    Assert.That(result.Records.First().UserId, Is.EqualTo("User456"), "The UserId should match the record with the included search text.");

}

[Test]
public async Task GetAuditLogsMatchingTextAsync_WithoutSearchText_ReturnsAllRecords()
{
    // Arrange
    var records = new List<AuditRecord>
    {
        new AuditRecord
        {
            EntityType = "User",
            RecordId = "1",
            UserId = "User123",
            ActionType = "Create",
            ActionTime = DateTime.UtcNow,
            Reason = "First record",
            UserIpAddress = "192.168.1.1"
        },
        new AuditRecord
        {
            EntityType = "Admin",
            RecordId = "2",
            UserId = "User456",
            ActionType = "Delete",
            ActionTime = DateTime.UtcNow,
            Reason = "Second record",
            UserIpAddress = "192.168.1.2"
        }
    };

    foreach (var record in records)
    {
        await _service.AuditLogRepository.InsertOneAsync(record);
    }

    AuditLogTextOrDateSearchDTO orDateSearchTextOrDateDto = new AuditLogTextOrDateSearchDTO
    {
        pageNumber = 1,
        pageSize = 10
    };

    // Act
    var result = await _service.GetAuditLogsMatchingTextOrDateAsync(orDateSearchTextOrDateDto);

    // Assert
    Assert.That(result.Records.Count, Is.EqualTo(2), "Should return all records when no search text is provided.");

}


    [Test]
    public async Task GetAuditLogsMatchingTextAsync_WithDateRange_ReturnsMatchingRecords()
    {
        // Arrange
        var now = DateTime.UtcNow;
        var earlier = now.AddDays(-1);
        var records = new List<AuditRecord>
        {
            new AuditRecord
            {
                EntityType = "User",
                RecordId = "123",
                UserId = "User123",
                ActionType = "Create",
                ActionTime = earlier,
                Reason = "Old record",
                UserIpAddress = "192.168.1.1"
            },
            new AuditRecord
            {
                EntityType = "Admin",
                RecordId = "456",
                UserId = "User456",
                ActionType = "Delete",
                ActionTime = now,
                Reason = "Recent record",
                UserIpAddress = "192.168.1.2"
            }
        };

        foreach (var record in records)
        {
            await _service.AuditLogRepository.InsertOneAsync(record);
        }

        AuditLogTextOrDateSearchDTO searchDto = new AuditLogTextOrDateSearchDTO
        {
            pageNumber = 1,
            pageSize = 10,
            searchText = "",
            startDate = earlier,
            endDate = now
        };

        // Act
        var result = await _service.GetAuditLogsMatchingTextOrDateAsync(searchDto);

        // Assert
        
        Assert.That(result.Records.Count(),Is.EqualTo(2),"Should return records within the date range.");
    }

    [Test]
    public async Task GetAuditLogsMatchingTextAsync_WithTextAndDateFilters_ReturnsCorrectlyFilteredRecords()
    {
        // Arrange
        var now = DateTime.UtcNow;
        var earlier = now.AddDays(-2);
        var records = new List<AuditRecord>
        {
            new AuditRecord
            {
                EntityType = "User",
                RecordId = "123",
                UserId = "User123",
                ActionType = "Create",
                ActionTime = now.AddDays(-1),
                Reason = "Old record",
                UserIpAddress = "192.168.1.1"
            },
            new AuditRecord
            {
                EntityType = "Admin",
                RecordId = "456",
                UserId = "User456",
                ActionType = "Delete",
                ActionTime = now,
                Reason = "Recent record",
                UserIpAddress = "192.168.1.2"
            }
        };

        foreach (var record in records)
        {
            await _service.AuditLogRepository.InsertOneAsync(record);
        }

        AuditLogTextOrDateSearchDTO searchDto = new AuditLogTextOrDateSearchDTO
        {
            pageNumber = 1,
            pageSize = 10,
            searchText = "123",
            startDate = earlier,
            endDate = now//now.AddDays(-0.5) // This will exclude the recent record
        };

        // Act
        var result = await _service.GetAuditLogsMatchingTextOrDateAsync(searchDto);

        // Assert
        Assert.That(result.Records.Count, Is.EqualTo(1), "Should return only records matching both text and date range filters.");
        Assert.That(result.Records.First().Reason, Is.EqualTo("Old record"), "The Reason should match the filter.");
    }

    [Test]
    public async Task GetAuditLogsMatchingTextAsync_NoMatchingCriteria_ReturnsNoRecords()
    {
        // Arrange
        var now = DateTime.UtcNow;
        var records = new List<AuditRecord>
        {
            new AuditRecord
            {
                EntityType = "User",
                RecordId = "123",
                UserId = "User123",
                ActionType = "Create",
                ActionTime = now.AddDays(-2),
                Reason = "Old record",
                UserIpAddress = "192.168.1.1"
            }
        };

        foreach (var record in records)
        {
            await _service.AuditLogRepository.InsertOneAsync(record);
        }

        AuditLogTextOrDateSearchDTO searchDto = new AuditLogTextOrDateSearchDTO
        {
            pageNumber = 1,
            pageSize = 10,
            searchText = "No match",
            startDate = DateTime.UtcNow.AddDays(-5),
            endDate = DateTime.UtcNow.AddDays(-3)
        };

        // Act
        var result = await _service.GetAuditLogsMatchingTextOrDateAsync(searchDto);

        // Assert
        Assert.That(result.Records.Count(),Is.EqualTo(0));
    }
    
    





    }