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.Filter;
using adas_core.Logging;
using Microsoft.AspNetCore.Mvc;
using MongoDB.Bson;

namespace adas_core.Controllers;

[Route("medicines")]
public class MedicinesController : ControllerBase
{
    private readonly IAdminPanelService _adminPanelService;

    private readonly IMedicineService _medicineService;
    //private readonly ILogger<AdminPanelService> _loggerADMPanel;


    public MedicinesController(IMedicineService medicineService,
        IAdminPanelService adminPanelService) //, ILogger<AdminPanelService> loggerADMPanel)
    {
        LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString(), true);

        _medicineService = medicineService;
        _adminPanelService = adminPanelService;
        //this._loggerADMPanel = loggerADMPanel;
    }

    /// <summary>
    /// Retrieves all active medicines, restricted to users with the required authorization role and source/display permissions.
    /// </summary>
    /// <returns>An <see cref="IActionResult"/> containing the collection of active medicines returned by the medicine service wrapped in an HTTP 200 OK response.</returns>
    [HttpGet]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetAllMedicines()
    {
        var activeMedicines = await _medicineService.GetAll();
        return Ok(activeMedicines);
    }


    /// <summary>
    /// Retrieves the list of active medicines associated with the specified patient.
    /// The patient identifier is validated to ensure it is a well-formed ObjectId before querying the medicine service.
    /// </summary>
    /// <param name="patientId">The identifier of the patient whose active medicines are being requested.</param>
    /// <returns>An <see cref="IActionResult"/> containing the active medicines for the patient wrapped in an HTTP 200 response.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="patientId"/> is not a valid ObjectId format.</exception>
    [HttpGet("{patientId}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetActiveMedicines(string patientId)
    {
        if (!ObjectId.TryParse(patientId, out var objectId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var activeMedicines = await _medicineService.GetActiveMedicinesByPatient(objectId);
        return Ok(activeMedicines);
    }


    #region ADMPanel

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

    /// <summary>
    /// Creates and persists a new <see cref="Medicine"/> entry by delegating the insert operation to the admin panel service.
    /// </summary>
    /// <param name="medicine">The medicine payload supplied in the request body to be created.</param>
    /// <returns>An <see cref="IActionResult"/> containing the newly inserted medicine wrapped in an HTTP 200 OK response.</returns>
    /// <exception cref="BadRequestException">Thrown when the provided <paramref name="medicine"/> is <c>null</c>, indicating missing required parameters.</exception>
    [HttpPost]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> PostMedicine([FromBody] Medicine medicine)
    {
        if (medicine == null) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestMissingParameters);
        var insertedMedicine = await _adminPanelService.PostMedicine(medicine);
        return Ok(insertedMedicine);
    }

    /// <summary>
    /// Updates an existing medicine record identified by the specified identifier.
    /// Validates the identifier format, retrieves the existing record to preserve its identity, and persists the updated medicine data.
    /// </summary>
    /// <param name="id">The string representation of the medicine's identifier used to locate the existing record.</param>
    /// <param name="medicine">The medicine payload containing the updated information to apply.</param>
    /// <returns>An <see cref="IActionResult"/> containing the updated medicine returned in an Ok response.</returns>
    /// <exception cref="BadRequestException">Thrown when the provided <paramref name="id"/> cannot be parsed as a valid ObjectId.</exception>
    [HttpPut("{id}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateMedicine(string id, [FromBody] Medicine medicine)
    {
        if (!ObjectId.TryParse(id, out var objectId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var med = await _adminPanelService.GetMedicineById(objectId);
        medicine.Id = med!.Id;
        return Ok(await _adminPanelService.UpdateMedicine(medicine));
    }

    /// <summary>
    /// Deletes a medicine by its unique identifier.
    /// </summary>
    /// <param name="id">The unique identifier of the medicine to delete.</param>
    /// <returns>An <see cref="IActionResult"/> containing an HTTP 200 OK response upon successful deletion.</returns>
    [HttpDelete("{id}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> DeleteMedicine(string id)
    {
        await _adminPanelService.DeleteMedicineById(id);
        return Ok();
    }

    /// <summary>
    /// Retrieves all medicine groups from the medicine service and returns them as an HTTP 200 OK response.
    /// Access is restricted to users with the required role and permission for the "Source" entity's "DisplayId" action.
    /// </summary>
    /// <returns>An <see cref="IActionResult"/> containing the list of all medicine groups returned by the medicine service.</returns>
    [HttpGet("groups")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetAllGroups()
    {
        return Ok(await _medicineService.GetAllGroups());
    }

    /// <summary>
    /// Retrieves all available medicine types, requiring authentication with the appropriate role and permission.
    /// </summary>
    /// <returns>An <see cref="IActionResult"/> containing the list of all medicine types if successful.</returns>
    [HttpGet("types")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetTypes()
    {
        return Ok(await _medicineService.GetAllTypes());
    }

    /// <summary>
    /// Retrieves the list of all medicine names. Requires the user to have the specified role permission and "DisplayId" permission for the "Source" resource.
    /// </summary>
    /// <returns>An <see cref="IActionResult"/> containing the collection of medicine names returned by the service.</returns>
    [HttpGet("names")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetNames()
    {
        return Ok(await _medicineService.GetAllNames());
    }

    /// <summary>
    /// Retrieves the list of all medicine codes available in the system.
    /// </summary>
    /// <returns>An <see cref="IActionResult"/> containing the collection of medicine codes with an HTTP 200 OK response.</returns>
    [HttpGet("codes")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetCodes()
    {
        return Ok(await _medicineService.GetAllCodes());
    }

    #endregion
}