using adas_core.Domain.Models;
using adas_core.Domain.Models.MongoModels;
using adas_core.Domain.Models.Providers;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Serilog;

namespace adas_core.Application.Providers;

public class AdasProvider(IOptions<ProvidersSettings> providerSettings, IHttpClientFactory httpClientFactory)
    : BaseProvider(providerSettings, httpClientFactory)
{
    /*
     * Get observations of:
     * Predict of UCI stay duration
     * Predict of medications for patients
     */
    public override async Task<List<PatientObservation>> GetObservations(Patient patient)
    {
        var calculatedObservations = new List<PatientObservation>();

        //get data from two endpoints one from UCI stay another for medication
        var predictOfStay = await GetPredictOfStay(patient.PatientNumber);

        if (predictOfStay == null || predictOfStay.Result.ToLower().Contains("error"))
            Log.Error("Error retrieving predict of stay in ADAS result, message: {predictOfStay}", predictOfStay);
        else
        {
            var durationPredicted1 = predictOfStay.Payload.MaxBy(i => i.PercentageMin)!.Duration;
            var durationPredicted2 = predictOfStay.Payload.MinBy(i => i.PercentageMin)!.Duration;

            calculatedObservations.Add(
                new PatientObservation
                {
                    PatientId = patient.Id,
                    CodingSystem = "ADAS",
                    Name = "Stay_Predict_Days_Most_Confident",
                    //get the most confident interval to show the most probable scenario
                    Value = durationPredicted1,
                    Time = DateTime.UtcNow
                });

            calculatedObservations.Add(new PatientObservation
            {
                PatientId = patient.Id,
                CodingSystem = "ADAS",
                Name = "Stay_Predict_Days_Less_Confident",
                //get the less confident interval to show the less probable scenario
                Value = durationPredicted2,
                Time = DateTime.UtcNow
            });
        }


        var predictMedication = await GetPredictMedications(patient.PatientNumber);


        if (predictMedication != null && predictMedication.Any())
            calculatedObservations.Add(new PatientObservation
            {
                PatientId = patient.Id,
                CodingSystem = "ADAS",
                Name = "Medication_Predict",
                Value = ParseAdasMedicationsToMedicationObservation(predictMedication),
                Time = DateTime.UtcNow
            });


        return calculatedObservations;
    }

    private static string ParseAdasMedicationsToMedicationObservation(
        List<ResultModelPredictMedicationAdas> medicationPredict)
    {
        return string.Join("^", medicationPredict.Take(5));
    }

    private async Task<ResultModelPredictOfStayAdas?> GetPredictOfStay(string? patientNumber)
    {
        if (patientNumber == null)
        {
            Log.Error("Error retrieving ADAS predict of stay patient number is null");
            return null;
        }

        try
        {
            var client = GetClient();
            var response = await client.GetAsync($"predictStay?patientNumber={patientNumber}");

            if (response.IsSuccessStatusCode)
            {
                var content = await response.Content.ReadAsStringAsync();
                return JsonConvert.DeserializeObject<ResultModelPredictOfStayAdas>(content);
            }

            Log.Error(
                "Error retrieving calculated ADAS observation length of stay for patient: {patientNumber}, status code: {response.StatusCode} ",
                patientNumber, response.StatusCode);
            return null;
        }


        catch (Exception e)
        {
            Log.Error("Exception retrieving ADAS predict of stay for patient: {patientNumber} exception: {e}",
                patientNumber, e.Message);
            return null;
        }
    }

    private async Task<List<ResultModelPredictMedicationAdas>?> GetPredictMedications(string? patientNumber)
    {
        if (patientNumber == null)
        {
            Log.Error("Error retrieving ADAS predict of stay for patient number is null");
            return null;
        }

        try
        {
            var client = GetClient();

            var response = await client.GetAsync($"predictMedicationNeedsPharmacy?patientNumber={patientNumber}");
            if (response.IsSuccessStatusCode)
            {
                var content = await response.Content.ReadAsStringAsync();
                return JsonConvert.DeserializeObject<List<ResultModelPredictMedicationAdas>>(content);
            }

            Log.Error(
                "Error retrieving calculated ADAS medicines for patient: {patientNumber}, status code: {response.StatusCode}",
                patientNumber, response.StatusCode);
            return null;
        }
        catch (Exception e)
        {
            Log.Error("Exception retrieving ADAS predict medicines for patient: {patientNumber} exception: {e}",
                patientNumber, e.Message);
            return null;
        }
    }

    private HttpClient GetClient()
    {
        var client = HttpClientFactory.CreateClient();
        client.BaseAddress = new Uri(Url);
        return client;
    }
}