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

namespace adas_core.Test.Repositories;

[TestFixture]
[Category("Integration")]
public class TreatmentRepositoryTest
{
    /// <summary>
    /// One-time test setup that resets the treatments collection, instantiates the repository, and seeds two patient treatments (one with OrderControlType.Nw and one with OrderControlType.Dc) to verify insert behavior.
    /// </summary>
    [OneTimeSetUp]
    public async Task Init()
    {
        _optionsApiSettings = Options.Create(_apiSettings);

        _treatment1 = new PatientTreatment
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = PatientId,
            OrderControl = OrderControlType.Nw,
            PlacerOrder = new Entity { EntityIdentifier = "3690", NamespaceId = "CareVue" },
            FillerOrder = new Entity { EntityIdentifier = "3690", NamespaceId = "CareVue" },
            OrderStatus = "A",
            OrderTime = DateTime.Now,
            Notes = [],
            Routes = []
        };

        _treatment2 = new PatientTreatment
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = PatientId,
            OrderControl = OrderControlType.Dc,
            PlacerOrder = new Entity { EntityIdentifier = "3690", NamespaceId = "CareVue" },
            FillerOrder = new Entity { EntityIdentifier = "3690", NamespaceId = "CareVue" },
            OrderStatus = "A",
            OrderTime = DateTime.Now.AddDays(-5),
            Notes = [],
            Routes = [],
            RequestedGiveCodesStatus =
            [
                new CodeStatus
                        { Code = new Code { CodingSystem = "CS", Identifier = "I", Text = "T" }, Status = "status" }
            ]
        };

        await IntegrationDb.Database.DropCollectionAsync("archive_patients_treatments");
        await IntegrationDb.Database.CreateCollectionAsync("archive_patients_treatments");

        _repository = new TreatmentRepository(_optionsApiSettings, IntegrationDb.Database);

        await _repository.InsertOneAsync(_treatment1);
        await _repository.InsertOneAsync(_treatment2);

        Assert.That(_repository.Collection.FindAsync(_ => true).Result.ToList(), Has.Count.EqualTo(2));
    }

    private TreatmentRepository _repository = null!;

    private readonly ApiSettings _apiSettings = new()
    {
        ArchivePatientsTreatments = "archive_patients_treatments"
    };

    private IOptions<ApiSettings> _optionsApiSettings = null!;

    //private static readonly DateTime now = DateTime.Now;
    private static readonly ObjectId PatientId = ObjectId.GenerateNewId();
    private PatientTreatment _treatment1 = null!;
    private PatientTreatment _treatment2 = null!;


    /// <summary>
    /// Verifies that GetByPatientId returns an empty result collection rather than null when no patient treatments are found for the supplied patient identifier.
    /// </summary>
    [Test]
    public async Task GetByPatientId_Not_Find_Return_Null()
    {
        var result = await _repository.GetByPatientId(ObjectId.GenerateNewId());

        var patientTreatments = result.ToList();
        Assert.That(patientTreatments, Is.Not.Null);
        Assert.That(patientTreatments.ToList(), Is.Empty);
    }

    /// <summary>
    /// Tests that the repository's <c>GetByPatientId</c> method returns the expected patient treatment records
    /// for the given patient, verifying that the result is not null and contains the expected number of entries.
    /// </summary>
    [Test]
    public async Task GetByPatientId_Find_Return_Null()
    {
        var result = await _repository.GetByPatientId(PatientId);

        var patientTreatments = result.ToList();
        Assert.That(patientTreatments, Is.Not.Null);
        Assert.That(patientTreatments.ToList(), Has.Count.EqualTo(2));
    }

    /// <summary>
    /// Verifies that <see cref="DeleteAsync"/> successfully removes a persisted patient treatment from the repository.
    /// The test inserts a treatment, confirms it exists, deletes it by id, and asserts it is no longer retrievable.
    /// </summary>
    [Test]
    public async Task DeleteAsync()
    {
        var treatment = new PatientTreatment
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = PatientId,
            OrderControl = OrderControlType.Nw,
            PlacerOrder = new Entity { EntityIdentifier = "3690", NamespaceId = "CareVue" },
            FillerOrder = new Entity { EntityIdentifier = "3690", NamespaceId = "CareVue" },
            OrderStatus = "A",
            OrderTime = DateTime.Now,
            Notes = [],
            Routes = []
        };

        await _repository.InsertOneAsync(treatment);

        var result = await _repository.Collection.FindAsync(t => t.Id == treatment.Id);

        Assert.That(result, Is.Not.Null);
        Assert.That(result.ToList(), Has.Count.EqualTo(1));

        await _repository.DeleteAsync(treatment.Id);

        var resultDelete = await _repository.Collection.FindAsync(t => t.Id == treatment.Id);

        Assert.That(resultDelete, Is.Not.Null);
        Assert.That(resultDelete.ToList(), Has.Count.EqualTo(0));
    }

    /// <summary>
    /// Verifies that <c>FindByPatientIdAsync</c> returns a non-null list containing the expected number of treatments for the specified patient.
    /// </summary>
    [Test]
    public async Task FindByPatientIdAsync_Find_Return_List_Traetments()
    {
        var result = await _repository.FindByPatientIdAsync(PatientId);

        Assert.That(result, Is.Not.Null);
        Assert.That(result.ToList(), Has.Count.EqualTo(2));
    }

    /// <summary>
    /// Verifies that <see cref="DeleteByPatientId"/> removes the patient treatment associated with the given patient identifier, ensuring no records remain for that patient after deletion.
    /// </summary>
    [Test]
    public async Task DeleteByPatientId()
    {
        var treatment = new PatientTreatment
        {
            Id = ObjectId.GenerateNewId(),
            PatientId = ObjectId.GenerateNewId(),
            OrderControl = OrderControlType.Nw,
            PlacerOrder = new Entity { EntityIdentifier = "3690", NamespaceId = "CareVue" },
            FillerOrder = new Entity { EntityIdentifier = "3690", NamespaceId = "CareVue" },
            OrderStatus = "A",
            OrderTime = DateTime.Now,
            Notes = [],
            Routes = []
        };

        await _repository.InsertOneAsync(treatment);

        var result = await _repository.Collection.FindAsync(t => t.PatientId == treatment.PatientId);

        Assert.That(result, Is.Not.Null);
        Assert.That(result.ToList(), Has.Count.EqualTo(1));

        await _repository.DeleteByPatientId(treatment.PatientId);

        var resultDelete = await _repository.Collection.FindAsync(t => t.PatientId == treatment.PatientId);

        Assert.That(resultDelete, Is.Not.Null);
        Assert.That(resultDelete.ToList(), Has.Count.EqualTo(0));
    }

    /// <summary>
    /// Verifies that _repository.FindBolusTreatments returns a non-null collection containing exactly one bolus treatment for the specified patient.
    /// </summary>
    [Test]
    public async Task FindBolusTreatments_Find_Return_Treatment()
    {
        var result = await _repository.FindBolusTreatments(PatientId);

        Assert.That(result, Is.Not.Null);
        Assert.That(result.ToList(), Has.Count.EqualTo(1));
    }

    /// <summary>
    /// Verifies that FindByPatientIdAsync returns a non-null list containing the expected number of treatments for the specified patient.
    /// </summary>
    [Test]
    public async Task FindByPatientId_Find_Return_List_Traetments()
    {
        var result = await _repository.FindByPatientIdAsync(PatientId);

        Assert.That(result, Is.Not.Null);
        Assert.That(result.ToList(), Has.Count.EqualTo(2));
    }
}