using adas_core.Application.Repositories.Interfaces;
using adas_core.Application.Services.Interfaces;
using adas_core.Domain.Models.MongoModels;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using MongoDB.Bson;

namespace adas_core.Application.Services;

public class ArchivePatientCarePlanService(
    IArchivePatientCarePlanRepository archivedPatientRepository,
    ILogger<ArchivePatientCarePlanService> logger,
    IHttpContextAccessor httpContextAccessor,
    ILocalAuditService auditService)
    : IArchivePatientCarePlanService
{
    #region Create

    /// <summary>
    /// Inserts a patient care plan into the archived patient repository, logs the operation, and creates an audit log entry capturing the current user context.
    /// </summary>
    /// <param name="patient">The patient care plan to be archived and inserted.</param>
    /// <returns>The inserted patient care plan, or <see langword="null"/> if no plan was provided.</returns>
    public async Task<PatientCarePlan?> InsertOneAsync(PatientCarePlan patient)
    {
        await archivedPatientRepository.InsertOneAsync(patient);
        logger.LogInformation(
            "Inserted archived patient care plan for patientId: {PatientId}, patientNumber: {PatientNumber}",
            patient.PatientId, patient.PatientNumber);
        await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, null, patient);
        return patient;
    }

    /// <summary>
    /// Asynchronously inserts a batch of archived patient care plans into the repository and creates an audit log entry for each one using the current HTTP context user.
    /// </summary>
    /// <param name="patientCarePla">The list of patient care plans to insert and audit.</param>
    public async Task InsertManyAsync(List<PatientCarePlan> patientCarePla)
    {
        await archivedPatientRepository.InsertManyAsync(patientCarePla);
        logger.LogInformation("Inserted {Count} archived patient care plans", patientCarePla.Count);
        foreach (var patient in patientCarePla)
            await auditService.CreateAuditLogAsync(httpContextAccessor.HttpContext?.User!, null, patient);
    }

    #endregion

    #region Read

    /// <summary>
    /// Retrieves the list of archived patient care plans associated with the specified patient identifier by delegating to the underlying repository.
    /// Returns a nullable list, which may be null when no archived care plans exist for the patient.
    /// </summary>
    /// <param name="patientId">The unique identifier of the patient whose archived care plans are being searched.</param>
    /// <returns>A task that represents the asynchronous operation. The task result contains a list of <see cref="PatientCarePlan"/> for the patient, or null if no records are found.</returns>
    public async Task<List<PatientCarePlan>?> FindByPatientId(ObjectId patientId)
    {
        return await archivedPatientRepository.FindByPatientId(patientId);
    }

    /// <summary>
    /// Retrieves a list of archived patient care plans associated with the specified patient identifier.
    /// Returns null when no archived care plans are found for the given patient.
    /// </summary>
    /// <param name="patientId">The unique identifier of the patient whose archived care plans are being retrieved.</param>
    /// <returns>A list of <see cref="PatientCarePlan"/> entries for the patient, or <c>null</c> if no records exist.</returns>
    public async Task<List<PatientCarePlan>?> FindByPatientId(string patientId)
    {
        return await archivedPatientRepository.FindByPatientId(patientId);
    }

    /// <summary>
    /// Retrieves a list of archived patient care plans associated with the specified patient number.
    /// Returns null if no archived care plans are found for the given patient.
    /// </summary>
    /// <param name="patientId">The unique identifier of the patient whose archived care plans are being searched.</param>
    /// <returns>A list of <see cref="PatientCarePlan"/> objects for the specified patient, or null if no records are found.</returns>
    public async Task<List<PatientCarePlan>?> FindByPatientNumber(string patientId)
    {
        return await archivedPatientRepository.FindByPatientNumber(patientId);
    }

    /// <summary>
    /// Retrieves all archived patient care plans by delegating to the archived patient repository.
    /// </summary>
    /// <returns>A task that resolves to a list of <see cref="PatientCarePlan"/> objects representing all archived patient care plans.</returns>
    public Task<List<PatientCarePlan>> FindAll()
    {
        return archivedPatientRepository.FindAll();
    }

    #endregion
}