using AutoMapper;
using FluentValidation;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PARR.API.Contracts.V1;
using PARR.API.Contracts.V1.Requests;
using PARR.API.Contracts.V1.Requests.Queries;
using PARR.API.Contracts.V1.Responses;
using PARR.API.Contracts.V1.Responses.Base;
using PARR.API.Controllers.V1.Base;
using PARR.API.Extensions;
using PARR.API.Services.Interfaces;
using PARR.Core.Repositories.Interfaces;
using PARR.Domain.Common.Pagination;
using PARR.Domain.Common.Roles;
using PARR.Domain.Entities;

namespace PARR.API.Controllers.V1
{
    /// <summary>
    /// Управление ТНК
    /// </summary>
    [Authorize(Roles = ParrRoles.Administrator.Role)]
    public class TnkController : BaseApiController
    {
        private readonly ILogger<TnkController> logger;
        private readonly IMapper mapper;
        private readonly ITnkRepository tnkService;
        //private readonly IValidator<TnkRequest> validator;
        private readonly IUriService uriService;

        public TnkController(
            ILogger<TnkController> logger,
            IMapper mapper,
            ITnkRepository tnkService,
            //IValidator<TnkRequest> validator,
            IUriService uriService
            )
        {
            this.logger = logger;
            this.mapper = mapper;
            this.tnkService = tnkService;
            //this.validator = validator;
            this.uriService = uriService;
        }


        /// <summary>
        /// Список ТНК постранично
        /// </summary>
        /// <param name="paginationQuery"></param>
        /// <returns></returns>
        [HttpGet(ApiRoutes.Tnk.GetAll)]
        public async Task<IActionResult> GetAll([FromQuery] PaginationQuery paginationQuery, [FromQuery] TnkQuery filter)
        {
            var paginationFilter = mapper.Map<PaginationFilter>(paginationQuery);

            IQueryable<Tnk> query = tnkService.Get()
                                        .OrderBy(t => t.Name);

            if (!string.IsNullOrEmpty(filter.Name))
                query = query.Where(t => t.Name.ToLower().Contains(filter.Name.ToLower()));

            if (filter.SubprocessId.HasValue)
                query = query.Where(t => t.SubprocessId == filter.SubprocessId);

            var tnks = await tnkService.GetPage(query, paginationFilter).ToListAsync();

            if (!tnks.Any())
                return NoContent();

            var tnkResponse = mapper.Map<List<TnkResponse>>(tnks);
            var paginationResponse = new PagedResponse<TnkResponse>(tnkResponse, true).GetPaginatedProps(paginationFilter, query);

            return Ok(paginationResponse);
        }


        /// <summary>
        /// Получить ТНК по id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet(ApiRoutes.Tnk.Get)]
        public async Task<IActionResult> GetById([FromRoute] Guid id)
        {
            var tnk = await tnkService.Get()
                                .FirstOrDefaultAsync(t => t.Id == id);

            if (tnk == null)
                return NotFound();

            var response = mapper.Map<TnkResponse>(tnk);

            return Ok(new Response<TnkResponse>(response, true));
        }


        /// <summary>
        /// Получить связанные с ТНК работы
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpGet(ApiRoutes.Tnk.GetJobs)]
        public async Task<IActionResult> Get([FromRoute] Guid id)
        {
            var tnk = await tnkService.Get()
                                .Include(w => w.Jobs)
                                .FirstOrDefaultAsync(t => t.Id == id);

            if (tnk == null)
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Не найдена ТНК с id: {id}" } }));

            var response = mapper.Map<List<JobBaseResponse>>(tnk.Jobs.OrderBy(t => t.Name).ToList());

            return Ok(new Response<List<JobBaseResponse>>(response, true));
        }



