using AsbCloudApp.Data.SAUB;
using AsbCloudApp.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace AsbCloudWebApi.Controllers.SAUB
{
    /// <summary>
    /// Рекомендация уставок бурильщику
    /// </summary>
    [ApiController]
    [Authorize]
    public class SetpointsController : ControllerBase
    {
        private readonly ISetpointsService setpointsService;
        private readonly IWellService wellService;
        private const int ObsolescenceSecMin = 30;
        private const int ObsolescenceSecMax = 6 * 60 * 60;

        public SetpointsController(ISetpointsService setpointsService, IWellService wellService)
        {
            this.setpointsService = setpointsService;
            this.wellService = wellService;
        }

        /// <summary>
        /// Получает список запросов на изменение уставок.
        /// </summary>
        /// <param name="idWell"></param>
        /// <returns></returns>
        [HttpGet("api/well/{idWell}/setpointsNames")]
        [ProducesResponseType(typeof(IEnumerable<SetpointInfoDto>), (int)System.Net.HttpStatusCode.OK)]
        [AllowAnonymous]
        public IActionResult GetSetpointsNamesByIdWellAsync([FromRoute] int idWell)
        {
            var result = setpointsService.GetSetpointsNames();
            return Ok(result);
        }

        /// <summary>
        /// Добавляет запрос на изменение заданий панели оператора.
        /// </summary>
        /// <param name="idWell"></param>
        /// <param name="setpoints"></param>
        /// <param name="token"></param>
        /// <returns></returns>        
        [HttpPost("api/well/{idWell}/setpoints")]
        [Permission]
        [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
        public async Task<IActionResult> InsertAsync(int idWell, SetpointsRequestDto setpoints, CancellationToken token = default)
        {
            int? idCompany = User.GetCompanyId();
            int? idUser = User.GetUserId();

            if (idCompany is null || idUser is null)
                return Forbid();

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

            setpoints.IdAuthor = idUser ?? -1;
            setpoints.IdWell = idWell;
            setpoints.IdState = 1;

            if (setpoints is null
                || setpoints.ObsolescenceSec > ObsolescenceSecMax
                || setpoints.ObsolescenceSec < ObsolescenceSecMin)
                return BadRequest("Wrong ObsolescenceSec");

            if (!setpoints.Setpoints.Any())
                return BadRequest("Wrong setpoints count");

            var result = await setpointsService.InsertAsync(setpoints, token)
                .ConfigureAwait(false);

            return Ok(result);
        }

        /// <summary>
        /// Получает список запросов на изменение уставок.
        /// </summary>
        /// <param name="idWell"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpGet("api/well/{idWell}/setpoints")]
        [Permission]
        [ProducesResponseType(typeof(IEnumerable<SetpointsRequestDto>), (int)System.Net.HttpStatusCode.OK)]
        public async Task<IActionResult> GetByIdWellAsync([FromRoute] int idWell, CancellationToken token = default)
        {
            int? idCompany = User.GetCompanyId();
            int? idUser = User.GetUserId();

            if (idCompany is null || idUser is null)
                return Forbid();

            var result = await setpointsService.GetAsync(idWell, token)
                .ConfigureAwait(false);

            return Ok(result);
        }

        /// <summary>
        /// Отчет о принятии, или отклонении уставок оператором.
        /// После уставка будет не изменяемой.
        /// </summary>
        /// <param name="uid"></param>
        /// <param name="id"></param>
        /// <param name="setpointsRequestDto">можно передать только новый state ex.: {state:3} - принято</param>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpPut("api/telemetry/{uid}/setpoints/{id}")]
        [ProducesResponseType(typeof(SetpointsRequestDto), (int)System.Net.HttpStatusCode.OK)]
        [AllowAnonymous]
        public async Task<IActionResult> UpdateByTelemetryUidAsync([FromRoute] string uid, int id, SetpointsRequestDto setpointsRequestDto, CancellationToken token = default)
        {
            var result = await setpointsService.UpdateStateAsync(setpointsRequestDto, token)
                .ConfigureAwait(false);

            return Ok(result);
        }

        /// <summary>
        /// Получает запросы на изменение уставок панели.
        /// !!SIDE EFFECT: изменяет состояние запросов уставок на отправлено, это не позволит удалить эти уставки после отправки на панель.
        /// </summary>
        /// <param name="uid"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpGet("api/telemetry/{uid}/setpoints")]
        [ProducesResponseType(typeof(IEnumerable<SetpointsRequestDto>), (int)System.Net.HttpStatusCode.OK)]
        [AllowAnonymous]
        public async Task<IActionResult> GetByTelemetryUidAsync([FromRoute] string uid, CancellationToken token = default)
        {
            var result = await setpointsService.GetForPanelAsync(uid, token)
                .ConfigureAwait(false);

            return Ok(result);
        }

        /// <summary>
        /// Пробует удалить запрос на изменение уставок. Это будет выполнено, если запрос еще не был отправлен на панель.
        /// </summary>
        /// <param name="idWell"></param>
        /// <param name="id"></param>
        /// <param name="token"></param>
        /// <returns>1 - удалено, 0 и меньше - не удалено</returns>
        [HttpDelete("api/well/{idWell}/setpoints/{id}")]
        [Permission]
        public async Task<IActionResult> TryDeleteByIdWellAsync(int idWell, int id, CancellationToken token = default)
        {
            int? idCompany = User.GetCompanyId();
            int? idUser = User.GetUserId();

            if (idCompany is null || idUser is null)
                return Forbid();

            var result = await setpointsService.TryDelete(id, token)
                .ConfigureAwait(false);

            return Ok(result);
        }
    }
}