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.Pumps;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MongoDB.Bson;

namespace adas_core.Application.Customizations.HGM;

//Custom for Hospital Gregorio Marañón
public class CalculatedObservations : ICalculatedObservations
{
    private readonly List<string> _highFrequencyVentilation = [];
    private readonly List<string> _invasiveVentilation = [];
    private readonly ILogger<CalculatedObservations> _logger;
    private readonly List<string> _nonInvasiveVentilation = [];
    private readonly Lazy<IObservationService> _observationService;

    public CalculatedObservations(IServiceProvider serviceProvider)
    {
        var apiSettings = serviceProvider.GetRequiredService<IOptions<ApiSettings>>().Value;
        _logger = serviceProvider.GetRequiredService<ILogger<CalculatedObservations>>();
        _observationService = serviceProvider.GetRequiredService<Lazy<IObservationService>>();

        var highFrequencyVentilation = apiSettings.HighFrequencyVentilation ?? null;
        highFrequencyVentilation?.ForEach(x => _highFrequencyVentilation.Add(x.Trim()));

        var invasiveVentilation = apiSettings.InvasiveVentilation ?? null;
        invasiveVentilation?.ForEach(x => _invasiveVentilation.Add(x.Trim()));

        var nonInvasiveVentilation = apiSettings.NonInvasiveVentilation ?? null;
        nonInvasiveVentilation?.ForEach(x => _nonInvasiveVentilation.Add(x.Trim()));
    }

    public async Task<T?> Map<T>(T obs, bool onlyByName = false) where T : BasePatientObservation
    {
        if (string.IsNullOrEmpty(obs.Name)) return obs;

        switch (obs.Name)
        {
            case "Resp_Mode":
                await CalculateVentilationMode(obs);
                break;
        }

        return obs;
    }


    public Task<PatientTreatment> Map(PatientTreatment treatment)
    {
        throw new NotImplementedException();
    }

    public Task<PatientDiagnosis> Map(PatientDiagnosis diagnosis)
    {
        throw new NotImplementedException();
    }

    public async Task<PumpObservation> Map(PumpObservation pumpObservation)
    {
        return await Task.FromResult(pumpObservation);
    }
    

    public Task CalculateActiveBolus(ObjectId patientId)
    {
        throw new NotImplementedException();
    }

    public Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
    {
        throw new NotImplementedException();
    }

    public Task<PatientObservation?> FixTimeInconsistencyWithLast(PatientObservation newObservation)
    {
        throw new NotImplementedException();
    }

    public Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
    {
        throw new NotImplementedException();
    }

    public Task<List<PatientObservation>> PreMapList(List<PatientObservation> listToInsert)
    {
        return Task.FromResult(listToInsert);
    }

    public Task<PatientObservation> MapSourceAlarm(PatientObservation obs, PatientObservationAlarm alarmToInsert)
    {
        return Task.FromResult(obs);
    }

    public Task SendAlarm(PatientObservation obs, string name, AlarmEnum.Name? code)
    {
        throw new NotImplementedException();
    }

    private async Task CalculateVentilationMode(BasePatientObservation obs)
    {
        var pobs = (PatientObservation)obs;
        var respTypeObs = new PatientObservation
        {
            Name = "Resp_Type",
            CodingSystem = "ADAS",
            PatientId = obs.PatientId,
            Time = obs.Time
        };

        var strValue = pobs.Value.ToString();
        if (string.IsNullOrEmpty(strValue))
            respTypeObs.Value = nameof(RespirationType.None);
        else
            respTypeObs.Value = _highFrequencyVentilation.Contains(strValue)
                ? nameof(RespirationType.HighFrequencyVentilation)
                : _invasiveVentilation.Contains(strValue)
                    ? respTypeObs.Value = nameof(RespirationType.Invasive)
                    : _nonInvasiveVentilation.Contains(strValue)
                        ? respTypeObs.Value = nameof(RespirationType.NonInvasive)
                        : nameof(RespirationType.None);


        var wasInserted = await _observationService.Value.InsertIfChanged("Resp_Type", respTypeObs);
        if (wasInserted)
            _logger.LogDebug("Calculated Resp_Type for patientid: {respTypeObsPatientid} value: {respType}",
                respTypeObs.PatientId, respTypeObs.Value);
    }
}