using adas_core.Application.Exceptions;
using adas_core.Application.Services.Interfaces;
using adas_core.Authentication.Attributes;
using adas_core.Domain.Enums;
using adas_core.Domain.Models;
using adas_core.Domain.Models.DTO;
using adas_core.Domain.Models.Filter;
using adas_core.Logging;
using Microsoft.AspNetCore.Mvc;
using MongoDB.Bson;

namespace adas_core.Controllers;

[Route("treatments")]
[ApiController]
public class TreatmentsController : ControllerBase
{
    private readonly IPatientService _patientService;
    private readonly ITreatmentService _treatmentService;

    public TreatmentsController(ITreatmentService treatmentService, IPatientService patientService)
    {
        LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString(), true);

        _treatmentService = treatmentService;
        _patientService = patientService;
    }


    /// <summary>
    /// Processes an inbound treatment request for a known patient, building an <see cref="ApiRequest"/> of type "RAS_O17" and persisting it asynchronously. Falls back to the patient's registered location when the incoming DTO does not specify one, and raises a not-found error if no patient matches the supplied number.
    /// </summary>
    /// <param name="treatmentDto">The treatment payload received in the request body, providing patient number, location, message time, wait result, and the optional treatment to forward.</param>
    /// <returns>An <see cref="IActionResult"/> that yields <c>200 OK</c> once the request has been successfully saved.</returns>
    /// <exception cref="NotFoundException">Thrown when no patient is found for the <c>PatientNumber</c> provided in <paramref name="treatmentDto"/>.</exception>
    [HttpPost]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> ProcessRequest([FromBody] TreatmentDto treatmentDto)
    {
        var request = new ApiRequest
        {
            TraceId = Guid.NewGuid().ToString(),
            Type = "RAS_O17",
            PatientNumber = treatmentDto.PatientNumber,
            Location = treatmentDto.Location,
            MessageTime = treatmentDto.MessageTime,
            WaitResult = treatmentDto.WaitResult,
            RequestFromPanel = true,
            Treatments = []
        };


        if (treatmentDto.Treatment != null)
            request.Treatments.Add(treatmentDto.Treatment);

        var patient = await _patientService.FindByPatientNumber(treatmentDto.PatientNumber, true) ??
                      throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing);

        request.Location ??= patient.Location;

        await _treatmentService.SaveRequestAsync(request);

        //var treatList = await _treatmentService.GetTreatmentsByPatientId(patient.Id);

        //if (!treatList.Any(t => t.MessageTime == treatmentDto.MessageTime))
        //{
        //    return NotFound($"Treatment not inserted");
        //}

        //var treat = treatList.FirstOrDefault(t => t.MessageTime == treatmentDto.MessageTime);
        //if (treat == null)
        //{
        //    return BadRequest("Error inserting treatment");
        //}

        //return Ok(treat);

        return Ok();
    }

    /// <summary>
    /// Retrieves up to 50 treatments associated with the specified patient, ordered by order time.
    /// Validates that the provided patient identifier is a well-formed value; otherwise a bad request is raised.
    /// </summary>
    /// <param name="patientid">The patient's identifier used to look up their treatments.</param>
    /// <returns>An <see cref="IActionResult"/> containing the first 50 treatments for the patient, sorted by order time.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="patientid"/> is not a valid identifier format.</exception>
    [HttpGet("{patientid}/patient-id")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetTreatmentsByPatientId(string patientid)
    {
        if (!ObjectId.TryParse(patientid, out var validId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var treatments = await _treatmentService.GetTreatmentsByPatientId(validId);
        return Ok(treatments.OrderBy(p => p.OrderTime).Take(50));
    }


    /// <summary>
    /// Updates an existing patient treatment record based on the provided request payload.
    /// Requires the caller to have the AuthSome role and the appropriate source/display permissions.
    /// </summary>
    /// <param name="request">The <see cref="PatientTreatment"/> payload containing the treatment data to update.</param>
    /// <returns>An <see cref="IActionResult"/> containing the updated treatment in an HTTP 200 OK response.</returns>
    [HttpPut]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateTreatment([FromBody] PatientTreatment request)
    {
        var treatment = await _treatmentService.UpdateTreatment(request);
        return Ok(treatment);
    }

    //Archive

    /// <summary>
    /// Deletes the treatment associated with the specified patient ID.
    /// </summary>
    /// <param name="patientId">The string representation of the patient's ObjectId used to identify the treatment to delete.</param>
    /// <returns>An <see cref="IActionResult"/> indicating the result of the delete operation.</returns>
    /// <exception cref="BadRequestException">Thrown when the provided <paramref name="patientId"/> is not a valid ObjectId format.</exception>
    [HttpDelete("{patientid}/patient-id")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> DeleteTreatment(string patientId)
    {
        if (!ObjectId.TryParse(patientId, out var id))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        await _treatmentService.DeleteByPatientId(id);
        return Ok();
    }

    /// <summary>
    /// Deletes a treatment by its unique identifier. Validates that the supplied identifier is a valid ObjectId format before invoking the deletion service.
    /// </summary>
    /// <param name="treatmentId">The unique identifier of the treatment to delete.</param>
    /// <returns>An <see cref="IActionResult"/> representing the result of the deletion operation.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="treatmentId"/> is not a valid ObjectId format.</exception>
    [HttpDelete("{treatmentId}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> DeleteTreatmentById(string treatmentId)
    {
        if (!ObjectId.TryParse(treatmentId, out var id))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);

        await _treatmentService.DeleteById(id);
        return Ok();
    }

    /// <summary>
    /// Retrieves a paginated list of treatments based on the provided filter criteria.
    /// </summary>
    /// <param name="request">The pagination filter containing paging parameters used to query the treatments.</param>
    /// <returns>An <see cref="IActionResult"/> containing the paginated treatments returned by the service.</returns>
    /// <exception cref="BadRequestException">Thrown when the <paramref name="request"/> is null.</exception>
    [HttpPost("paginated")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetPaginatedTreatments([FromBody] PaginationFilter request)
    {
        if (request == null) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestMissingParameters);
        var treatments = await _treatmentService.GetPaginatedTreatments(request);

        return Ok(treatments);
    }
}