using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using PARR.API.Contracts.V1;
using PARR.API.Contracts.V1.Requests.BaseRequests;
using PARR.API.Contracts.V1.Requests.Queries;
using PARR.API.Contracts.V1.Responses.Base;
using PARR.API.Contracts.V1.Responses.Statistics;
using PARR.API.Controllers.V1.Base;
using PARR.API.Services.Interfaces;
using PARR.Core.Services.TaskServices.Interfaces;
using PARR.Core.Services.TaskServices.Providers;
using PARR.Core.Services.Workload.Interfaces;
using PARR.Domain.Common.Roles;
using PARR.Domain.Entities.Base.History;
using PARR.Domain.Enums;
using PARR.Domain.Exceptions;
using static PARR.API.Contracts.V1.ApiRoutes;

namespace PARR.API.Controllers.V1.Statistics
{
    /// <summary>
    /// Статистика загруженности по ЗО, РГ
    /// </summary>
    [Authorize(Roles = ParrRoles.EsppRobot.RoleOrAdmin)]
    public class StatWorkloadController : BaseApiController
    {
        private readonly ITaskManagementService taskManagementService;
        private readonly IClientService clientService;
        private readonly ILogger<StatWorkloadController> logger;
        private readonly ITaskMqSettingsProvider taskMqSettingsProvider;
        private readonly IWorkloadService workloadService;
        private readonly IMapper mapper;

        public StatWorkloadController(
            ITaskManagementService taskManagementService,
            IClientService clientService,
            ILogger<StatWorkloadController> logger,
            ITaskMqSettingsProvider taskMqSettingsProvider,
            IWorkloadService workloadService,
            IMapper mapper
            )
        {
            this.taskManagementService = taskManagementService;
            this.clientService = clientService;
            this.logger = logger;
            this.taskMqSettingsProvider = taskMqSettingsProvider;
            this.workloadService = workloadService;
            this.mapper = mapper;
        }


        /// <summary>
        /// Отчет о загруженности по всем РГ
        /// </summary>
        /// <returns></returns>
        [HttpGet(ApiRoutes.Workload.WorkGroup)]
        public async Task<IActionResult> GetWorkGroupReport([FromQuery] TimeZoneOffsetClient offset, [FromQuery] WorkloadBaseQuery request)
        {
            return await GetReportAsync(WorkloadReportType.WorkGroupAll, request.DurationDays, offset.TimeZoneOffset, null);
        }


        /// <summary>
        /// Отчет о загруженности по РГ - работы
        /// </summary>
        /// <param name="workGroup"></param>
        /// <param name="offset"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpGet(ApiRoutes.Workload.WorkGroupJob)]
        public async Task<IActionResult> GetWorkGroupJobReport([FromRoute] string workGroup, [FromQuery] TimeZoneOffsetClient offset, [FromQuery] WorkloadBaseQuery request)
        {
            if (string.IsNullOrWhiteSpace(workGroup))
                throw new AppValidationException("Не указано значение рабочей группы");

            return await GetReportAsync(WorkloadReportType.WorkGroupJob, request.DurationDays, offset.TimeZoneOffset, workGroup);
        }


        /// <summary>
        /// Отчет о загруженности по всем ЗО
        /// </summary>
        /// <returns></returns>
        [HttpGet(ApiRoutes.Workload.ResponseArea)]
        public async Task<IActionResult> GetResponseAreaReport([FromQuery] TimeZoneOffsetClient offset, [FromQuery] WorkloadBaseQuery request)
        {
            return await GetReportAsync(WorkloadReportType.ResponseAreaAll, request.DurationDays, offset.TimeZoneOffset, null);
        }


        /// <summary>
        /// Отчет о загруженности по ЗО - рабочие группы
        /// </summary>
        /// <param name="responseArea"></param>
        /// <param name="offset"></param>
        /// <param name="request"></param>
        /// <returns></returns>
        [HttpGet(ApiRoutes.Workload.ResponseAreaWorkGroups)]
        public async Task<IActionResult> GetResponseAreaWorkGroupsReport([FromRoute] string responseArea, [FromQuery] TimeZoneOffsetClient offset, [FromQuery] WorkloadBaseQuery request)
        {
            if (string.IsNullOrWhiteSpace(responseArea))
                throw new AppValidationException("Не указано значение зоны ответственности");

            return await GetReportAsync(WorkloadReportType.ResponseAreaWorkGroups, request.DurationDays, offset.TimeZoneOffset, responseArea);
        }


        /// <summary>
        /// Сформировать отчетность
        /// </summary>
        /// <returns></returns>
        [HttpPost(ApiRoutes.Workload.Build)]
        public async Task<IActionResult> Build()
        {
            var initiator = new HistoryInitiator
            {
                InitiatorIp = clientService.GetClientIp()?.ToString(),
                InitiatorParrComponentId = ParrComponentsEnum.Api,
                InitiatorComment = "Отправлен запрос из API на формирование отчета о загруженности"
            };

            var queueSettings = taskMqSettingsProvider.GetSettings(TaskTypeEnum.Workload);

            var taskId = await taskManagementService.CreateTaskAsync<object?>(TaskTypeEnum.Workload, default, initiator, queueSettings);

            return Ok(new Response<string?>(null, true, null!, $"Создана задача {taskId} на формирование отчета"));
        }


        /// <summary>
        /// Получить информацию о формировании КЭШ
        /// </summary>
        /// <returns></returns>
        [HttpGet(ApiRoutes.Workload.ReportInfo)]
        public async Task<IActionResult> GetReportInfo()
        {
            var report = await workloadService.GetReportInfoAsync();

            var response = mapper.Map<StatWorkloadCacheInfoResponse>(report);

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


        /// <summary>
        /// Универсальный метод получения отчетности
        /// </summary>
        /// <returns></returns>
        private async Task<IActionResult> GetReportAsync(WorkloadReportType reportType, int durationDays, TimeSpan offset, string? filter)
        {
            var utcNow = DateTimeOffset.UtcNow;
            var localTime = utcNow.ToOffset(offset);
            var dateStart = DateOnly.FromDateTime(localTime.Date);

            var report = await workloadService.GetWorkloadReport(reportType, dateStart, durationDays, offset, filter?.Trim());

            if (report == null)
                return BadRequest(new Response<string?>(null, false, new List<ErrorModel> { new ErrorModel { Message = "Необходимо сформировать отчетность." } }, "empty"));

            var resonse = mapper.Map<StatWorkloadReportResponse>(report);

            return Ok(new Response<StatWorkloadReportResponse>(resonse, true));
        }


    }
}
