using AsbCloudApp.Data;
using AsbCloudApp.Data.DrillTestReport;
using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Repositories;
using AsbCloudApp.Requests;
using AsbCloudApp.Services;
using AsbCloudWebApi.SignalR;
using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;
using System;
using System.ComponentModel.DataAnnotations;
using System.Net;
using System.Threading;
using System.Threading.Tasks;

namespace AsbCloudWebApi.Controllers;

/// <summary>
/// Контроллер для drill_test отчётов 
/// </summary>
[ApiController]
[Authorize]
public class DrillTestController : ControllerBase
{
    private readonly IDrillTestReportService drillTestReportService;
    private readonly IDrillTestRepository drillTestRepository;
    private readonly IWellService wellService;
    private readonly ITelemetryService telemetryService;
    private readonly IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext;


    public DrillTestController(
        IDrillTestReportService drillTestReportService,
        IDrillTestRepository drillTestRepository,
        IWellService wellService,
        ITelemetryService telemetryService,
        IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext)
    {
        this.drillTestReportService = drillTestReportService;
        this.drillTestRepository = drillTestRepository;
        this.wellService = wellService;
        this.telemetryService = telemetryService;
        this.telemetryHubContext = telemetryHubContext;
    }

    /// <summary>
    /// Метод получения данных drill_test и drill_test_params от панели оператора.
    /// Сохраняет в БД.        
    /// </summary>
    /// <param name="uid">уникальный идентификатор записи drill_test</param>
    /// <param name="dto">запись drill test</param>        
    /// <param name="token"></param>
    /// <returns></returns>
    [AllowAnonymous]
    [HttpPost("api/telemetry/{uid}/[controller]")]
    public async Task<IActionResult> PostDataAsync(
    string uid,
        [FromBody] DrillTestDto dto,
        CancellationToken token)
    {
        var telemetry = telemetryService.GetOrCreateTelemetryByUid(uid);
        if (telemetry is null)
            throw new Exception($"Telemetry with RemoteUid: {uid} does not exist.");

        await drillTestRepository.SaveDataAsync(telemetry.Id, dto, token);
        var idWell = telemetryService.GetIdWellByTelemetryUid(uid);
        if (idWell is not null)
            _ = Task.Run(async () =>
            {
                var clients = telemetryHubContext.Clients.Group($"well_{idWell}");
                await clients.ReceiveDrilltestData(dto, token);
            }, CancellationToken.None);

        return Ok();
    }

    /// <summary>
    /// Формирование отчёта
    /// </summary>
    /// <param name="idWell">Id скважины</param>
    /// <param name="id">Ключ entity test записи</param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    [HttpGet("api/well/{idWell}/[controller]")]
    [Permission]
    [ProducesResponseType(typeof(PhysicalFileResult), (int)HttpStatusCode.OK, "application/octet-stream")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    public async Task<IActionResult> GenerateReportAsync([FromRoute] int idWell,
        [FromQuery] int id,
        CancellationToken cancellationToken)
    {
        if (!await CanUserAccessToWellAsync(idWell, cancellationToken))
            return Forbid();

        var reportFile = await drillTestReportService.GenerateAsync(idWell, id, cancellationToken);

        return File(reportFile.stream, "application/octet-stream", reportFile.fileName);
    }

    /// <summary>
    /// Список файлов drill test отчётов
    /// </summary>
    /// <param name="idWell">Id скважины</param>
    /// <param name="request">Параметры запроса</param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    [HttpGet("api/well/{idWell}/[controller]/all")]
    [Permission]
    [ProducesResponseType(typeof(PaginationContainer<DrillTestReportInfoDto>), (int)HttpStatusCode.OK)]
    public async Task<IActionResult> GetListAsync([FromRoute][Required] int idWell,
        [FromQuery] FileReportRequest request,
        CancellationToken cancellationToken)
    {
        if (!await CanUserAccessToWellAsync(idWell, cancellationToken))
            return Forbid();

        var reports = await drillTestReportService.GetListAsync(idWell,
            request,
            cancellationToken);

        return Ok(reports);
    }

    private async Task<bool> CanUserAccessToWellAsync(int idWell, CancellationToken cancellationToken)
    {
        int? idCompany = User.GetCompanyId();
        return idCompany is not null && await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
            idWell, cancellationToken).ConfigureAwait(false);
    }
}