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

namespace AsbCloudWebApi.Controllers
{

    /// <summary>
    /// Суточный рапорт
    /// </summary>
    [Route("api/well/{idWell}/[controller]")]
    [ApiController]
    [Authorize]
    public class DailyReportController : ControllerBase
    {
        private readonly IDailyReportService dailyReportService;
        private readonly IWellService wellService;

        public DailyReportController(
            IDailyReportService dailyReportService,
            IWellService wellService)
        {
            this.dailyReportService = dailyReportService;
            this.wellService = wellService;
        }

        /// <summary>
        /// Список наборов данных для формирования рапорта
        /// </summary>
        /// <param name="idWell"></param>
        /// <param name="begin"></param>
        /// <param name="end"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpGet]
        [ProducesResponseType(typeof(IEnumerable<DailyReportDto>), (int)System.Net.HttpStatusCode.OK)]
        public async Task<IActionResult> GetListAsync(int idWell, DateOnly? begin, DateOnly? end, CancellationToken token)
        {
            var result = await dailyReportService.GetListAsync(idWell, begin, end, token);
            return Ok(result);
        }

        /// <summary>
        /// Создание суточного рапорта
        /// </summary>
        /// <param name="idWell"></param>
        /// <param name="startDate"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpPost]
        [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
        public async Task<IActionResult> AddAsync(int idWell, [Required] DateOnly startDate, CancellationToken token)
        {
            if (!await UserHasAccesToWellAsync(idWell, token))
                return Forbid();

            var idUser = User.GetUserId()!.Value;

            var result = await dailyReportService.AddAsync(idWell, startDate, idUser, token);
            return Ok(result);
        }

        /// <summary>
        /// Сохранение изменений набора данных для формирования рапорта (заголовок)
        /// </summary>
        /// <param name="idWell"></param>
        /// <param name="date">Дата без учета времени</param>
        /// <param name="dto"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpPut("{date}/head")]
        [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
        public Task<IActionResult> UpdateHeadAsync(int idWell, [Required] DateOnly date, [Required] HeadDto dto, CancellationToken token)
            => UpdateReportBlockAsync(idWell, date, dto, token);

        /// <summary>
        /// Сохранение изменений набора данных для формирования рапорта (блок КНБК)
        /// </summary>
        /// <param name="idWell"></param>
        /// <param name="date">Дата без учета времени</param>
        /// <param name="dto"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpPut("{date}/bha")]
        [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
        public Task<IActionResult> UpdateBhaAsync(int idWell, [Required] DateOnly date, [Required] BhaDto dto, CancellationToken token)
            => UpdateReportBlockAsync(idWell, date, dto, token);

        /// <summary>
        /// Сохранение изменений набора данных для формирования рапорта (безметражные работы)
        /// </summary>
        /// <param name="idWell"></param>
        /// <param name="date">Дата без учета времени</param>
        /// <param name="dto"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpPut("{date}/noDrilling")]
        [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
        public Task<IActionResult> UpdateNoDrillingAsync(int idWell, [Required] DateOnly date, [Required] NoDrillingDto dto, CancellationToken token)
            => UpdateReportBlockAsync(idWell, date, dto, token);

        /// <summary>
        /// Сохранение изменений набора данных для формирования рапорта (САУБ)
        /// </summary>
        /// <param name="idWell"></param>
        /// <param name="date">Дата без учета времени</param>
        /// <param name="dto"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpPut("{date}/saub")]
        [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
        public Task<IActionResult> UpdateSaubAsync(int idWell, [Required] DateOnly date, [Required] SaubDto dto, CancellationToken token)
            => UpdateReportBlockAsync(idWell, date, dto, token);

        /// <summary>
        /// Сохранение изменений набора данных для формирования рапорта (подпись)
        /// </summary>
        /// <param name="idWell"></param>
        /// <param name="date">Дата без учета времени</param>
        /// <param name="dto"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpPut("{date}/sign")]
        [ProducesResponseType(typeof(int), (int)System.Net.HttpStatusCode.OK)]
        public Task<IActionResult> UpdateSignAsync(int idWell, [Required] DateOnly date, [Required] SignDto dto, CancellationToken token)
            => UpdateReportBlockAsync(idWell, date, dto, token);

        /// <summary>
        /// Обновление блока суточного рапорта
        /// </summary>
        /// <param name="idWell">ключ скважины</param>
        /// <param name="date">дата суточного рапорта</param>
        /// <param name="dto"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        private async Task<IActionResult> UpdateReportBlockAsync(int idWell, DateOnly date, ItemInfoDto dto, CancellationToken token)
        {
            if (!await UserHasAccesToWellAsync(idWell, token))
                return Forbid();

            dto.IdUser = User.GetUserId();
            dto.LastUpdateDate = DateTimeOffset.Now;

            var result = await dailyReportService.UpdateBlockAsync(idWell, date, dto, token);
            return Ok(result);
        }

        /// <summary>
        /// Сформировать и скачать рапорт в формате excel
        /// </summary>
        /// <param name="idWell"></param>
        /// <param name="date"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpGet("{date}/excel")]
        [ProducesResponseType(typeof(PhysicalFileResult), (int)System.Net.HttpStatusCode.OK)]
        [ProducesResponseType(StatusCodes.Status204NoContent)]
        public async Task<IActionResult> DownloadAsync(int idWell, DateOnly date, CancellationToken token)
        {
            if (!await UserHasAccesToWellAsync(idWell, token))
                return Forbid();

            var well = await wellService.GetOrDefaultAsync(idWell, token);
            if (well is null)
                return this.ValidationBadRequest(nameof(idWell), $"Скважина c id:{idWell} не найдена");

            var stream = await dailyReportService.MakeReportAsync(idWell, date, token);
            if (stream is null) 
                return NoContent();
            
            var fileName = $"Суточный рапорт по скважине {well.Caption} куст {well.Cluster}.xlsx";
            return File(stream, "application/octet-stream", fileName);

        }

        protected async Task<bool> UserHasAccesToWellAsync(int idWell, CancellationToken token)
        {
            var idCompany = User.GetCompanyId();
            if (idCompany is not null &&
                await wellService.IsCompanyInvolvedInWellAsync((int)idCompany, idWell, token)
                    .ConfigureAwait(false))
                return true;
            return false;
        }
    }

}