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.Core.Repositories.Interfaces.Unit;
using PARR.Domain.Common.Pagination;
using PARR.Domain.Common.Roles;
using PARR.Domain.Entities;

namespace PARR.API.Controllers.V1
{
    /// <summary>
    /// История работы агента
    /// </summary>
    public class AgentHistoryController : BaseApiController
    {
        //private readonly IValidator<AgentHistoryRequest> validator;
        private readonly IAgentHistoryRepository agentHistoryService;
        private readonly IUriService uriService;
        private readonly IMapper mapper;
        private readonly ITemplateRepository templateService;
        private readonly IClientService clientService;
        private readonly IUnitRepository unitService;
        private readonly ILogger<AgentHistoryController> logger;

        public AgentHistoryController(
            //IValidator<AgentHistoryRequest> validator,
            IAgentHistoryRepository agentHistoryService,
            IUriService uriService,
            IMapper mapper,
            ITemplateRepository templateService,
            IClientService clientService,
            IUnitRepository unitService,
            ILogger<AgentHistoryController> logger
            )
        {
            //this.validator = validator;
            this.agentHistoryService = agentHistoryService;
            this.uriService = uriService;
            this.mapper = mapper;
            this.templateService = templateService;
            this.clientService = clientService;
            this.unitService = unitService;
            this.logger = logger;
        }


        /// <summary>
        /// Получить историю работы агента постранично
        /// </summary>
        /// <returns></returns>
        [Authorize(Roles = ParrRoles.Administrator.Role)]
        [HttpGet(ApiRoutes.AgentHistory.GetAll)]
        public async Task<IActionResult> GetAll([FromQuery] PaginationQuery paginationQuery, [FromQuery] AgentHistoryQuery request)
        {
            var paginationFilter = mapper.Map<PaginationFilter>(paginationQuery);

            IQueryable<AgentHistory> query = agentHistoryService.Get()
                                                .Include(t => t.AgentHistoryLevel)
                                                .Include(t => t.Template)
                                                .Include(t => t.Order).ThenInclude(s => s.OrderStatus)
                                                .Include(t => t.Order).ThenInclude(s => s.NextStatus);

            if (request.TemplateId.HasValue)
                query = query.Where(t => t.TemplateId == request.TemplateId);

            var history = await agentHistoryService.GetPage(query.OrderByDescending(t => t.DateCreated), paginationFilter).ToListAsync();

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

            var response = mapper.Map<List<AgentHistoryResponse>>(history);
            var paginationResponse = new PagedResponse<AgentHistoryResponse>(response, true).GetPaginatedProps(paginationFilter, query);

            return Ok(paginationResponse);
        }


        /// <summary>
        /// Получить запись истории работы агента по id
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        [Authorize(Roles = ParrRoles.Administrator.Role)]
        [HttpGet(ApiRoutes.AgentHistory.Get)]
        public async Task<IActionResult> GetById([FromRoute] Guid id)
        {
            var history = await agentHistoryService.Get()
                                        .Include(t => t.AgentHistoryLevel)
                                        .Include(t => t.Template)
                                        .Include(t => t.Order).ThenInclude(s => s.OrderStatus)
                                        .Include(t => t.Order).ThenInclude(s => s.NextStatus)
                                        .FirstOrDefaultAsync(t => t.Id == id);

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

            var response = mapper.Map<AgentHistoryResponse>(history);

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


        /// <summary>
        /// Добавить запись в историю работы агента
        /// </summary>
        /// <returns></returns>
        [Authorize(Roles = ParrRoles.Agent.RoleOrAdmin)]
        [HttpPost(ApiRoutes.AgentHistory.Create)]
        public async Task<IActionResult> Create([FromBody] AgentHistoryRequest request)
        {
            //var resultValidate = await validator.ValidateAsync(request);
            //if (!resultValidate.IsValid)
            //    return BadRequest(new Response(resultValidate.Errors));


            var clientIp = clientService.GetClientIp()?.ToString();
            var template = await templateService.Get()
                                    .Include(t => t.Unit)
                                    .ThenInclude(t => t!.UnitValues)

                                    .FirstOrDefaultAsync(t => t.Id == request.TemplateId);

            if (template == null)
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { FieldName = nameof(request.TemplateId), Message = $"Не найден шаблон с Id: {request.TemplateId}" } }));

            //проверять что этот этот шаблон привязан к этому серверу по ip
            var unit = await unitService.GetWithIncludes().AsNoTracking().FirstOrDefaultAsync(t => t.Id == template.UnitId);
            var unitIp = unit?.UnitValues.FirstOrDefault(t => t.Field!.AihitName == "IP_АДРЕС")!.Value!.Value;
            if (unitIp != clientIp)
            {
                logger.LogWarning($"Клиент с ip: {clientIp} пытается записать историю агента для templateId: {request.TemplateId}, " +
                    $"но у шаблона ip: {unitIp}, доступ запрещен так как их ip не равны.");
                return Forbid();
            }

            var agentJournal = new AgentHistory
            {
                Id = Guid.NewGuid(),
                Message = request.Message,
                HistoryLevelId = (int)request.Level,
                TemplateId = request.TemplateId
            };

            if (!await agentHistoryService.CreateAsync(agentJournal) || !await agentHistoryService.CommitAsync())
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при добавлении записи в историю работы агента." } }));

            var createdObject = await agentHistoryService.Get()
                                            .Include(t => t.AgentHistoryLevel)
                                            .Include(t => t.Template)
                                            .Include(t => t.Order).ThenInclude(s => s.OrderStatus)
                                            .Include(t => t.Order).ThenInclude(s => s.NextStatus)
                                            .FirstAsync(t => t.Id == agentJournal.Id);
            var response = mapper.Map<AgentHistoryResponse>(createdObject);

            var createdUri = uriService.GetUri(ApiRoutes.AgentHistory.Get, ApiRoutes.AgentHistory.getParam, agentJournal.Id);

            return Created(createdUri, new Response<AgentHistoryResponse>(response, true));
        }
    }
}
