using AsbCloudApp.Exceptions;
using AsbCloudWebApi.SignalR;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace AsbCloudWebApi.Controllers;

/// <summary>
/// Имитирует разные типы ответа сервера
/// </summary>
[Route("api/[controller]")]
[ApiController]
public class MockController : ControllerBase
{
    private readonly IServiceProvider provider;

    public MockController(IServiceProvider provider)
    {
        this.provider = provider;
    }

    /// <summary>
    /// имитирует http-400
    /// </summary>
    [HttpGet("400")]
    [ProducesResponseType(typeof(ValidationProblemDetails), (int)System.Net.HttpStatusCode.BadRequest)]
    public IActionResult Get400([FromQuery, Required]IDictionary<string, string> args)
    {
        var errors = new Dictionary<string, string[]>();
        
        foreach (var arg in args)
        {
            var countOfErrors = ((arg.Key + arg.Value).Length % 3) + 1;
            var errorsText = Enumerable.Range(0, countOfErrors)
                .Select(i => $"{arg.Value} не соответствует критериям проверки № {i}");

            errors.Add(arg.Key, errorsText.ToArray());                
        }

        if (errors.Any())
        {
            var problem = new ValidationProblemDetails(errors);                
            return BadRequest(problem);
        }
        else
        {
            var problem = new ValidationProblemDetails { Detail = "at least one argument must be provided" };
            return BadRequest(problem);
        }
    }

    /// <summary>
    /// имитирует http-403
    /// </summary>
    [HttpGet("403")]
    public IActionResult Get403()
    {
        return Forbid();
    }

    /// <summary>
    /// имитирует http-401
    /// </summary>
    [HttpGet("401")]
    public IActionResult Get401()
    {
        return Unauthorized();
    }

    /// <summary>
    /// имитирует http-500
    /// </summary>
    [HttpGet("500")]
    public IActionResult Get500()
    {
        throw new System.Exception("Это тестовое исключение");
    }

    /// <summary>
    /// имитация отправки SignalR данных
    /// </summary>
    /// <example>
    /// </example>
    /// <param name="hubName">
    /// Поддерживаемые hubЫ: wellInfo, notifications, telemetry, reports
    /// </param>
    /// <param name="methodName">Название вызываемого на клиенте метода. Прим.:"ReceiveDataSaub". Список методов см. в swagger definition signalr</param>
    /// <param name="groupName">Группа пользователей. Прим.: "well_1". Если не задана - все пользователи. Шаблон формирования групп см. описание методов в swagger definition signalr</param>
    /// <param name="body">передаваемая нагрузка. (json)</param>
    /// <param name="token"></param>
    /// <returns></returns>
    [HttpPost("signalr/hubs/{hubName}/{methodName}/{groupName}")]
    [Authorize]
    public async Task<IActionResult> PostAsync(string hubName, string methodName, string? groupName, object body, CancellationToken token)
    {
        IHubClients clients = hubName.ToLower() switch {
            "wellinfo" => provider.GetRequiredService<IHubContext<NotificationHub>>().Clients,
            "notifications" => provider.GetRequiredService<IHubContext<NotificationHub>>().Clients,
            "telemetry" => provider.GetRequiredService<IHubContext<TelemetryHub>>().Clients,
            "reports" => provider.GetRequiredService<IHubContext<ReportsHub>>().Clients,
            _ => throw new ArgumentInvalidException(nameof(hubName), "hubName does not listed"),
        };

        IClientProxy selectedClients = string.IsNullOrEmpty(groupName)
            ? clients.All
            : clients.Group(groupName);

        await selectedClients.SendAsync(methodName, body, token);
        return Ok();
    }
}