using adas_core.Application.Repositories.Interfaces;
using adas_core.Application.Services;
using adas_core.Application.Services.Interfaces;
using adas_core.Domain.Enums;
using adas_core.Domain.Models;
using adas_core.Domain.Models.AppSettings;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using Moq;
using static NUnit.Framework.Is;
using Options = Microsoft.Extensions.Options.Options;

namespace adas_core.Test.Services;

[TestFixture]
public class MedicineServiceTest
{
    [SetUp]
    public void Setup()
    {
        _medicineRepositoryMock = new Mock<IMedicineRepository>();
        _treatmentServiceMock = new Mock<ITreatmentService>();

        _optionsApiSettings = Options.Create(_apiSettings);

        _logger = new Mock<ILogger<MedicineService>>();

        _medicineService = new MedicineService(
            _medicineRepositoryMock.Object,
            _treatmentServiceMock.Object,
            _optionsApiSettings,
            _logger.Object,
            _httpContextAccessor.Object,
            _auditService.Object);
    }

    private MedicineService _medicineService;

    private Mock<IMedicineRepository> _medicineRepositoryMock;
    private Mock<ITreatmentService> _treatmentServiceMock;
    private readonly Mock<IHttpContextAccessor> _httpContextAccessor = new();
    private readonly Mock<ILocalAuditService> _auditService = new();

    private readonly ApiSettings _apiSettings = new()
    {
        NotesIndicatingMedication = ["NoteMedication"]
    };

    private IOptions<ApiSettings> _optionsApiSettings;

    private Mock<ILogger<MedicineService>> _logger;

    //private static readonly DateTime now = DateTime.Now;
    private static readonly ObjectId PatientId = ObjectId.GenerateNewId();

    [Test]
    public async Task GetMedicinesOfTreatments_Null_Medicine_Return_0()
    {
        var medicineList = new List<Medicine>();

        List<PatientTreatment> patientTreatment = [];
        if (patientTreatment == null) throw new ArgumentNullException(nameof(patientTreatment));

        _medicineRepositoryMock.Setup(m => m.GetMedicineByCodeOrNote(It.IsAny<List<string>>()))
            .ReturnsAsync(medicineList);

        var result = await _medicineService.GetMedicinesOfTreatments(patientTreatment);

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

    [Test]
    public async Task GetMedicinesOfTreatments_Medicines_Return_Medicines()
    {
        var treatment =
            new PatientTreatment
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = PatientId,
                OrderControl = OrderControlType.Nw,
                PlacerOrder = new Entity { EntityIdentifier = "100", NamespaceId = "CareVue" },
                FillerOrder = new Entity { EntityIdentifier = "100", NamespaceId = "CareVue" },
                RequestedGiveCodes = [new Code { Identifier = "12345" }],
                OrderStatus = "A",
                OrderTime = DateTime.Now,
                Notes = [],
                Routes = []
            };

        var treatmentList = new List<PatientTreatment>
        {
            treatment
        };

        var medicine =
            new Medicine
            {
                Codes = ["12345"],
                Group = [MedicineEnum.Group.DoubleSignature.ToString()],
                Type = [MedicineEnum.Types.MuscleRelaxant.ToString()],
                Name = "cisataracurio"
            };


        var medicineList = new List<Medicine>
        {
            medicine
        };

        _medicineRepositoryMock.Setup(m => m.GetMedicineByCodeOrNote(It.IsAny<List<string>>()))
            .ReturnsAsync(medicineList);

        var result = await _medicineService.GetMedicinesOfTreatments(treatmentList);

        Assert.That(result.Count(), GreaterThan(0));
    }

    [Test]
    public async Task GetMedicinesOfTreatments_Not_Get_Medicines_Return_Note_Medicines()
    {
        var treatment =
            new PatientTreatment
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = PatientId,
                OrderControl = OrderControlType.Nw,
                PlacerOrder = new Entity { EntityIdentifier = "100", NamespaceId = "CareVue" },
                FillerOrder = new Entity { EntityIdentifier = "100", NamespaceId = "CareVue" },
                RequestedGiveCodes = [new Code { Identifier = "12345", Text = "CodeText" }],
                OrderStatus = "A",
                OrderTime = DateTime.Now,
                Notes = [new Note { Comment = "NoteMedication" }],
                Routes = []
            };

        var treatmentList = new List<PatientTreatment>
        {
            treatment
        };

        _medicineRepositoryMock.Setup(m => m.GetMedicineByCodeOrNote(It.IsAny<List<string>>())).ReturnsAsync([]);

