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 adas_core.Domain.Models.MongoModels;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MongoDB.Bson;
using Moq;
using Options = Microsoft.Extensions.Options.Options;

namespace adas_core.Test.Services;

[TestFixture]
public class DiagnosisServiceTest
{
    /// <summary>
    /// Initializes the mocked dependencies (patient, diagnosis, unit, audit, subscribers and calculated observations services along with their repositories) and constructs the <see cref="DiagnosisService"/> instance under test.
    /// </summary>
    [SetUp]
        public void Setup()
        {
            _patientServiceMock = new Mock<IPatientService>();
            _patientServiceLazy = new Lazy<IPatientService>(() => _patientServiceMock.Object);
    
            //var sectionServiceMock = new Mock<ISectionService>();
            //sectionServiceLazy = new Lazy<ISectionService>(() => sectionServiceMock.Object);
    
            _diagnosisRepositoryMock = new Mock<IDiagnosisRepository>();
            _diagnosisArchiveRepositoryMock = new Mock<IDiagnosisArchiveRepository>();
            _clientMessageServiceMock = new Mock<IClientMessageService>();
            _subscribersServiceMock = new Mock<ISubscribersService>();
            _unitServiceMock = new Mock<IUnitService>();
            _httpContextAccessor = new Mock<IHttpContextAccessor>();
            _auditService = new Mock<ILocalAuditService>();
            _calculatedObservationsServiceMock = new Mock<ICalculatedObservationsService>();
            _calculatedObservationsServiceLazy =
                new Lazy<ICalculatedObservationsService>(() => _calculatedObservationsServiceMock.Object);
            _calculatedObservationsServiceMock.Setup(x => x.Map(It.IsAny<PatientDiagnosis>()))
                .ReturnsAsync((PatientDiagnosis? value) => value);
            _optionsApiSettings = Options.Create(_apiSettings);
            _logger = new Mock<ILogger<DiagnosisService>>();
            _diagnosisService = new DiagnosisService(
                _patientServiceLazy,
                //sectionServiceLazy,
                _optionsApiSettings,
                _diagnosisRepositoryMock.Object,
                _diagnosisArchiveRepositoryMock.Object,
                _logger.Object,
                _clientMessageServiceMock.Object,
                _subscribersServiceMock.Object,
                _calculatedObservationsServiceLazy,
                _httpContextAccessor.Object,
                _auditService.Object,
                _unitServiceMock.Object
            );
    
    
            // Create a mock of the singleton class subscribers
            var mockSingleton = new Mock<ICalculatedObservationsService>();
    
            // Set up the mock object to return a specific value when a method is called
            mockSingleton.Setup(x => x.Map(It.IsAny<PatientDiagnosis>())).ReturnsAsync((PatientDiagnosis? value) => value);
        }

    private DiagnosisService _diagnosisService;

    private Lazy<IPatientService> _patientServiceLazy;

    private Mock<IPatientService> _patientServiceMock;
    private Mock<IDiagnosisRepository> _diagnosisRepositoryMock;
    private Mock<IDiagnosisArchiveRepository> _diagnosisArchiveRepositoryMock;

    private Mock<IClientMessageService> _clientMessageServiceMock;
    private Mock<ISubscribersService> _subscribersServiceMock;
    private Mock<IUnitService> _unitServiceMock;
    private Lazy<ICalculatedObservationsService> _calculatedObservationsServiceLazy;
    private Mock<ICalculatedObservationsService> _calculatedObservationsServiceMock;
    private Mock<IHttpContextAccessor> _httpContextAccessor = new();
    private Mock<ILocalAuditService> _auditService = new();

    private readonly ApiSettings _apiSettings = new()
    {
        DiagnosisSystem = "Snomed-CT",
        DiagnosisCode = { "55607006" }
    };

    private IOptions<ApiSettings> _optionsApiSettings;


    private Mock<ILogger<DiagnosisService>> _logger;

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

    // [Test]
    // public void SaveRequest_patientNumber_and_pointOfCare_null_Return_not_insert()
    // {
    //     var apiRequest = new ApiRequest();
    //
    //     Assert.ThrowsAsync<Exception>(async () => await _diagnosisService.SaveRequest(apiRequest, null));
    // }

