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

namespace adas_core.Controllers;

[Route("displays")]
[ApiController]
public class DisplayController(
    IDisplayService displayService,
    IDisplayConfigService displayConfigService)
    : ControllerBase
{
    /// <summary>
    ///     Get all display list
    /// </summary>
    /// <returns>
    ///     List<Display />
    /// </returns>
    [HttpGet]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    //[PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> List()
    {
        var username = JwtHelper.GetUsernameFromPrincipal(HttpContext.User);
        return Ok(await displayService.GetAllByUser(username));
    }

    /// <summary>
    /// Retrieves a compact list of all displays, requiring the caller to be authenticated with the <see cref="PermissionEnum.RolesType.AuthSome"/> role and to have the "Source" / "DisplayId" permission.
    /// </summary>
    /// <returns>An <see cref="IActionResult"/> containing the HTTP 200 response with the compact display list returned by the display service.</returns>
    [HttpGet("compact")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> ListCompact()
    {
        return Ok(await displayService.GetAllCompact());
    }

    /// <summary>
    /// Retrieves a paginated list of displays based on the provided pagination filter, after enforcing role-based and resource-level authorization.
    /// </summary>
    /// <param name="request">The pagination filter containing paging criteria sent in the request body.</param>
    /// <returns>An <see cref="IActionResult"/> containing the paginated displays wrapped in an HTTP 200 OK response.</returns>
    /// <exception cref="BadRequestException">Thrown when the <paramref name="request"/> payload is null, indicating missing required parameters.</exception>
    [HttpPost("paginated")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetPaginatedDisplays([FromBody] PaginationFilter request)
    {
        if (request == null) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestMissingParameters);
        var displays = await displayService.GetPaginatedDisplays(request);

        return Ok(displays);
    }

    /// <summary>
    ///     Get By type all display list
    /// </summary>
    /// <returns>
    ///     List<Display />
    /// </returns>
    [HttpGet("{type}/type")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> ListByType(DisplayConfigEnums.DisplayType type)
    {
        return Ok(await displayService.GetByType(type));
    }

    /// <summary>
    ///     Get By type all minimal display list on a DTO
    /// </summary>
    /// <returns>
    ///     List<Display />
    /// </returns>
    [HttpGet("{type}/compact")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetAllMinimalListByType()
    {
        return Ok(await displayService.GetAllDisplaySection());
    }

    /// <summary>
    ///     Get all display list by pointOfCare
    /// </summary>
    /// <returns>
    ///     List<Display />
    /// </returns>
    [HttpPost("poc")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> ListByPointOfCare([FromBody] PointOfCare pointOfCare)
    {
        return Ok(await displayService.GetByPointOfCare(pointOfCare));
    }

    /// <summary>
    ///     Get display by name
    /// </summary>
    /// <returns>
    ///     display
    /// </returns>
    [HttpGet("{name}/name")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> ListByPointOfCare(string name)
    {
        var result = await displayService.GetByName(name);
        return Ok(result);
    }

    /// <summary>
    ///     Get display by object id
    /// </summary>
    /// <returns>
    ///     display
    /// </returns>
    [HttpGet("{localeEnum}/{id}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetById(string id, string localeEnum)
    {
        if (!ObjectId.TryParse(id, out var objectId) || !Enum.TryParse<LocaleEnum>(localeEnum, out var locale))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var result = await displayService.GetByIdWithPermissions(objectId, locale);
        return Ok(result);
    }

    /// <summary>
    /// Retrieves a display entity by its identifier, intended for administrative panel access without enforcing user-level permissions.
    /// </summary>
    /// <param name="id">The string representation of the display's unique identifier.</param>
    /// <returns>An <see cref="IActionResult"/> containing the requested display entity.</returns>
    /// <exception cref="BadRequestException">Thrown when the provided <paramref name="id"/> is not a valid ObjectId format.</exception>
    [HttpGet("{id}/adm-panel")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetByIdWithNoPermissions(string id)
    {
        if (!ObjectId.TryParse(id, out var objectId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);

        var result = await displayService.GetById(objectId);
        return Ok(result);
    }

    /// <summary>
    ///     Get display list by it unit object id
    /// </summary>
    /// <returns>
    ///     List<Unit />
    /// </returns>
    [HttpGet("{id}/unitId")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> ListUnitById(string id)
    {
        if (!ObjectId.TryParse(id, out var objectId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var result = await displayService.GetByUnitId(objectId);
        return Ok(result);
    }

    /// <summary>
    ///     Get display info by it object id and fill options
    /// </summary>
    /// <returns>
    ///     display
    /// </returns>
    [HttpGet("{id}/info")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> ListInfoId(string id, [FromQuery] bool? fillPointOfCare,
        [FromQuery] bool? fillDisplayList)
    {
        if (!ObjectId.TryParse(id, out var objectId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var username = JwtHelper.GetUsernameFromPrincipal(HttpContext.User);
        var result =
            await displayService.GetInfo(objectId, username, null, null, fillPointOfCare ?? true, fillDisplayList ?? true);
        return result == null ? throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing) : Ok(result);
    }

    /// <summary>
    /// Retrieves the default display configuration for a given identifier and display type, after validating the identifier format.
    /// </summary>
    /// <param name="id">The string representation of the object identifier to look up; must be a valid ObjectId.</param>
    /// <param name="type">The display type used to filter the configuration lookup.</param>
    /// <returns>An <see cref="IActionResult"/> containing the display configuration retrieved for the supplied identifier and type.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="id"/> is not a valid ObjectId format.</exception>
    [HttpGet("{id}/unitId/{type}/type")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> DefaultConfig(string id, DisplayConfigEnums.DisplayType type)
    {
        if (!ObjectId.TryParse(id, out var objectId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        //var username = JwtHelper.GetUsernameFromPrincipal(HttpContext.User);
        return Ok(await displayConfigService.GetById(new ObjectId("66191fbb91b99fb5ac42e714"), objectId, type));
    }

    /// <summary>
    /// Retrieves the list of available points of contact (POC) associated with the specified display identifiers.
    /// </summary>
    /// <param name="displayIds">The collection of display identifiers used to look up the available points of contact.</param>
    /// <returns>An <see cref="IActionResult"/> containing the list of available points of contact matching the provided display identifiers.</returns>
    [HttpPost("poc-available")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetPocAvailablebyDisplayId([FromBody] List<string> displayIds)
    {
        var listToReturn = await displayService.GetAllAvailablePoc(displayIds, true);
        return Ok(listToReturn);
    }

    /// <summary>
    /// Retrieves the list of POCs associated with the specified display identifier.
    /// Validates that the provided <paramref name="displayId"/> is a valid ObjectId format; if not, a bad request exception is thrown.
    /// </summary>
    /// <param name="displayId">The display identifier used to look up the associated POCs.</param>
    /// <returns>An <see cref="IActionResult"/> containing the POC list returned by the display service.</returns>
    /// <exception cref="BadRequestException">Thrown when <paramref name="displayId"/> is not a valid ObjectId format.</exception>
    [HttpGet("{displayId}/pocs")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetPocByDisplayId(string displayId)
    {
        if (!ObjectId.TryParse(displayId, out var objectId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var pocList = await displayService.GetAllPocsByDisplayId(objectId);
        return Ok(pocList);
    }


    /// <summary>
    ///     Update display PointOfCare id and notify subscribers
    /// </summary>
    /// <returns>
    ///     display
    /// </returns>
    [HttpPut("{id}/pocs-ids")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    // [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdatePointOfCares(string id, [FromBody] List<string> pointOfCareIdList)
    {
        if (!ObjectId.TryParse(id, out var objectId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var listPocObId = new List<ObjectId>();
        foreach (var poc in pointOfCareIdList)
        {
            if (!ObjectId.TryParse(poc, out var pocObjectId))
                throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
            listPocObId.Add(pocObjectId);
        }

        return Ok(await displayService.UpdatePointOfCareList(objectId, listPocObId));
    }


    /// <summary>
    ///     Update display config id and notify subscribers
    /// </summary>
    /// <returns>
    ///     display
    /// </returns>
    [HttpPut("{idDisplay}/config-preset/{idConfig}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    // [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateConfig(string idDisplay, string idConfig)
    {
        if (!ObjectId.TryParse(idDisplay, out var objectIdDisplay) ||
            !ObjectId.TryParse(idConfig, out var objectIdConfigDisplay)
           ) throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var display = await displayService.GetInfo(objectIdDisplay, null, null, null, false);
        if (display == null) throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing);
        await displayConfigService.GetById(objectIdConfigDisplay);
        var result = await displayService.UpdateConfigPreset(objectIdDisplay, objectIdConfigDisplay);

        return Ok(result);
    }

    /// <summary>
    ///     Update display name
    /// </summary>
    /// <returns>
    ///     display
    /// </returns>
    [HttpPut("{id}/{name}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    // [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateDisplayName(string id, string name)
    {
        if (!ObjectId.TryParse(id, out var displayId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var result = await displayService.UpdateName(displayId, name);
        return Ok(result);
    }

    /// <summary>
    ///     Insert display
    /// </summary>
    /// <returns>
    ///     display
    /// </returns>
    [HttpPost]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    // [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> CreateDisplay([FromBody] Display display)
    {
        var result = await displayService.InsertOne(display);
        return Ok(result);
    }


    /// <summary>
    ///     Delete display
    /// </summary>
    /// <returns>
    ///     display
    /// </returns>
    [HttpDelete("{id}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    // [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> DeleteDisplay(string id)
    {
        if (!ObjectId.TryParse(id, out var displayId))
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var result = await displayService.DeleteDisplay(displayId);

        return Ok(result);
    }
}