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

namespace AsbCloudWebApi.Controllers
{
    [Route("api/well/{idWell}/telemetryAnalytics")]
    [ApiController]
    [Authorize]
    public class TelemetryAnalyticsController : ControllerBase
    {
        private readonly ITelemetryAnalyticsService analyticsService;
        private readonly IWellService wellService;

        public TelemetryAnalyticsController(ITelemetryAnalyticsService analyticsService, IWellService wellService)
        {
            this.analyticsService = analyticsService;
            this.wellService = wellService;
        }

        /// <summary>
        /// Возвращает список операций на скважине за все время
        /// </summary>
        /// <param name="idWell">id скважины</param>
        /// <param name="categoryIds">список категорий</param>
        /// <param name="begin">дата начала</param>
        /// <param name="end">окончание</param>
        /// <param name="skip">для пагинации кол-во записей пропустить</param>
        /// <param name="take">для пагинации кол-во записей </param>
        /// <param name="token"> Токен отмены задачи </param>
        /// <returns>Список операций на скважине за все время</returns>
        [HttpGet]
        [Route("operationsByWell")]
        [ProducesResponseType(typeof(PaginationContainer<TelemetryOperationDto>), (int)System.Net.HttpStatusCode.OK)]
        public async Task<IActionResult> GetOperationsByWellAsync(int idWell, int skip = 0, int take = 32,
            [FromQuery] IEnumerable<int> categoryIds = default, DateTime begin = default, DateTime end = default,
            CancellationToken token = default)
        {
            int? idCompany = User.GetCompanyId();

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

            var analytics = await analyticsService.GetOperationsByWellAsync(idWell, categoryIds, begin, end, skip, take, token)
                .ConfigureAwait(false);

            if (analytics is null || analytics.Count == 0)
                return NoContent();

            return Ok(analytics);
        }

        /// <summary>
        /// Возвращает данные по скважине "глубина-день"
        /// </summary>
        /// <param name="idWell">id скважины</param>
        /// <param name="token">Токен отмены задачи</param>
        /// <returns>Коллекцию данных по скважине "глубина-день"</returns>
        [HttpGet]
        [Route("wellDepthToDay")]
        [ProducesResponseType(typeof(IEnumerable<WellDepthToDayDto>), (int)System.Net.HttpStatusCode.OK)]
        public async Task<IActionResult> GetWellDepthToDayAsync(int idWell,
            CancellationToken token = default)
        {
            int? idCompany = User.GetCompanyId();

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

            var wellDepthToDayData = await analyticsService.GetWellDepthToDayAsync(idWell, token)
                .ConfigureAwait(false);

            if (wellDepthToDayData is null || !wellDepthToDayData.Any())
                return NoContent();

            return Ok(wellDepthToDayData);
        }

        /// <summary>
        /// Возвращает данные по глубине скважины за период
        /// </summary>
        /// <param name="idWell">id скважины</param>
        /// <param name="intervalSeconds">количество секунд в необходимом интервале времени</param>
        /// <param name="workBeginSeconds">количество секунд в времени начала смены</param>
        /// <param name="token">Токен отмены задачи</param>
        /// <returns>Коллекцию данных по глубине скважины за период</returns>
        [HttpGet]
        [Route("wellDepthToInterval")]
        [ProducesResponseType(typeof(IEnumerable<WellDepthToIntervalDto>), (int)System.Net.HttpStatusCode.OK)]
        public async Task<IActionResult> GetWellDepthToIntervalAsync(int idWell,
            int intervalSeconds, int workBeginSeconds, CancellationToken token = default)
        {
            int? idCompany = User.GetCompanyId();

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

            var wellDepthToIntervalData = await analyticsService.GetWellDepthToIntervalAsync(idWell,
                intervalSeconds, workBeginSeconds, token).ConfigureAwait(false);

            if (wellDepthToIntervalData is null || !wellDepthToIntervalData.Any())
                return NoContent();

            return Ok(wellDepthToIntervalData);
        }

        /// <summary>
        /// Возвращает данные по операциям на скважине "операции-время"
        /// </summary>
        /// <param name="idWell">id скважины</param>
        /// <param name="begin">дата начала интервала</param>
        /// <param name="end">дата окончания интервала</param>
        /// <param name="token">Токен отмены задачи</param>
        /// <returns>Коллекцию операций на скважине</returns>
        [HttpGet]
        [Route("operationsSummary")]
        [ProducesResponseType(typeof(IEnumerable<TelemetryOperationDurationDto>), (int)System.Net.HttpStatusCode.OK)]
        public async Task<IActionResult> GetOperationsSummaryAsync(int idWell, DateTime begin = default,
            DateTime end = default, CancellationToken token = default)
        {
            int? idCompany = User.GetCompanyId();

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

            var analytics = await analyticsService.GetOperationsSummaryAsync(idWell,
                begin, end, token).ConfigureAwait(false);

            if (analytics is null || !analytics.Any())
                return NoContent();

            return Ok(analytics);
        }

        /// <summary>
        /// Возвращает детальные данные по операциям на скважине за период
        /// </summary>
        /// <param name="idWell">id скважины</param>
        /// <param name="intervalSeconds">количество секунд в необходимом интервале времени</param>
        /// <param name="workBeginSeconds">количество секунд в времени начала смены</param>
        /// <param name="token">Токен отмены задачи</param>
        /// <returns>Коллекцию операций на скважине</returns>
        [HttpGet]
        [Route("operationsToInterval")]
        [ProducesResponseType(typeof(IEnumerable<TelemetryOperationDurationDto>), (int)System.Net.HttpStatusCode.OK)]
        public async Task<IActionResult> GetOperationsToIntervalAsync(int idWell,
            int intervalSeconds, int workBeginSeconds, CancellationToken token = default)
        {
            int? idCompany = User.GetCompanyId();

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

            var analytics = await analyticsService.GetOperationsToIntervalAsync(idWell,
                intervalSeconds, workBeginSeconds, token).ConfigureAwait(false);

            if (analytics is null || !analytics.Any())
                return NoContent();

            return Ok(analytics);
        }

        /// <summary>
        /// Возвращает даты первой и последней операций на скважине
        /// </summary>
        /// <param name="idWell">id скважины</param>
        /// <param name="token">Токен для отмены задачи</param>
        /// <param name="isUtc">Смена дат с UTC формата на часовой пояс скважины</param>
        /// <returns>Даты самой первой и самой последней операций на скважине</returns>
        [HttpGet]
        [Route("datesRange")]
        [ProducesResponseType(typeof(DatesRangeDto), (int)System.Net.HttpStatusCode.OK)]
        public async Task<IActionResult> GetOperationsDateRangeAsync(int idWell, bool isUtc = true,
            CancellationToken token = default)
        {
            int? idCompany = User.GetCompanyId();

            if (idCompany is null)
                return Forbid();

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

            var wellOperationsDatesRange = await analyticsService.GetOperationsDateRangeAsync(idWell,
                isUtc, token).ConfigureAwait(false);

            return Ok(wellOperationsDatesRange);
        }
    }
}