    // [Test]
    // public void SaveRequest_Not_ORU_R01_Return_not_insert()
    // {
    //     var patientObs = new Person
    //     {
    //         FirstName = "Miguel",
    //         LastName = "Villanueva",
    //         Ids = new Dictionary<string, string> { { "MR", "437537" } }
    //     };
    //
    //     var patient = new Patient
    //     {
    //         Id = ObjectId.GenerateNewId(),
    //         UnitString = "UCI5C",
    //         Bed = "Box4",
    //         PatientNumber = "437537",
    //         Person = patientObs
    //
    //     };
    //
    //     var apiRequest = new ApiRequest
    //     {
    //         Location = new PatientLocation("UCI5C", "Box4"),                
    //         Patient = patientObs,
    //         PatientNumber = "437537",
    //         Type = "ORU_R11",
    //         PatientId = PatientId.ToString(),
    //         MessageTime = Now
    //     };
    //
    //     _patientServiceMock.Setup(cm => cm.FindPatientByApiRequest(apiRequest)).ReturnsAsync(patient);            
    //
    //     Assert.ThrowsAsync<Exception>(async () => await _diagnosisService.SaveRequest(apiRequest, null));
    // }


    /// <summary>
    /// Verifies that <c>SaveRequest</c> does not insert a diagnosis when the patient referenced by the <see cref="ApiRequest"/> cannot be found.
    /// </summary>
    /// <returns>A task representing the asynchronous test execution.</returns>
    [Test]
        public async Task SaveRequest_Not_FindPatient_Return_not_insert()
        {
            var apiRequest = new ApiRequest
            {
                Location = new PatientLocation("UCI5C", "Box4"),
                PatientNumber = "437537",
                Type = "ORU_R01",
                PatientId = PatientId.ToString(),
                MessageTime = Now
            };
    
            _patientServiceMock.Setup(cm => cm.FindPatientByApiRequest(apiRequest)).ReturnsAsync((Patient?)null);
    
            await _diagnosisService.SaveRequest(apiRequest, null);
    
            _diagnosisRepositoryMock.Verify(d => d.InsertOneAsync(It.IsAny<PatientDiagnosis>()), Times.Never);
        }

    /// <summary>
    /// Verifies that <c>SaveRequest</c> does not insert a <see cref="PatientDiagnosis"/> when the provided <see cref="ApiRequest"/> is not considered an observation request, ensuring observations must be present to trigger a database insertion.
    /// </summary>
    /// <param name="apiRequest">The API request containing the patient and observation data being evaluated.</param>
    /// <param name="null">Reserved parameter passed to <c>SaveRequest</c> as a null value.</param>
    [Test]
        public async Task SaveRequest_Not_Observations_Return_not_insert()
        {
            var patientObs = new Person
            {
                FirstName = "Miguel",
                LastName = "Villanueva",
                Ids = new Dictionary<string, string> { { "MR", "437537" } }
            };
    
            var patient = new Patient
            {
                Id = ObjectId.GenerateNewId(),
                UnitString = "UCI5C",
                Bed = "Box4",
                PatientNumber = "437537",
                Person = patientObs
            };
    
            var apiRequest = new ApiRequest
            {
                Location = new PatientLocation("UCI5C", "Box4"),
                ObservationData = new ObservationData
                {
                    Code = "302147001",
                    CodingSystem = "SNM",
                    Value = "Aire; Contacto; Preventivo",
                    Text = "Aislamiento",
                    Time = Now
                },
                Patient = patientObs,
                PatientNumber = "437537",
                Type = "ORU_R01",
                PatientId = PatientId.ToString(),
                MessageTime = Now
            };
    
    
            _patientServiceMock.Setup(cm => cm.FindPatientByApiRequest(apiRequest)).ReturnsAsync(patient);
    
            await _diagnosisService.SaveRequest(apiRequest, null);
    
            _diagnosisRepositoryMock.Verify(d => d.InsertOneAsync(It.IsAny<PatientDiagnosis>()), Times.Never);
        }

    [Test]
    public async Task SaveRequest_Not_DiagnosisCodeSettings_Return_not_insert()
    {
        var patientObs = new Person
        {
            FirstName = "Miguel",
            LastName = "Villanueva",
            Ids = new Dictionary<string, string> { { "MR", "437537" } }
        };

        var patient = new Patient
        {
            Id = ObjectId.GenerateNewId(),
            UnitString = "UCI5C",
            Bed = "Box4",
            PatientNumber = "437537",
            Person = patientObs
        };

        var apiRequest = new ApiRequest
        {
            Location = new PatientLocation("UCI5C", "Box4"),
            ObservationData = new ObservationData
            {
                Code = "302147001",
                CodingSystem = "SNM",
                Value = "Aire; Contacto; Preventivo",
                Text = "Aislamiento",
                Time = Now
            },
            Observations =
            [
                new PatientObservation
                {
                    Code = "263490005",
                    CodingSystem = "SNM",
                    Name = "Estado",
                    Status = StatusEnum.Type.Ok,
                    Time = Now,
                    Value = "Sin alergias conocidas"
                },

                new PatientObservation
                {
                    Code = "300916003",
                    CodingSystem = "SNM",
                    Name = "¿Alergia al látex?",
                    Status = StatusEnum.Type.Ok,
                    Time = Now,
                    Value = "No"
                }
            ],
            Patient = patientObs,
            PatientNumber = "437537",
            Type = "ORU_R01",
            PatientId = PatientId.ToString(),
            MessageTime = Now
        };

        Options.Create(new ApiSettings());

        var diagnosisService = new DiagnosisService(
            _patientServiceLazy,
            //sectionServiceLazy,
            _optionsApiSettings,
            _diagnosisRepositoryMock.Object,
            _diagnosisArchiveRepositoryMock.Object,
            _logger.Object,
            _clientMessageServiceMock.Object,
            _subscribersServiceMock.Object,
            _calculatedObservationsServiceLazy,
            _httpContextAccessor.Object,
            _auditService.Object,
            _unitServiceMock.Object);

        _patientServiceMock.Setup(cm => cm.FindPatientByApiRequest(apiRequest)).ReturnsAsync(patient);

        await diagnosisService.SaveRequest(apiRequest, null);

        _diagnosisRepositoryMock.Verify(d => d.InsertOneAsync(It.IsAny<PatientDiagnosis>()), Times.Never);
    }


