using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Data;
using AsbCloudApp.Data.ProcessMaps;
using AsbCloudApp.Repositories;
using AsbCloudApp.Services;
using AsbCloudApp.Services.ProcessMaps;
using AsbCloudApp.Services.ProcessMaps.WellDrilling;
using AsbCloudWebApi.SignalR;
using AsbCloudWebApi.SignalR.Clients;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SignalR;

namespace AsbCloudWebApi.Controllers.ProcessMaps;

/// <summary>
/// РТК бурение
/// </summary>
public class ProcessMapWellDrillingController : ProcessMapBaseController<ProcessMapPlanWellDrillingDto>
{
    private readonly IProcessMapReportWellDrillingService processMapReportWellDrillingService;
    private readonly IProcessMapReportWellDrillingExportService processMapReportWellDrillingExportService;
    private readonly IProcessMapPlanImportService processMapPlanImportService;

    protected override string SignalRGroup => "ProcessMapWellDrilling";

    public ProcessMapWellDrillingController(IWellService wellService,
        IProcessMapPlanRepository<ProcessMapPlanWellDrillingDto> repository,
        IUserRepository userRepository,
        IProcessMapReportWellDrillingExportService processMapReportWellDrillingExportService,
        IProcessMapPlanImportService processMapPlanImportService,
        IProcessMapReportWellDrillingService processMapReportWellDrillingService, 
        ICrudRepository<WellSectionTypeDto> wellSectionRepository,
        IHubContext<TelemetryHub, ITelemetryHubClient> telemetryHubContext,
        ITelemetryService telemetryService,
        IProcessMapPlanService<ProcessMapPlanWellDrillingDto> service)
        : base(wellService, repository, userRepository, wellSectionRepository, telemetryHubContext, telemetryService, service)
    {
        this.processMapReportWellDrillingExportService = processMapReportWellDrillingExportService;
        this.processMapPlanImportService = processMapPlanImportService;
        this.processMapReportWellDrillingService = processMapReportWellDrillingService;
    }

    /// <summary>
    /// Получение данных для отчета РТК бурение
    /// </summary>
    /// <param name="idWell">Id</param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    [HttpGet("report")]
    [ProducesResponseType(typeof(IEnumerable<ProcessMapPlanWellDrillingDto>), StatusCodes.Status200OK)]
    public async Task<IActionResult> GetReportAsync(int idWell, CancellationToken cancellationToken)
    {
        var report = await processMapReportWellDrillingService.GetAsync(idWell, cancellationToken);

        return Ok(report);
    }

    /// <summary>
    /// Экспорт отчета РТК бурение
    /// </summary>
    /// <param name="idWell">Id скважины</param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    [HttpGet("report/export")]
    [ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    public async Task<IActionResult> ExportReportAsync(int idWell, CancellationToken cancellationToken)
    {
        var report = await processMapReportWellDrillingExportService.ExportAsync(idWell, cancellationToken);

        if (report is null)
            return NoContent();

        return File(report.Value.File, "application/octet-stream", report.Value.Name);
    }

    /// <summary>
    /// Импорт РТК бурение план
    /// </summary>
    /// <param name="idWell">Id скважины</param>
    /// <param name="options"></param>
    /// <param name="file"></param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    [HttpPost("import/{options}")]
    [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> ImportAsync(int idWell, 
        int options, 
        [Required] IFormFile file, 
        CancellationToken cancellationToken)
    {
        await AssertUserHasAccessToEditProcessMapAsync(idWell, cancellationToken);

        if (Path.GetExtension(file.FileName).ToLower() != ".xlsx")
            return this.ValidationBadRequest(nameof(file), "Требуется xlsx файл.");

        using Stream stream = file.OpenReadStream();

        try
        {
            await processMapPlanImportService.ImportAsync(idWell,
                IdUser,
                (options & 1) > 0,
                stream,
                cancellationToken);

            await NotifyUsersBySignalR(idWell, cancellationToken);
        }
        catch (FileFormatException ex)
        {
            return this.ValidationBadRequest(nameof(file), ex.Message);
        }

        return Ok();
    }

    /// <summary>
    /// Экспорт РТК бурение план
    /// </summary>
    /// <param name="idWell">Id скважины</param>
    /// <param name="cancellationToken"></param>
    /// <returns></returns>
    [HttpGet("export")]
    [ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")]
    [ProducesResponseType(typeof(ValidationProblemDetails), StatusCodes.Status400BadRequest)]
    public async Task<IActionResult> ExportAsync(int idWell, CancellationToken cancellationToken)
    {
        var processMapsFile = await processMapPlanImportService.ExportAsync(idWell, cancellationToken);

        return File(processMapsFile.File, "application/octet-stream", processMapsFile.Name);
    }

    /// <summary>
    /// Возвращает шаблон файла для импорта
    /// </summary>
    /// <returns>Запрашиваемый файл</returns>
    [HttpGet("template")]
    [ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")]
    public async Task<IActionResult> GetTemplateAsync(CancellationToken cancellationToken)
    {
        var template = await processMapPlanImportService.GetExcelTemplateStreamAsync(cancellationToken);
        return File(template.File, "application/octet-stream", template.Name);
    }
}