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.DTO.Display;
using adas_core.Domain.Models.Filter;
using adas_core.Domain.Models.GroupedObservations;
using adas_core.Domain.Models.MongoModels;
using adas_core.Domain.Utils;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using MongoDB.Bson;
using Newtonsoft.Json;

namespace adas_core.Controllers;

[Route("config-displays")]
[ApiController]
public class ConfigDisplayController(
    IDisplayConfigService displayConfigService)
    : ControllerBase
{

    /// <summary>
    ///     GetByCodeSysAndCode all display config list
    /// </summary>
    /// <returns>
    ///     List<DisplayConfig />
    /// </returns>
    [HttpGet]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> List()
    {
        return Ok(await displayConfigService.GetAll());
    }

    /// <summary>
    ///     GetByCodeSysAndCode all display config compact paginated
    /// </summary>
    /// <returns>
    ///     List<DisplayConfig />
    /// </returns>
    [HttpPost("paginated")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> ListCompactPaginated([FromBody] PaginationFilter request)
    {
        return Ok(await displayConfigService.GetAllCompactPaginated(request));
    }

    /// <summary>
    ///     GetByCodeSysAndCode all display config compact
    /// </summary>
    /// <returns>
    ///     List<DisplayConfig />
    /// </returns>
    [HttpGet("compact")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    public async Task<IActionResult> ListCompact()
    {
        return Ok(await displayConfigService.GetAllCompact());
    }

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

    /// <summary>
    ///     GetByCodeSysAndCode display config by it object id
    /// </summary>
    /// <returns>
    ///     displayConfig
    /// </returns>
    [HttpGet("{id}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> ListById(string id)
    {
        if (!ObjectId.TryParse(id, out var objectId))
            throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var result = await displayConfigService.GetById(objectId);
        return Ok(result);
    }

    [HttpPost]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> Insert([FromBody] DisplayConfig config)
    {
        var result = await displayConfigService.InsertOne(config);
        return Ok(result);
    }

    [HttpPost("compact")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> InsertMinimal([FromBody] CreateDisplayConfigDto config)
    {
        var result = config.DisplayConfigIdTemplate != null
            ? await displayConfigService.InsertOneWithTemplate(config.DisplayConfigIdTemplate, config.Type,
                config.Hospital)
            : await displayConfigService.InsertOneMinimal(config);
        return Ok(result);
    }

    [HttpGet("insertion-test")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> InsertNurse()
    {
        var result = await displayConfigService.InsertOneTest();
        return Ok(result);
    }

    /// <summary>
    ///     Update display Config and notify subscribers
    /// </summary>
    /// <returns>
    ///     display
    /// </returns>
    [HttpPut("{id}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateConfig(string id, [FromBody] object newDisplayConfig)
    {
        if (!ObjectId.TryParse(id, out var objectId))
            throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);

        var result = await displayConfigService.UpdateConfig(objectId, newDisplayConfig);
        return Ok(result);
    }

    [HttpPut("{idConfig}/color-config")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateConfigColor(string idConfig, ColorConfig colorConfig)
    {
        if (!ObjectId.TryParse(idConfig, out var objectIdConfigDisplay))
            throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var result = await displayConfigService.UpdateConfigColor(objectIdConfigDisplay, colorConfig);

        return result ? Ok(result) : Ok((int)HttpEnum.ErrorMessage.OkResouceNotModified);
    }

    [HttpPut("{idConfig}/header-config")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateHeaderConfig(string idConfig, HeaderConfig headerConfig)
    {
        if (!ObjectId.TryParse(idConfig, out var objectIdConfigDisplay))
            throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var result = await displayConfigService.UpdateHeaderConfig(objectIdConfigDisplay, headerConfig);

        return result ? Ok(result) : Ok((int)HttpEnum.ErrorMessage.OkResouceNotModified);
    }

    [HttpPut("{idConfig}/home-banner")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateSetHomeBanner(string idConfig, List<BannerItem> bannerItems)
    {
        if (!ObjectId.TryParse(idConfig, out var objectIdConfigDisplay))
            throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var displayConfig = await displayConfigService.GetById(objectIdConfigDisplay) ??
                            throw new NotFoundException(HttpEnum.ErrorMessage.NotFoundResourceMissing);
        if (displayConfig.Type != DisplayConfigEnums.DisplayType.DisplayNurse)
            throw new BadRequestException(HttpEnum.ErrorMessage.BadRequestIncorrectType);
        var result = await displayConfigService.UpdateSetHomeBanner(objectIdConfigDisplay, bannerItems);
        return result ? Ok(result) : Ok((int)HttpEnum.ErrorMessage.OkResouceNotModified);
    }

    [HttpPut("update/base-config")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateBaseConfig(DisplayConfig baseConfig)
    {
        var result = await displayConfigService.UpdateBaseConfig(baseConfig);
        return result ? Ok(result) : Ok(HttpEnum.ErrorMessage.OkResouceNotModified);
    }

    [HttpPut("update/card-config")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateCardConfig(CardConfig baseConfig)
    {
        var result = await displayConfigService.UpdateCardConfig(baseConfig);
        return result ? Ok(result) : Ok(HttpEnum.ErrorMessage.OkResouceNotModified);
    }

    [HttpPut("update/detail-config")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateDetailConfig(CardDetailsConfig baseConfig)
    {
        var result = await displayConfigService.UpdateDetailConfig(baseConfig);
        return result ? Ok(result) : Ok(HttpEnum.ErrorMessage.OkResouceNotModified);
    }

    [HttpPut("update/chart-config")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateChartConfig(ChartConfig baseConfig)
    {
        var result = await displayConfigService.UpdateChartConfig(baseConfig);
        return result ? Ok(result) : Ok(HttpEnum.ErrorMessage.OkResouceNotModified);
    }

    [HttpPut("{idConfig}/field-list")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateFieldList(string idConfig, List<Field> fields)
    {
        if (!ObjectId.TryParse(idConfig, out var objectIdConfigDisplay))
            throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var result = await displayConfigService.UpdateFieldList(objectIdConfigDisplay, fields);
        return Ok(result);
    }

    [HttpPost("{idConfig}/name")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> UpdateName(string idConfig, UpdateDisplayConfigNameDto updateDisplayConfigNameDto)
    {
        if (!ObjectId.TryParse(idConfig, out var objectIdConfigDisplay))
            throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var displayConfigName = updateDisplayConfigNameDto.DisplayName;
        if (displayConfigName.IsEmpty())
            throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var result =
            await displayConfigService.UpdateDisplayConfigHospitalName(objectIdConfigDisplay, displayConfigName);
        return result ? Ok(result) : Ok((int)HttpEnum.ErrorMessage.OkResouceNotModified);
    }

    [HttpPost("card-config")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> InsertCardConfig(CreateDisplayConfigCardDto updateDisplayConfigNameDto)
    {
        var result = await displayConfigService.InsertCardConfig(updateDisplayConfigNameDto);
        return Ok(result);
    }

    [HttpPost("detail-config")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> InsertCardDetailConfig(CreateDisplayConfigCardDto updateDisplayConfigNameDto)
    {
        var result = await displayConfigService.InsertCardDetailConfig(updateDisplayConfigNameDto);
        return Ok(result);
    }

    [HttpPost("chart-config")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> InsertChartConfig(CreateDisplayConfigCardDto updateDisplayConfigNameDto)
    {
        var result = await displayConfigService.InsertChartConfig(updateDisplayConfigNameDto);
        return Ok(result);
    }

    [HttpGet("get-all-card-config")]
    [AllowAnonymous]
    public async Task<IActionResult> GetAllCardConfig()
    {
        var result = await displayConfigService.GetCardConfigAll();
        return Ok(result);
    }

    [HttpDelete("{idConfig}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> DeleteDisplayConfig(string idConfig)
    {
        if (!ObjectId.TryParse(idConfig, out var objectIdConfigDisplay))
            throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var result = await displayConfigService.DeleteDisplayConfig(objectIdConfigDisplay);
        if (result) return Ok(result);

        throw new ConflictException(HttpEnum.ErrorMessage.ConflictDeleteFailed);
    }

    [HttpDelete("chart-config/{idConfig}")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> DeleteChartConfig(string idConfig)
    {
        if (!ObjectId.TryParse(idConfig, out var objectIdConfigDisplay))
            throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var result = await displayConfigService.DeleteChartConfig(objectIdConfigDisplay);
        if (result) return Ok(result);

        throw new ConflictException(HttpEnum.ErrorMessage.ConflictDeleteFailed);
    }

    [HttpGet("chart-config/{idConfig}")]
    [AllowAnonymous]
    public async Task<IActionResult> GetChartConfig(string idConfig)
    {
        if (!ObjectId.TryParse(idConfig, out var objectIdConfigDisplay))
            throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        var result = await displayConfigService.GetChartConfig(objectIdConfigDisplay);
        if (result != null) return Ok(result);

        throw new NotFoundException();
    }

    [HttpGet("{idConfig}/locations")]
    [AuthorizeRoles(PermissionEnum.RolesType.AuthSome)]
    [PermissionAuthorize("Source", "DisplayId")]
    public async Task<IActionResult> GetDisplayConfigLocations(string idConfig)
    {
        if (!ObjectId.TryParse(idConfig, out var objectIdConfigDisplay))
            throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);
        return Ok(await displayConfigService.GetDisplayConfigLocations(objectIdConfigDisplay));
    }


    /// <summary>
    ///     Search media element
    /// </summary>
    /// <param name="id">display config id</param>
    /// <param name="filename"></param>
    /// <returns> File stream </returns>
    /// <exception cref="InvalidFormatException"></exception>
    //[AuthorizeRoles(RolesType.Some)]
    //[TypeFilter(type: typeof(AuthorizePermissionsAttribute), Arguments = new object[] { "DisplayId", AuthorizeUserByServiceType.CONFIGDISPLAY })]
    [HttpGet]
    [AllowAnonymous]
    [Route("{id}/getMedia/{filename}")]
    public async Task<IActionResult> StreamMediaById(string filename, string id)
    {
        try
        {
            // Validar el ID
            if (!ObjectId.TryParse(id, out var configDisplayId))
                throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);

            // Obtener la configuraci�n y ruta
            var config = await displayConfigService.GetById(configDisplayId);
            var sharedFolderPath = config.MediaFolder;

            // Validar existencia de carpeta y archivo
            if (!Directory.Exists(sharedFolderPath)) return NotFound("Shared Folder Not Exists");

            var filePath = Path.Combine(sharedFolderPath, filename);
            if (!System.IO.File.Exists(filePath)) return NotFound("File not found");

            var fileInfo = new FileInfo(filePath);
            var fileLength = fileInfo.Length;

            // Leer el encabezado "Range"
            var rangeHeader = Request.Headers["Range"].ToString();
            var end = fileLength - 1;

            if (!string.IsNullOrEmpty(rangeHeader))
            {
                // Parsear el rango solicitado
                var range = rangeHeader.Replace("bytes=", "").Split('-');
                var start = long.Parse(range[0]);
                if (range.Length > 1 && !string.IsNullOrEmpty(range[1])) end = long.Parse(range[1]);

                // Validar el rango solicitado
                if (start >= fileLength || end >= fileLength || start > end)
                    return StatusCode(416, $"Requested Range Not Satisfiable. File length: {fileLength}");
            }

            // Crear un flujo continuo para transmitir los datos
            return new FileStreamResult(new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read),
                MediaUtils.GetMimeType(filePath))
            {
                EnableRangeProcessing = true
            };
        }
        catch (Exception ex)
        {
            return StatusCode(500, $"Error al procesar la solicitud: {ex.Message}");
        }
    }


    /// <summary>
    ///     GetByCodeSysAndCode all media files in a shared folder
    /// </summary>
    /// <param name="id">display config id</param>
    /// <returns>File details list</returns>
    /// <exception cref="InvalidFormatException"></exception>
    [AllowAnonymous]
    [HttpGet("allMediaFiles/{id}")]
    public async Task<IActionResult> GetAllMediaFiles(string id)
    {
        try
        {
            if (!ObjectId.TryParse(id, out var configDisplayId))
                throw new InvalidFormatException(HttpEnum.ErrorMessage.BadRequestInvalidFormat);

            var config = await displayConfigService.GetById(configDisplayId);

            var sharedFolderPath = config.MediaFolder; // @"\\10.0.20.75\smartuci-nurseplan\ad-media";

            // Verificar si la carpeta existe
            if (!Directory.Exists(sharedFolderPath)) return NotFound("Shared Folder Not Exists");

            // Obtener todos los archivos en la carpeta
            var files = Directory.GetFiles(sharedFolderPath);

            var fileDetails = files.Select(file => new
            {
                Name = Path.GetFileName(file),
                Type = MediaUtils.GetMimeType(file),
                SizeInBytes = new FileInfo(file).Length,
                Duration = MediaUtils.IsVideoFile(file)
                    ? MediaUtils.GetVideoDuration(file)
                    : null // S�lo calcula duraci�n para videos
            });

            return Ok(JsonConvert.SerializeObject(fileDetails, new JsonSerializerSettings
            {
                Formatting = Formatting.None
            }));
        }
        catch (Exception ex)
        {
            return StatusCode(500, $"Error al procesar la solicitud: {ex.Message}");
        }
    }
}