    // [Test]
    // public async Task SaveRequest_DiagnosisCodeSettings_Return_insert()
    // {
    //     var patientObs = new Person
    //     {
    //         FirstName = "Miguel",
    //         LastName = "Villanueva",
    //         Ids = new Dictionary<string, string> { { "MR", "437537" } }
    //     };
    //
    //     var patient = new Patient
    //     {
    //         Id = ObjectId.GenerateNewId(),
    //         UnitString = "UCI5C",
    //         Bed = "Box4",
    //         PatientNumber = "437537",
    //         Person = patientObs
    //     };
    //
    //     var apiRequest = new ApiRequest
    //     {                
    //         Location = new PatientLocation("UCI5C", "Box4"),
    //         ObservationData= new ObservationData
    //         {
    //             Code = "55607006",
    //             CodingSystem = "SNM",
    //             Value = "Diagnosis",                    
    //             Time = Now
    //
    //         },
    //         Observations = new List<PatientObservation>
    //         {
    //             new()
    //             {
    //                 Code = "272099008",
    //                 CodingSystem = "SNM",
    //                 Name = "description",
    //                 Status = ObservationStatus.Ok,
    //                 Time = Now,
    //                 Value = "Daño axonal difuso"
    //             },
    //             new()
    //             {
    //                 Code = "1000000013",
    //                 CodingSystem = "SNM",
    //                 Name = "label",
    //                 Status = ObservationStatus.Ok,
    //                 Time = Now,
    //                 Value = "Daño axonal difuso"
    //             },
    //             new()
    //             {
    //                 Code = "1000000014",
    //                 CodingSystem = "SNM",
    //                 Name = "code",
    //                 Status = ObservationStatus.Ok,
    //                 Time = Now,
    //                 Value = "262693007"
    //             },
    //             new()
    //             {
    //                 Code = "394731006",
    //                 CodingSystem = "SNM",
    //                 Name = "state",
    //                 Status = ObservationStatus.Ok,
    //                 Time = Now,
    //                 Value = "state"
    //             },
    //             new()
    //             {
    //                 Code = "272125009",
    //                 CodingSystem = "SNM",
    //                 Name = "category",
    //                 Status = ObservationStatus.Ok,
    //                 Time = Now,
    //                 Value = "category"
    //             },
    //             new()
    //             {
    //                 Code = "398201009",
    //                 CodingSystem = "SNM",
    //                 Name = "starTime",
    //                 Status = ObservationStatus.Ok,
    //                 Time = Now,
    //                 Value = Now.AddHours(1)
    //             },
    //             new()
    //             {
    //                 Code = "397898000",
    //                 CodingSystem = "SNM",
    //                 Name = "endTime",
    //                 Status = ObservationStatus.Ok,
    //                 Time = Now,
    //                 Value = Now.AddHours(2)
    //             }
    //
    //         },
    //         Patient = patientObs,
    //         PatientNumber = "437537",
    //         Type = "ORU_R01",
    //         PatientId = PatientId.ToString(),
    //         MessageTime = Now
    //     };            
    //
    //     _diagnosisService = new DiagnosisService(
    //         _patientServiceLazy,
    //         //sectionServiceLazy,
    //         _optionsApiSettings,
    //         _diagnosisRepositoryMock.Object,
    //         _diagnosisArchiveRepositoryMock.Object,
    //         _logger.Object,
    //         _clientMessageServiceMock.Object,
    //         _subscribersServiceMock.Object,
    //         _calculatedObservationsServiceLazy,
    //         _unitServiceMock.Object);
    //
    //     _patientServiceMock.Setup(cm => cm.FindPatientByApiRequest(apiRequest)).ReturnsAsync(patient);            
    //
    //     await _diagnosisService.SaveRequest(apiRequest, null);
    //
    //     _diagnosisRepositoryMock.Verify(d => d.InsertOneAsync(It.IsAny<PatientDiagnosis>()), Times.Once);
    //     _diagnosisRepositoryMock.Verify(d => d.UpdateOneAsync(It.IsAny<ObjectId>(),It.IsAny<PatientDiagnosis>()), Times.Never);
    // }

