using AsbCloudApp.Data;
using AsbCloudApp.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Threading;
using System.Threading.Tasks;
using AsbCloudApp.Services.WellReport;
using Microsoft.AspNetCore.Http;

namespace AsbCloudWebApi.Controllers;

/// <summary>
/// Инфо о скважине
/// </summary>
[Route("api/well")]
[ApiController]
[Authorize]
public class WellController : ControllerBase
{
    private readonly IWellService wellService;
    private readonly IWellReportExportService wellReportExportService;

	public WellController(IWellService wellService, IWellReportExportService wellReportExportService)
	{
		this.wellService = wellService;
		this.wellReportExportService = wellReportExportService;
	}

    /// <summary>
    /// Возвращает список доступных скважин
    /// </summary>
    /// <param name="token"> Токен отмены задачи </param>
    /// <returns>Список скважин</returns>
    [HttpGet]
    [Permission]
    [ProducesResponseType(typeof(IEnumerable<WellDto>), (int)System.Net.HttpStatusCode.OK)]
    public async Task<IActionResult> GetWellsAsync(CancellationToken token)
    {
        var idCompany = User.GetCompanyId();

        if (idCompany is null)
            return NoContent();

        var wells = await wellService.GetAsync(new() { IdCompany = idCompany },
            token).ConfigureAwait(false);

        return Ok(wells);
    }

    /// <summary>
    /// Возвращает список доступных скважин
    /// </summary>
    /// <param name="token"> Токен отмены задачи </param>
    /// <returns>Список скважин</returns>
    [HttpGet("wellTree")]
    [ProducesResponseType(typeof(IEnumerable<DepositBranchDto>), (int)System.Net.HttpStatusCode.OK)]
    public async Task<IActionResult> GetWellTreeAsync(CancellationToken token)
    {
        var idCompany = User.GetCompanyId();

        if (idCompany is null)
            return NoContent();

        var wells = await wellService.GetWellTreeAsync((int)idCompany,
            token).ConfigureAwait(false);

        return Ok(wells);
    }

    /// <summary>
    /// Возвращает информацию о требуемой скважине 
    /// </summary>
    /// <param name="idWell"> Id требуемой скважины </param>
    /// <param name="token"> Токен отмены задачи </param>
    /// <returns>Информация о требуемой скважине </returns>
    [HttpGet("{idWell}")]
    [Permission]
    [ProducesResponseType(typeof(WellMapInfoWithTelemetryStat), (int)System.Net.HttpStatusCode.OK)]
    [ProducesResponseType((int)System.Net.HttpStatusCode.NoContent)]
    public async Task<IActionResult> GetAsync(int idWell, CancellationToken token)
    {
        var idCompany = User.GetCompanyId();

        if (idCompany is null || !await wellService.IsCompanyInvolvedInWellAsync(idCompany ?? default, idWell, token).ConfigureAwait(false))
            return Forbid();

        var well = await wellService.GetOrDefaultStatAsync(idWell, token);

        return Ok(well);
    }

    /// <summary>
    /// Редактирует указанные поля скважины
    /// </summary>
    /// <param name="dto"> Объект параметров скважины.
    /// IdWellType: 1 - Наклонно-направленная, 2 - Горизонтальная.
    /// State: 0 - Неизвестно, 1 - В работе, 2 - Завершена.</param>
    /// <param name="token"> Токен отмены задачи </param>
    /// <returns></returns>
    [HttpPut]
    [Permission]
    [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
    public async Task<IActionResult> UpdateWellAsync(WellDto dto,
        CancellationToken token)
    {
        var idCompany = User.GetCompanyId();

        if (idCompany is null || !await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
            dto.Id, token).ConfigureAwait(false))
            return Forbid();

        var result = await wellService.UpdateAsync(dto, token)
            .ConfigureAwait(false);

        return Ok(result);

    }

    /// <summary>
    /// Обновляет статус скважины
    /// </summary>
    /// <param name="idWell">ключ скважины</param>
    /// <param name="idState">статус: 0 - Неизвестно, 1 - В работе, 2 - Завершена.</param>
    /// <param name="token"></param>
    /// <returns></returns>
    [HttpPut("{idWell}/state")]
    [Permission]
    [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
    public async Task<IActionResult> UpdateWellStateAsync(int idWell,
        [Range(0, 2, ErrorMessage = "Статус некорректен")] int idState,
        CancellationToken token)
    {
        var idCompany = User.GetCompanyId();

        if (idCompany is null || !await wellService.IsCompanyInvolvedInWellAsync((int)idCompany,
            idWell, token).ConfigureAwait(false))
            return Forbid();

        var dto = await wellService.GetOrDefaultAsync(idWell, token);
        
        if (dto is null)
            return this.ValidationBadRequest(nameof(idWell), $"Скважина с id: {idWell} недоступна");

        dto.IdState = idState;

        var result = await wellService.UpdateAsync(dto, token)
            .ConfigureAwait(false);

        return Ok(result);

    }

    //TODO: навзание пока такое. У нас в API уже есть метод с такой сигнатурой.

    /// <summary>
    /// Получить отчёт по скважине
    /// </summary>
    /// <param name="idWell"></param>
    /// <param name="token"></param>
    /// <returns></returns>
    [HttpGet("{idWell}/report/export")]
    [ProducesResponseType(typeof(PhysicalFileResult), StatusCodes.Status200OK, "application/octet-stream")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    public async Task<IActionResult> ExportAsync(int idWell, CancellationToken token)
    {
        var report = await wellReportExportService.ExportAsync(idWell, token);

        if (report is null)
            return NoContent();

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