        /// <summary>
        /// Создать ТНК
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPost(ApiRoutes.Tnk.Create)]
        public async Task<IActionResult> Create([FromBody] TnkRequest request)
        {
            //var resultValidate = await validator.ValidateAsync(request);
            //if (!resultValidate.IsValid)
            //    return BadRequest(new Response(resultValidate.Errors));

            var existName = await tnkService.Get().FirstOrDefaultAsync(t => t.Name.ToLower() == request.Name.Trim().ToLower());
            if (existName != null)
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { FieldName = nameof(request.Name), Message = $"Вид работы с именем \"{request.Name}\" уже существует." } }));

            //var existEsppId = await tnkService.Get().FirstOrDefaultAsync(t => t.EsppId == request.EsppId);
            //if (existEsppId != null)
            //    return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { FieldName = nameof(request.EsppId), Message = $"ТНК с EsppId: {request.EsppId} уже существует." } }));

            var tnk = new Tnk
            {
                Id = Guid.NewGuid(),
                Name = request.Name.Trim(),
                EsppId = request.EsppId,
                ShortName = request.ShortName?.Trim(),
                SubprocessId = request.SubprocessId
            };

            if (!await tnkService.CreateAsync(tnk) || !await tnkService.CommitAsync())
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка добавлении ТНК." } }));

            logger.LogInformation($"Пользователь {User.Identity?.Name} добавил ТНК: {tnk.Name}, {tnk.EsppId}, {tnk.SubprocessId}");

            var locationUri = uriService.GetUri(ApiRoutes.Tnk.Get, ApiRoutes.Tnk.getParam, tnk.Id);

            return Created(locationUri, new Response<TnkResponse>(mapper.Map<TnkResponse>(tnk), true));
        }


        /// <summary>
        /// Обновить ТНК
        /// </summary>
        /// <param name="id"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpPut(ApiRoutes.Tnk.Update)]
        public async Task<IActionResult> Update([FromRoute] Guid id, [FromBody] TnkRequest request)
        {
            //var resultValidate = await validator.ValidateAsync(request);
            //if (!resultValidate.IsValid)
            //    return BadRequest(new Response(resultValidate.Errors));

            ////проверка на уникальность esppId
            //var existEsppId = await tnkService.Get().FirstOrDefaultAsync(t => t.Id != id && t.EsppId == request.EsppId);
            //if (existEsppId != null)
            //    return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { FieldName = nameof(request.EsppId), Message = $"Уже есть ТНК с EsppId: {request.EsppId}" } }));

            var orig = await tnkService.Get()
                                .FirstOrDefaultAsync(t => t.Id == id);

            if (orig == null)
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при изменении ТНК." } }));

            orig.Name = request.Name.Trim();
            orig.EsppId = request.EsppId;
            orig.SubprocessId = request.SubprocessId;
            orig.ShortName = request.ShortName?.Trim();
            orig.DateModified = DateTimeOffset.UtcNow;

            if (!await tnkService.CommitAsync())
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при изменении ТНК." } }));

            logger.LogInformation($"Пользователь {User.Identity?.Name} обновил ТНК: {orig.Id}, {orig.Name}, {orig.EsppId}, {orig.SubprocessId}");

            return Ok(new Response<TnkResponse>(mapper.Map<TnkResponse>(orig), true));
        }


        /// <summary>
        /// Удалить ТНК (если у него нет работ)
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [HttpDelete(ApiRoutes.Tnk.Delete)]
        public async Task<IActionResult> Delete([FromRoute] Guid id)
        {
            var tnk = await tnkService.Get().Include(t => t.Jobs).FirstOrDefaultAsync(t => t.Id == id);

            if (tnk == null)
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при удалении ТНК." } }));

            if (tnk.Jobs.Any())
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при удалении ТНК. У данного ТНК есть работы ({tnk.Jobs.Count()} шт.)" } }));

            if (!tnkService.Delete(tnk) || !await tnkService.CommitAsync())
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Ошибка при удалении ТНК." } }));

            logger.LogInformation($"Пользователь {User.Identity?.Name} удалил ТНК: {tnk.Id}, {tnk.Name}, {tnk.EsppId}, {tnk.SubprocessId}");

            return NoContent();
        }
    }
}