    // [Test]
    // public async Task SaveRequest_DiagnosisCodeSettings_Return_Update()
    // {
    //     var patientObs = new Person
    //     {
    //         FirstName = "Miguel",
    //         LastName = "Villanueva",
    //         Ids = new Dictionary<string, string> { { "MR", "437537" } }
    //     };
    //
    //     var patient = new Patient
    //     {
    //         Id = ObjectId.GenerateNewId(),
    //         UnitString = "UCI5C",
    //         Bed = "Box4",
    //         PatientNumber = "437537",
    //         Person = patientObs
    //     };
    //
    //     var apiRequest = new ApiRequest
    //     {
    //         Location = new PatientLocation("UCI5C", "Box4"),
    //         ObservationData= new ObservationData
    //         {
    //             Code = "55607006",
    //             CodingSystem = "SNM",
    //             Value = "Diagnosis",
    //             Time = Now
    //
    //         },
    //         Observations = new List<PatientObservation>
    //         {
    //             new()
    //             {
    //                 Code = "272099008",
    //                 CodingSystem = "SNM",
    //                 Name = "description",
    //                 Status = ObservationStatus.Ok,
    //                 Time = Now,
    //                 Value = "Daño axonal difuso"
    //             },
    //             new()
    //             {
    //                 Code = "1000000013",
    //                 CodingSystem = "SNM",
    //                 Name = "label",
    //                 Status = ObservationStatus.Ok,
    //                 Time = Now,
    //                 Value = "Daño axonal difuso"
    //             },
    //             new()
    //             {
    //                 Code = "1000000014",
    //                 CodingSystem = "SNM",
    //                 Name = "code",
    //                 Status = ObservationStatus.Ok,
    //                 Time = Now,
    //                 Value = "262693007"
    //             },
    //             new()
    //             {
    //                 Code = "394731006",
    //                 CodingSystem = "SNM",
    //                 Name = "state",
    //                 Status = ObservationStatus.Ok,
    //                 Time = Now,
    //                 Value = "state"
    //             },
    //             new()
    //             {
    //                 Code = "272125009",
    //                 CodingSystem = "SNM",
    //                 Name = "category",
    //                 Status = ObservationStatus.Ok,
    //                 Time = Now,
    //                 Value = "category"
    //             },
    //             new()
    //             {
    //                 Code = "398201009",
    //                 CodingSystem = "SNM",
    //                 Name = "starTime",
    //                 Status = ObservationStatus.Ok,
    //                 Time = Now,
    //                 Value = Now.AddHours(1)
    //             },
    //             new()
    //             {
    //                 Code = "397898000",
    //                 CodingSystem = "SNM",
    //                 Name = "endTime",
    //                 Status = ObservationStatus.Ok,
    //                 Time = Now,
    //                 Value = Now.AddHours(2)
    //             }
    //
    //         },
    //         Patient = patientObs,
    //         PatientNumber = "437537",
    //         Type = "ORU_R01",
    //         PatientId = patient.Id.ToString(),
    //         MessageTime = Now
    //     };
    //
    //     var patientDiagnosis = new PatientDiagnosis
    //     {
    //         Id = ObjectId.GenerateNewId(),
    //         Time = Now
    //     };
    //
    //     _diagnosisService = new DiagnosisService(
    //         _patientServiceLazy,
    //         //sectionServiceLazy,
    //         _optionsApiSettings,
    //         _diagnosisRepositoryMock.Object,
    //         _diagnosisArchiveRepositoryMock.Object,
    //         _logger.Object,
    //         _clientMessageServiceMock.Object,
    //         _subscribersServiceMock.Object,
    //         _calculatedObservationsServiceLazy,
    //         _unitServiceMock.Object);
    //
    //     _patientServiceMock.Setup(cm => cm.FindPatientByApiRequest(apiRequest)).ReturnsAsync(patient);
    //     _diagnosisRepositoryMock.Setup(d => d.FindByPatientIdAndCode(patient.Id, "262693007", "Snomed-CT")).ReturnsAsync(patientDiagnosis);
    //
    //     await _diagnosisService.SaveRequest(apiRequest, null);
    //
    //     //_diagnosisRepositoryMock.Verify(d => d.InsertOneAsync(It.IsAny<PatientDiagnosis>()), Times.Never);
    //     _diagnosisRepositoryMock.Verify(d => d.UpdateOneAsync(It.IsAny<ObjectId>(), It.IsAny<PatientDiagnosis>()), Times.Once);
    // }
}