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

namespace adas_core.Controllers;

[Route("beacons")]
public class LightBeaconController : ControllerBase
{
    private readonly ILightBeaconService _lightBeaconService;
    private readonly IPatientService _patientService;


    public LightBeaconController(ILightBeaconService lightBeaconService, IPatientService patientService)
    {
        LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString(), true);

        _lightBeaconService = lightBeaconService;
        _patientService = patientService;
    }

    /// <summary>
    /// Retrieves a paginated list of light beacons based on the provided pagination filter.
    /// Validates that the request payload is not null before delegating to the light beacon service.
    /// </summary>
    /// <param name="request">The pagination filter containing the paging parameters used to query the beacons.</param>
    /// <returns>An <see cref="IActionResult"/> containing the paginated list of beacons returned by the service.</returns>
    /// <exception cref="BadRequestException">Thrown when the <paramref name="request"/> parameter is null, indicating missing parameters.</exception>
    [HttpPost("paginated")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    public async Task<IActionResult> GetPaginatedUnits([FromBody] PaginationFilter request)
    {
        if (request == null) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestMissingParameters);
        var beacons = await _lightBeaconService.GetPaginatedBeacons(request);
        return Ok(beacons);
    }
    /// <summary>
    /// Creates a new camera record by inserting a light beacon into the system.
    /// Requires the caller to have the role associated with <see cref="PermissionEnum.RolesType.AuthSome"/>.
    /// </summary>
    /// <param name="beac">The light beacon data to create the camera from, supplied in the request body.</param>
    /// <returns>An <see cref="IActionResult"/> containing the created light beacon.</returns>
    [HttpPost]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    public async Task<IActionResult> CreateCamera([FromBody] LightBeacon beac)
    {
        var beacon = await _lightBeaconService.InsertOne(beac);
        return Ok(beacon);
    }
    /// <summary>
    /// Updates an existing light beacon (camera) identified by the route parameter, applying the provided data from the request body.
    /// </summary>
    /// <param name="id">The string identifier of the light beacon to update, expected to be a valid ObjectId.</param>
    /// <param name="beacon">The light beacon payload containing the updated information, sourced from the request body.</param>
    /// <returns>An <see cref="IActionResult"/> containing the updated light beacon returned by the service.</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)]
    public async Task<IActionResult> UpdateCamera(string id, [FromBody] LightBeacon beacon)
    {
        if (!ObjectId.TryParse(id, out var idParsed)) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestMissingParameters);
        beacon.Id = idParsed;
        var cameraUpdated = await _lightBeaconService.UpdateOne(beacon);
        return Ok(cameraUpdated);
    }
    /// <summary>
    /// Searches for a light beacon by the provided text and returns the matching result.
    /// </summary>
    /// <param name="textToSearch">The text used to search for the light beacon by name.</param>
    /// <returns>An <see cref="IActionResult"/> containing the matching beacon, or a not-found response if no match exists.</returns>
    [HttpGet("{textToSearch}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    public async Task<IActionResult> GetSearchByName(string textToSearch)
    {
        var beacon = await _lightBeaconService.GetSearchByName(textToSearch);
        return Ok(beacon);
    }
    /// <summary>
    /// Sets the light beacon color for the point of care associated with the specified patient.
    /// Maps the <c>color</c> route value (case-insensitive) to a <see cref="LightBeaconColor"/> and forwards it to the beacon service.
    /// </summary>
    /// <param name="patientId">The patient's identifier, supplied in the request body, used to locate the patient's point of care.</param>
    /// <param name="color">The color name from the route (e.g. "Yellow", "Blue", "Red", "Off", "Green", "Cyan", "Magenta", "White") to apply to the beacon.</param>
    /// <returns>An <see cref="IActionResult"/> indicating successful completion.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="patientId"/> is not a valid <see cref="ObjectId"/> format.</exception>
    /// <exception cref="NotFoundException">Thrown when the patient cannot be found or has no associated point of care.</exception>
    [HttpPost("on/{color}")]
    public async Task<IActionResult> On([FromBody] string patientId, string color)
    {
        var parsed = ObjectId.TryParse(patientId, out var patientObjectId);
        if (!parsed) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var patient = await _patientService.FindById(patientObjectId);
        if (patient == null || !patient.PointOfCareId.HasValue)
            throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing);
        switch (color.ToUpper())
        {
            case "YELLOW":
                await _lightBeaconService.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Yellow);
                break;
            case "BLUE":
                await _lightBeaconService.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Blue);
                break;
            case "RED":
                await _lightBeaconService.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Red);
                break;
            case "OFF":
                await _lightBeaconService.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Off);
                break;
            case "GREEN":
                await _lightBeaconService.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Green);
                break;
            case "CYAN":
                await _lightBeaconService.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Cyan);
                break;
            case "MAGENTA":
                await _lightBeaconService.SendColor(patient.PointOfCareId.Value, LightBeaconColor.Magenta);
                break;
            case "WHITE":
                await _lightBeaconService.SendColor(patient.PointOfCareId.Value, LightBeaconColor.White);
                break;
        }

        return Ok();
    }


    /// <summary>
    /// Powers off the LED of the light beacon associated with the specified POC identifier.
    /// </summary>
    /// <param name="pocId">The string representation of the POC ObjectId whose light beacon LED should be powered off.</param>
    /// <exception cref="BadRequestException">Thrown when <paramref name="pocId"/> is not a valid ObjectId format.</exception>
    [HttpPost("off")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    public IActionResult Off([FromBody] string pocId)
    {
        var isParse = ObjectId.TryParse(pocId, out var pocObjectId);
        if (!isParse) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        _lightBeaconService.PowerOffLed(pocObjectId);

        return Ok();
    }
    /// <summary>
    /// Creates a new light beacon by inserting the provided beacon data into the system.
    /// Returns a conflict response if the insertion yields no result; otherwise, returns the inserted beacon.
    /// </summary>
    /// <param name="beacon">The light beacon data to be created, provided in the request body.</param>
    /// <returns>An <see cref="IActionResult"/> containing the inserted beacon on success, or a conflict response if the insertion fails.</returns>
    [HttpPost("create")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    public async Task<IActionResult> Create([FromBody] adas_core.Domain.Models.MongoModels.LightBeacon beacon)
    {
        var beaconInserted = await _lightBeaconService.InsertOne(beacon);
        if (beaconInserted == null) return Conflict();

        return Ok(beaconInserted);
    }
}