using adas_core.Application.Services.Interfaces;
using adas_core.Domain.Models;
using adas_core.Domain.Models.AppSettings;
using adas_core.Domain.Models.Pumps;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using MongoDB.Bson;

namespace adas_core.Application.Services;

public class CalculatedObservationsService : ICalculatedObservationsService
{
    private static ICalculatedObservations? _service;
    private readonly ILogger<CalculatedObservationsService>? _logger;


    public CalculatedObservationsService(
        IOptions<ApiSettings> apiSettings,
        IServiceProvider serviceProvider,
        ILogger<CalculatedObservationsService> logger)
    {
        _logger = logger;

        var customize = apiSettings.Value.Customize;
        if (customize == null)
        {
            _logger.LogWarning("Not customization specified");
            _service = new DefaultCalculatedObservations();
            return;
        }


        var calculatedObservations = "adas_core.Application.Customizations." + customize + ".CalculatedObservations";

        if (string.IsNullOrEmpty(customize))
        {
            _service = new DefaultCalculatedObservations();
        }
        else
        {
            var type = Type.GetType(calculatedObservations);
            if (type == null)
            {
                _logger.LogWarning(
                    $"Type {calculatedObservations} not found for specification. Using DefaultCalculatedObservations");
                _service = new DefaultCalculatedObservations();
                return;
            }

            var ctor = Type.GetType(calculatedObservations)?.GetConstructor([typeof(IServiceProvider)]);
            if (ctor == null)
            {
                _logger.LogWarning(
                    $"Constructor not found for type {calculatedObservations} accepts one parameter with type IServiceProvider. Using DefaultCalculatedObservations");
                _service = new DefaultCalculatedObservations();
                return;
            }

            _service = (ICalculatedObservations)ctor.Invoke([serviceProvider]);
        }
    }


    public virtual async Task<PatientObservation?> Map(PatientObservation obs, bool onlyByName = false)
    {
        if (_service == null) return obs;
        var result = await _service.Map(obs, onlyByName);
        if (result == null)
            _logger?.LogDebug("Mapping calculated via service {serviceFullName}. {obs} Ignored",
                _service.GetType().FullName, obs);
        return result;
    }

    public virtual async Task<PatientObservationAlarm?> Map(PatientObservationAlarm obs, bool onlyByName = false)
    {
        if (_service == null) return obs;
        var result = await _service.Map(obs, onlyByName);
        if (result == null)
            _logger?.LogDebug("Mapping calculated via service {serviceFullName}. {obs} Ignored",
                _service.GetType().FullName, obs);
        return result;
    }

    public virtual async Task<PumpObservation?> Map(PumpObservation obs)
    {
        if (_service == null) return null;
        var result = await _service.Map(obs);
        return result;
    }

    public async Task<PatientRecordingAlert?> Map(PatientRecordingAlert obs)
    {
        if (_service == null) return obs;
        var result = await _service.Map(obs);
        if (result == null)
            _logger?.LogDebug("Mapping calculated via service  {serviceFullName}. {obs} Ignored",
                _service.GetType().FullName, obs);
        return result;
    }

    public async Task<PatientTreatment?> Map(PatientTreatment treatment)
    {
        if (_service == null) return treatment;
        var result = await _service.Map(treatment);
        return result;
    }

    public virtual async Task<PatientDiagnosis?> Map(PatientDiagnosis diagnosis)
    {
        if (_service == null) return diagnosis;
        var result = await _service.Map(diagnosis);
        return result;
    }

    public virtual async Task CalculateMedicineObservation(List<Medicine> activeMedicines, ObjectId patientId)
    {
        if (_service != null) await _service.CalculateMedicineObservation(activeMedicines, patientId);
    }

    public async Task CalculateBolusOpiates(ObjectId patientId)
    {
        if (_service != null) await _service.CalculateActiveBolus(patientId);
    }

    public virtual async Task<IEnumerable<PatientTreatment?>> GetActiveTreatmentsByPatient(ObjectId id)
    {
        if (_service != null) return await _service.GetActiveTreatmentsByPatient(id);
        return new List<PatientTreatment?>();
    }

    public virtual async Task<List<PatientObservation>> MapList(List<PatientObservation> listToInsert)
    {
        if (_service != null) return await _service.PreMapList(listToInsert);
        return [];
    }

    public virtual async Task<PatientObservation> MapSourceAlarm(PatientObservation observation,
        PatientObservationAlarm observationAlarm)
    {
        if (_service != null) return await _service.MapSourceAlarm(observation, observationAlarm);
        return observation;
    }
}