        var result = await _medicineService.GetMedicinesOfTreatments(treatmentList);
        using (Assert.EnterMultipleScope())
        {
            var medicines = result as Medicine[] ?? result.ToArray();
            Assert.That(medicines.Count(), GreaterThan(0));
            Assert.That(medicines.FirstOrDefault()?.Codes.FirstOrDefault(), EqualTo("12345"));
            Assert.That(medicines.FirstOrDefault()?.Name, EqualTo("CodeText"));
        };
    }

    [Test]
    public async Task GetMedicinesOfTreatments_Not_Get_Medicines_Not_Code_identifier_Return_Note_Medicines()
    {
        var treatment =
            new PatientTreatment
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = PatientId,
                OrderControl = OrderControlType.Nw,
                PlacerOrder = new Entity { EntityIdentifier = "100", NamespaceId = "CareVue" },
                FillerOrder = new Entity { EntityIdentifier = "100", NamespaceId = "CareVue" },
                RequestedGiveCodes = [new Code { Text = "CodeText" }],
                OrderStatus = "A",
                OrderTime = DateTime.Now,
                Notes = [new Note { Comment = "NoteMedication" }],
                Routes = []
            };

        var treatmentList = new List<PatientTreatment>
        {
            treatment
        };


        _medicineRepositoryMock.Setup(m => m.GetMedicineByCodeOrNote(It.IsAny<List<string>>())).ReturnsAsync([]);

        var result = await _medicineService.GetMedicinesOfTreatments(treatmentList);
        using (Assert.EnterMultipleScope())
        {
            var medicines = result as Medicine[] ?? result.ToArray();
            Assert.That(medicines.Count(), GreaterThan(0));
            Assert.That(medicines.FirstOrDefault()?.Codes.FirstOrDefault(), EqualTo(string.Empty));
            Assert.That(medicines.FirstOrDefault()?.Name, EqualTo("CodeText"));
        };
    }

    [Test]
    public async Task CalculateParentalNutritionMedicine_Notes_NPT_Return_NPT_Medicine()
    {
        var treatment =
            new PatientTreatment
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = PatientId,
                OrderControl = OrderControlType.Nw,
                PlacerOrder = new Entity { EntityIdentifier = "100", NamespaceId = "CareVue" },
                FillerOrder = new Entity { EntityIdentifier = "100", NamespaceId = "CareVue" },
                RequestedGiveCodes = [new Code { Text = "CodeText" }],
                OrderStatus = "A",
                OrderTime = DateTime.Now,
                Notes = [new Note { Comment = "NPT", CommentType = "formularybaseformulation" }],
                Routes = []
            };

        var treatmentList = new List<PatientTreatment>
        {
            treatment
        };


        _medicineRepositoryMock.Setup(m => m.GetMedicineByCodeOrNote(It.IsAny<List<string>>())).ReturnsAsync([]);

        var result = await _medicineService.GetMedicinesOfTreatments(treatmentList);
        using (Assert.EnterMultipleScope())
        {
            var medicines = result as Medicine[] ?? result.ToArray();
            Assert.That(medicines.Count(), GreaterThan(0));
            Assert.That(medicines.FirstOrDefault()?.Codes.FirstOrDefault(), EqualTo(null));
            Assert.That(medicines.FirstOrDefault()?.Name, EqualTo("NPT"));
            Assert.That(MedicineEnum.Types.ParenteralNutrition.ToString(),
                EqualTo(medicines.FirstOrDefault()?.Type.FirstOrDefault()));
        };
    }

    [Test]
    public async Task CalculateParentalNutritionMedicine_Notes_NPTL_Return_NPTL_Medicine()
    {
        var treatment =
            new PatientTreatment
            {
                Id = ObjectId.GenerateNewId(),
                PatientId = PatientId,
                OrderControl = OrderControlType.Nw,
                PlacerOrder = new Entity { EntityIdentifier = "100", NamespaceId = "CareVue" },
                FillerOrder = new Entity { EntityIdentifier = "100", NamespaceId = "CareVue" },
                RequestedGiveCodes = [new Code { Text = "CodeText" }],
                OrderStatus = "A",
                OrderTime = DateTime.Now,
                Notes =
                [
                    new Note { Comment = "NPT", CommentType = "formularybaseformulation" },
                    new Note { Comment = "LÍPIDOS NEONATALES AL 20%" }
                ],
                Routes = []
            };

        var treatmentList = new List<PatientTreatment>
        {
            treatment
        };


        _medicineRepositoryMock.Setup(m => m.GetMedicineByCodeOrNote(It.IsAny<List<string>>())).ReturnsAsync([]);

        var result = await _medicineService.GetMedicinesOfTreatments(treatmentList);
        using (Assert.EnterMultipleScope())
        {
            var medicines = result as Medicine[] ?? result.ToArray();
            Assert.That(medicines.Count(), GreaterThan(0));
            Assert.That(medicines.FirstOrDefault()?.Codes.FirstOrDefault(), EqualTo(null));
            Assert.That(medicines.FirstOrDefault()?.Name, EqualTo("NPT"));
            Assert.That(MedicineEnum.Types.ParenteralNutritionLipids.ToString(),
                EqualTo(medicines.FirstOrDefault()?.Type.FirstOrDefault()));
        };
    }
}