using adas_core.Domain.Models;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.MongoModels;
using adas_core.Infrastructure.Repositories;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using Options = Microsoft.Extensions.Options.Options;

namespace adas_core.Test.Repositories;

[TestFixture]
public class PoCSettingsRepositoryTest
{
    /// <summary>
    /// One-time setup that prepares the integration test environment by resetting the PoC settings collection in the integration database, seeding it with test data, and instantiating the <see cref="PoCSettingsRepository"/> used by the test fixture.
    /// </summary>
    [OneTimeSetUp]
        public async Task Init()
        {
            _optionsApiSettings = Options.Create(_apiSettings);
    
            await IntegrationDb.Database.DropCollectionAsync(_apiSettings.PoCSettings);
            await IntegrationDb.Database.CreateCollectionAsync(_apiSettings.PoCSettings);
    
            _repository = new PoCSettingsRepository(_optionsApiSettings, IntegrationDb.Database);
    
            await _repository.InsertOneAsync(TestPoCSettings);
        }

    private PoCSettingsRepository _repository;

    private readonly ApiSettings _apiSettings = new()
    {
        PoCSettings = "poc_settings"
    };

    private IOptions<ApiSettings> _optionsApiSettings;

    private static readonly ObjectId TestObjectId = ObjectId.GenerateNewId();
    private static readonly PatientLocation TestLocation = new("POC1", "Bed1");

    private static readonly PoCSettings TestPoCSettings = new()
    {
        Id = TestObjectId,
        PatientLocation = TestLocation
    };

    /// <summary>
    /// Verifies that calling the Delete method with an existing PoCSettings identifier removes the corresponding record from the repository, resulting in a null lookup via FindById.
    /// </summary>
    [Test]
        public async Task Delete_WhenCalled_ShouldRemovePoCSettings()
        {
            // Arrange
            var newObjectId = ObjectId.GenerateNewId();
            var newPoCSettings = new PoCSettings
            {
                Id = newObjectId,
                PatientLocation = new PatientLocation("poc2", "bed2")
            };
            await _repository.InsertOneAsync(newPoCSettings);
    
            // Act
            await _repository.Delete(newObjectId);
    
            // Assert
            var result = await _repository.FindById(newObjectId);
            Assert.That(result, Is.Null);
        }

    /// <summary>
    /// Verifies that the repository's <c>FindAll</c> method returns a non-null and non-empty collection of PoC settings.
    /// </summary>
    [Test]
        public async Task FindAll_WhenCalled_ShouldReturnAllPoCSettings()
        {
            // Act
            var result = await _repository.FindAll();
    
            // Assert
            Assert.That(result, Is.Not.Null);
            Assert.That(result, Is.Not.Empty);
        }

    /// <summary>
    /// Tests that FindById returns a non-null PoC settings object whose identifier matches the requested value.
    /// </summary>
    [Test]
        public async Task FindById_WhenCalled_ShouldReturnPoCSettings()
        {
            // Act
            var result = await _repository.FindById(TestObjectId);
    
            // Assert
            Assert.That(result, Is.Not.Null);
            Assert.That(result?.Id, Is.EqualTo(TestObjectId));
        }

    /// <summary>
    /// Verifies that _repository.FindByLocation returns a PoC settings object matching the requested patient location.
    /// </summary>
    [Test]
        public async Task FindByLocation_WhenCalled_ShouldReturnPoCSettings()
        {
            // Act
            var result = await _repository.FindByLocation(TestLocation);
    
            // Assert
            Assert.That(result, Is.Not.Null);
            Assert.That(result?.PatientLocation, Is.EqualTo(TestLocation));
        }

    /// <summary>
    /// Verifies that the repository correctly updates an existing PoCSettings entity, specifically ensuring that the associated PatientLocation properties (such as Bed) are persisted after the update operation.
    /// </summary>
    /// <returns>A task that represents the asynchronous test execution.</returns>
    [Test]
        public async Task Update_WhenCalled_ShouldUpdatePoCSettings()
        {
            // Arrange
            var updatedPoCSettings = new PoCSettings
            {
                Id = TestObjectId,
                PatientLocation = new PatientLocation("POC3", "Bed3")
            };
    
            // Act
            await _repository.Update(updatedPoCSettings);
    
            // Assert
            var result = await _repository.FindById(TestObjectId);
            Assert.That(result, Is.Not.Null);
            //Assert.That(result?.PatientLocation?.PointOfCare, Is.EqualTo("POC3"));
            Assert.That(result?.PatientLocation?.Bed, Is.EqualTo("Bed3"));
        }
}