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.Logging;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace adas_core.Controllers;

/// <summary>
/// Provides API endpoints for managing application-level operations such as subscribers, file uploads, asset management, and cache cleaning.
/// </summary>
[Route("application")]
[ApiController]
public class ApplicationController : ControllerBase
{
    private readonly IClientMessageService _clientMessageService;

    //Logger<ApplicationController> logger
    //private readonly ILogger<ApplicationController> _loggerADMPanel;
    private readonly IFileService _fileService;
    private readonly ICacheService? _redisService;
    private readonly ISubscriberGroupedService _subscriberGroupedService;
    private readonly ISubscribersService _subscribersService;


    /// <summary>
    /// Initializes a new instance of the <see cref="ApplicationController"/> class with the required services.
    /// </summary>
    /// <param name="fileService">The service responsible for handling file operations.</param>
    /// <param name="subscribersService">The service responsible for managing subscribers.</param>
    /// <param name="subscriberGroupedService">The service responsible for managing grouped subscribers.</param>
    /// <param name="clientMessageService">The service responsible for handling client messages.</param>
    /// <param name="redisService">The optional cache service used for distributed caching. May be <see langword="null"/> if caching is not configured.</param>
    /// <exception cref="ArgumentNullException">
    /// Thrown when <paramref name="fileService"/>, <paramref name="subscribersService"/>,
    /// <paramref name="subscriberGroupedService"/>, or <paramref name="clientMessageService"/> is <see langword="null"/>.
    /// </exception>
    public ApplicationController(
        IFileService fileService,
        ISubscribersService subscribersService,
        ISubscriberGroupedService subscriberGroupedService,
        IClientMessageService clientMessageService,
        ICacheService? redisService)
    {
        LogExecutionContext.TrySetTraceIdentifier(Guid.NewGuid().ToString(), true);

        _fileService = fileService;
        _subscribersService = subscribersService;
        _subscriberGroupedService = subscriberGroupedService;
        _clientMessageService = clientMessageService;
        _redisService = redisService;
    }


    /// <summary>
    /// Handles an anonymous HTTP GET request to retrieve the list of subscribers by delegating to the subscribers service and returning the result.
    /// </summary>
    /// <returns>An <see cref="IActionResult"/> containing the subscribers data returned by <c>_subscribersService.GetSubscribers()</c>.</returns>
    [HttpGet("subscribers")]
    [AllowAnonymous]
    public IActionResult GetSubscribersVersion()
    {
        return Ok(_subscribersService.GetSubscribers());
    }

    /// <summary>
    /// Handles an anonymous HTTP GET request to retrieve the list of subscribers grouped according to the application's grouping rules.
    /// The grouped result is obtained from the subscriber grouping service and returned with an HTTP 200 OK status.
    /// </summary>
    /// <returns>An <see cref="IActionResult"/> containing the grouped subscribers returned by the subscriber grouping service wrapped in an HTTP 200 OK response.</returns>
    [HttpGet("subscribers-group")]
    [AllowAnonymous]
    public IActionResult GetSubscribersGroup()
    {
        return Ok(_subscriberGroupedService.GetGrouped());
    }

    /// <summary>
    /// Sends an update message containing the provided patient location data to the relevant boxes.
    /// </summary>
    /// <param name="boxes">The list of patient locations to be dispatched to the boxes for update.</param>
    /// <returns>An <see cref="IActionResult"/> containing an HTTP 200 OK response when the update messages are successfully dispatched.</returns>
    [AuthorizeRoles(PermissionEnum.RolesType.AuthAdmin)]
    [HttpPost]
    public IActionResult UpdateApplications([FromBody] List<PatientLocation> boxes)
    {
        _clientMessageService.SendUpdateMessageToBoxes(boxes);
        return Ok();
    }

    /// <summary>
    /// Handles uploading files by delegating to the file service, which copies and updates the provided files.
    /// Restricted to users with the AuthAdmin role and accepts requests up to 300,000,000 bytes in size.
    /// </summary>
    /// <param name="files">The list of files submitted for upload.</param>
    /// <returns>An <see cref="ActionResult"/> indicating the result of the upload operation.</returns>
    [AuthorizeRoles(PermissionEnum.RolesType.AuthAdmin)]
    [HttpPost("upload")]
    [RequestSizeLimit(300_000_000)]
    public async Task<ActionResult> UploadFile(List<IFormFile> files)
    {
        await _fileService.CopyUpdateFiles(files);
        return Ok();
    }

    /// <summary>
    /// Uploads one or more asset files to the storage associated with the specified theme. Requires
    /// AuthAdmin permissions and enforces a maximum request size of 300 MB. If the supplied
    /// <paramref name="theme"/> does not match a valid <c>FileEnum.AssetTheme</c> value, the request
    /// is rejected as a bad request with an invalid format error.
    /// </summary>
    /// <param name="theme">The asset theme name; must be parseable to a <c>FileEnum.AssetTheme</c> value.</param>
    /// <param name="files">The collection of files to upload to the resolved theme.</param>
    /// <returns>An <see cref="ActionResult"/> containing an HTTP 200 OK response when the files are successfully uploaded.</returns>
    /// <exception cref="InvalidFormatException">Thrown when the provided <paramref name="theme"/> cannot be parsed into a valid <c>FileEnum.AssetTheme</c> value.</exception>
    [AuthorizeRoles(PermissionEnum.RolesType.AuthAdmin)]
    [HttpPost("upload/{theme}/{category}/asset")]
    [RequestSizeLimit(300_000_000)]
    public async Task<ActionResult> UploadAssetFile(string theme, List<IFormFile> files)
    {
        var isParsed = Enum.TryParse<FileEnum.AssetTheme>(theme, out var themeParsed);
        if (!isParsed) throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        await _fileService.UploadAssetFiles(files, themeParsed);

        return Ok();
    }

    /// <summary>
    /// Retrieves all asset files for the specified theme, restricted to users with the AuthAdmin role.
    /// Validates the theme by attempting to parse it into an <see cref="FileEnum.AssetTheme"/> value; an invalid theme results in an <see cref="InvalidFormatException"/>.
    /// </summary>
    /// <param name="theme">The theme name to parse into an <see cref="FileEnum.AssetTheme"/> value used to look up the associated asset files.</param>
    /// <returns>An <see cref="ActionResult"/> containing the list of asset files for the resolved theme.</returns>
    /// <exception cref="InvalidFormatException">Thrown when the <paramref name="theme"/> parameter cannot be parsed into a valid <see cref="FileEnum.AssetTheme"/> value.</exception>
    [AuthorizeRoles(PermissionEnum.RolesType.AuthAdmin)]
    [HttpGet("{theme}/{category}/asset")]
    public ActionResult UGetAssetFile(string theme)
    {
        var isParsed = Enum.TryParse<FileEnum.AssetTheme>(theme, out var themeParse);
        if (!isParsed) throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        return Ok(_fileService.GetAllAssetFile(themeParse));
    }

    /// <summary>
    /// Cleans the Redis cache. Restricted to users with AuthAdmin permissions.
    /// </summary>
    /// <returns>An <see cref="ActionResult"/> containing an HTTP 200 OK response when the cache is successfully cleared.</returns>
    /// <exception cref="InvalidFormatException">Thrown when the Redis service is not available.</exception>
    [AuthorizeRoles(PermissionEnum.RolesType.AuthAdmin)]
    [HttpGet("cleaning")]
    public ActionResult CleanCache()
    {
        if (_redisService == null) throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestMissingParameters);
        _redisService.CleanCache();
        return Ok();
    }
}