using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using PARR.API.Contracts.V1;
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.Services.Interfaces;
using PARR.Core.Services.RobotTask.Interfaces;
using PARR.Domain.Common.Roles;
using PARR.Domain.Entities.Base.History;
using PARR.Domain.Enums;
using PARR.Domain.Exceptions;

namespace PARR.API.Controllers.V1
{
    [Authorize(Roles = ParrRoles.EsppRobot.RoleOrAdmin)]
    public class RobotTaskController : BaseApiController
    {
        private readonly IRobotTaskService robotTaskService;

        private readonly IMapper mapper;
        //private readonly SettingsFromDb settingsFromDb;
        //private readonly IRobotConfigurationRepository robotConfigurationService;
        //private readonly ILogger<RobotTaskController> logger;
        private readonly IClientService clientService;
        //private readonly IRobotHistoryRepository robotHistoryService;
        //private readonly IShortcodesService shortcodesService;
        //private readonly INextRunService nextRunService;

        public RobotTaskController(
            IMapper mapper,
            //SettingsFromDb settingsFromDb,
            //IRobotConfigurationRepository robotConfigurationService,
            //ILogger<RobotTaskController> logger,
            IClientService clientService,
            //IRobotHistoryRepository robotHistoryService,
            //IShortcodesService shortcodesService,
            //INextRunService nextRunService
            IRobotTaskService robotTaskService
            )
        {
            this.robotTaskService = robotTaskService;
            this.mapper = mapper;
            //this.settingsFromDb = settingsFromDb;
            //this.robotConfigurationService = robotConfigurationService;
            //this.logger = logger;
            this.clientService = clientService;
            //this.robotHistoryService = robotHistoryService;
            //this.shortcodesService = shortcodesService;
            //this.nextRunService = nextRunService;
        }


        /// <summary>
        /// Получить задание для робота по коду робота и по статусу задания
        /// </summary>
        /// <param name="robotCode"></param>
        /// <param name="taskStatusCode"></param>
        /// <param name="requestQuery"></param>
        /// <returns></returns>
        [HttpGet(ApiRoutes.RobotTask.GetByRobotAndStatusTask)]
        public async Task<IActionResult> GetByRobotAndStatusTask([FromRoute] RobotsEnum robotCode, [FromRoute] TaskStatusEnum taskStatusCode, [FromQuery] RobotTaskQuery requestQuery)
        {
            switch (robotCode)
            {
                case RobotsEnum.TemplateOrder:
                    var templateTask = await robotTaskService.GetTemplateTaskAsync(
                                                                    taskStatusCode,
                                                                    requestQuery.SetInProgressStatus ?? false,
                                                                    clientService.GetClientIp()?.ToString(),
                                                                    requestQuery.RobotId
                                                                );
                    var templateResponse = mapper.Map<RobotTaskTemplateResponse>(templateTask);

                    return Ok(new Response<RobotTaskTemplateResponse>(templateResponse, true));
                case RobotsEnum.ScheduleOrder:
                    var historyIniciator = new HistoryInitiator
                    {
                        InitiatorComment="Задание роботу, расписание.",
                        InitiatorIp=clientService.GetClientIp()?.ToString(),
                        InitiatorParrComponentId= ParrComponentsEnum.Api
                    };
                    var scheduleTask = await robotTaskService.GetScheduleTaskAsync(
                                                                    taskStatusCode,
                                                                    requestQuery.SetInProgressStatus ?? false,
                                                                    historyIniciator.InitiatorIp,
                                                                    requestQuery.RobotId,
                                                                    historyIniciator
                                                                );

                    var scheduleResponse = mapper.Map<RobotTaskScheduleResponse>(scheduleTask);

                    return Ok(new Response<RobotTaskScheduleResponse>(scheduleResponse, true));
                default:
                    throw new AppValidationException("Некорректное значение robotCode");
            }
        }


        #region Old

        //    /// <summary>
        //    /// Получить задание для робота по коду робота и по статусу задания
        //    /// </summary>
        //    /// <param name="robotCode"></param>
        //    /// <param name="taskStatusCode"></param>
        //    /// <returns></returns>
        //    [HttpGet(ApiRoutes.RobotTask.GetByRobotAndStatusTask)]
        //    public async Task<IActionResult> GetByRobotAndStatusTask([FromRoute] RobotsEnum robotCode, [FromRoute] TaskStatusEnum taskStatusCode, [FromQuery] RobotTaskQuery requestQuery)
        //    {
        //        //Ищем все задания с превышенным кол-вом попыток и с просроченным временем и ставим им статус ошибки
        //        await robotConfigurationService.MarkExpiredTasksAsFailedAsync(settingsFromDb.RobotAttemptsNumber, settingsFromDb.RobotWaitTime);


        //        var query = robotConfigurationService.Get()
        //                            .AsSingleQuery()
        //                            .Where(t => t.RobotCode == (int)robotCode && t.TaskStatusCode == (int)taskStatusCode);

        //        switch (robotCode)
        //        {
        //            case RobotsEnum.TemplateOrder:
        //                // шаблоны
        //                query = query
        //                    .Include(t => t.Template)
        //                        .ThenInclude(t => t!.Unit)
        //                            .ThenInclude(t => t!.UnitValues)
        //                                .ThenInclude(t => t.Field)
        //                    .Include(t => t.Template)
        //                        .ThenInclude(t => t!.Unit)
        //                            .ThenInclude(t => t!.UnitValues)
        //                                .ThenInclude(t => t.Value)
        //                    .Include(t => t.Template)
        //                        .ThenInclude(a => a!.Job)
        //                            .ThenInclude(t => t!.Group)
        //                                .ThenInclude(g => g.GroupType)
        //                    .Include(t => t.Template)
        //                        .ThenInclude(w => w!.Job)
        //                        .ThenInclude(t => t!.Tnk)
        //                        .ThenInclude(s => s!.Subprocess)
        //                        .ThenInclude(p => p!.Process);

        //                query = query
        //                    .Include(t => t.Template)
        //                        .ThenInclude(t => t!.UnitsInTemplate);

        //                break;

        //            case RobotsEnum.ScheduleOrder:
        //                //расписание
        //                query = query
        //                    .Include(t => t.Template)
        //                        .ThenInclude(t => t!.Unit)
        //                            .ThenInclude(t => t!.UnitValues)
        //                                .ThenInclude(t => t.Field)
        //                    .Include(t => t.Template)
        //                        .ThenInclude(t => t!.Unit)
        //                            .ThenInclude(t => t!.UnitValues)
        //                                .ThenInclude(t => t.Value)
        //                    .Include(t => t.Template)
        //                        .ThenInclude(a => a!.Job)
        //                            .ThenInclude(t => t!.Group)
        //                                .ThenInclude(g => g.GroupType)
        //                    .Include(t => t.Template)
        //                        .ThenInclude(a => a!.Job)
        //                            .ThenInclude(t => t!.Group)
        //                                .ThenInclude(t => t!.EsppSchValues)
        //                                    .ThenInclude(t => t!.EsppSchTypeConfig)
        //                                    .ThenInclude(t => t!.EsppSchTypeSchedule)
        //                    .Include(t => t.Template)
        //                        .ThenInclude(t => t!.Job)
        //                            .ThenInclude(t => t!.Group)
        //                                .ThenInclude(t => t!.ScheduleExcludeType)
        //                    .Include(t => t.Template)
        //                        .ThenInclude(t => t!.Job)
        //                            .ThenInclude(t => t!.Group)
        //                                .ThenInclude(t => t.ScheduleExcludeTypeCalendar)
        //                    .Include(t => t.Template)
        //                        .ThenInclude(t => t!.Job)
        //                            .ThenInclude(t => t!.Tnk)
        //                    .Include(t => t.Template)
        //                        .ThenInclude(t => t!.UnitsInTemplate);

        //                //выбираем только записи с созданными шаблонами (у которых статус 20 или 30), а только потом у них ищем расписания
        //                var createdTemplates = robotConfigurationService.Get()
        //                                                    .Where(t => t.RobotCode == (int)RobotsEnum.TemplateOrder && (t.TaskStatusCode == (int)TaskStatusEnum.Ok))
        //                                                    .Select(t => t.TemplateId);
        //                query = query.Where(t => t.RobotCode == (int)RobotsEnum.ScheduleOrder && createdTemplates.Contains(t.TemplateId));
        //                //  query = query.Where(t => t.RobotCode == (int)RobotsEnum.ScheduleOrder && t.TemplateId==Guid.Parse("7cb7c3be-506d-40e0-a63f-4554edb52459"));
        //                break;

        //            default:
        //                break;
        //        }


        //        // сортируем по NextRun, чтобы те у которых дата след срабатывания ближе к текущей, выполнились скорее
        //        query = query.OrderBy(t => t.Template!.NextRun).ThenBy(t => t.Template!.IsActiveSchedule).ThenBy(t => t.Template.IsActiveTemplate);

        //        RobotConfiguration? task = null;

        //        //ищем задание в ожидании, если нашли, выбираем его
        //        task = await query.FirstOrDefaultAsync(t => t.RobotStatusCode == (int)RobotStatusEnum.Wait);

        //        if (task == null)
        //        {
        //            //ищем задания в работе, которые можно перезапустить
        //            //Поиск по `RobotStatusCode` = 22.
        //            //Далее проверяется `LastStatusUpdated`, что время последнего смены статуса не превышает допустимого(берется из настроек, поле `RobotWaitTime`)
        //            //и что текущая попытка не больше разрешенной(берется из настроек, поле `RobotAttemptsNumber`) - если это так, берется эта запись.

        //            var endDate = DateTimeOffset.UtcNow.Add(-settingsFromDb.RobotWaitTime);
        //            task = await query
        //                            .FirstOrDefaultAsync(t =>
        //                                                t.RobotStatusCode == (int)RobotStatusEnum.InProgress
        //                                                && t.AttemptsNumber < settingsFromDb.RobotAttemptsNumber
        //                                                && t.LastRobotStatusUpdated < endDate
        //                                            );
        //        }

        //        if (task == null)
        //            return NotFound();

        //        if (requestQuery?.SetInProgressStatus == true)
        //        {
        //            var resultSetStatus = await SetInProgressStatusAsync(task.Id);
        //            if (resultSetStatus == false)
        //            {
        //                logger.LogError($"Ошибка при установке статуса {RobotStatusEnum.InProgress.ToString()} для задания RobotConfigutationId {task.Id} (при выдаче задания роботу)");
        //                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при выдаче задания." } }));
        //            }
        //        }

        //        switch (robotCode)
        //        {
        //            case RobotsEnum.TemplateOrder:
        //                {    //RobotTaskTemplateResponse
        //                    var robotTaskTemplateResponse = mapper.Map<RobotTaskTemplateResponse>(task);

        //                    robotTaskTemplateResponse.FullDescription = NormalizeLineEndingsToCrlf(await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.FullDescription, task.Template!));
        //                    robotTaskTemplateResponse.ShortDescription = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.ShortDescription, task.Template!);
        //                    robotTaskTemplateResponse.Solution = NormalizeLineEndingsToCrlf(await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.Solution, task.Template!));
        //                    robotTaskTemplateResponse.TnkName = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.TnkName, task.Template!);
        //                    robotTaskTemplateResponse.WorkName = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.WorkName, task.Template!);
        //                    robotTaskTemplateResponse.WorkGroup = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.WorkGroup, task.Template!);
        //                    robotTaskTemplateResponse.ResponseArea = await shortcodesService.ApplyShortcodesAsync(robotTaskTemplateResponse.ResponseArea, task.Template!);

        //                    return Ok(new Response<RobotTaskTemplateResponse>(robotTaskTemplateResponse, true));
        //                }
        //            case RobotsEnum.ScheduleOrder:
        //                { // если был запрос на расписание, проверяем у него nextRun, lastRun, обновляем их
        //                    var resultUpdateNextRun = await UpdateNextRunAsync(task);
        //                    if (!resultUpdateNextRun)
        //                    {
        //                        logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}", task.TemplateId);
        //                        return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при расчете NextRun" } }));
        //                    }

        //                    //RobotTaskScheduleResponse
        //                    var robotTaskScheduleResponse = mapper.Map<RobotTaskScheduleResponse>(task);

        //                    robotTaskScheduleResponse.Timezone = settingsFromDb.EsppScheduleTimezone;

        //                    robotTaskScheduleResponse.WorkGroup = await shortcodesService.ApplyShortcodesAsync(robotTaskScheduleResponse.WorkGroup, task.Template!);
        //                    robotTaskScheduleResponse.ResponseArea = await shortcodesService.ApplyShortcodesAsync(robotTaskScheduleResponse.ResponseArea, task.Template!);

        //                    //var nextRunWithRobotTz = nextRunService.GetNextRunWithTimezoneEsppAndResponseArea(task.Template!.NextRun, task.Template!.Job?.Group?.IsResponseAreaTimezone, robotTaskScheduleResponse.ResponseArea);
        //                    //nextRun в часовой зоне УЗ Робота ЕСПП
        //                    var nextRunWithRobotTz = task.Template!.NextRun.Add(nextRunService.GetEsppAccountOffset());

        //                    //на всякий случай еще раз проверяем, что дата не устарела и отправляем задание
        //                    if (nextRunWithRobotTz < DateTimeOffset.UtcNow)
        //                    {
        //                        logger.LogError("Ошибка при расчете NextRun для templateId: {templateId}, итоговое значение для робота, меньше чем сейчас {nextRunWithRobotTz}<{now}",
        //                                                                    task.TemplateId, nextRunWithRobotTz, DateTimeOffset.UtcNow);
        //                        return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = "Ошибка при расчете NextRun" } }));
        //                    }

        //                    robotTaskScheduleResponse.NextStart = EsppScheduleHelpers.GetNextRun(nextRunWithRobotTz);
        //                    robotTaskScheduleResponse.GenerationTime = EsppScheduleHelpers.GetGenerationTime(nextRunWithRobotTz);

        //                    return Ok(new Response<RobotTaskScheduleResponse>(robotTaskScheduleResponse, true));
        //                }
        //            default:
        //                break;
        //        }

        //        return BadRequest();
        //    }


        //    /// <summary>
        //    /// Обоновить NextRun если он устарел
        //    /// </summary>
        //    /// <param name="task"></param>
        //    /// <returns></returns>
        //    private async Task<bool> UpdateNextRunAsync(RobotConfiguration task)
        //    {
        //        var template = task.Template!;

        //        //var nextRun = await esppScheduleTransformService.GetNextDateAsync(template.Job!.GroupId, template!.Job!.Group!.ReferenceDate);
        //        var nextRun = await nextRunService.GetNextRunForTemplateAsync(template.Id, false);

        //        if (!nextRun.HasValue)
        //        {
        //            logger.LogError("При обновлении nextRun для шаблона {templateId}, расчитанный nextRun=null, ошибка в расчетах.", template.Id);
        //            return false;
        //        }

        //        if (nextRun.Value < DateTimeOffset.UtcNow)
        //        {
        //            logger.LogError("При обновлении nextRun для шаблона {templateId}, расчитанный nextRun<Now [{nextRun}<{now}], ошибка в расчетах.", template.Id, nextRun.Value, DateTimeOffset.UtcNow);
        //            return false;
        //        }

        //        if (nextRun != template.NextRun)
        //        {
        //            logger.LogDebug($"Для шаблона id {template.Id} обновляю nextRun, новое значение {nextRun}, старое значение {template.NextRun}");

        //            template.LastRun = template.NextRun;
        //            template.NextRun = nextRun.Value;

        //            await robotConfigurationService.CommitAsync(new HistoryInitiator { InitiatorComment = "При получении задания роботом, обновил NextRun", InitiatorIp = clientService.GetClientIp()?.ToString(), InitiatorParrComponentId = ParrComponentsEnum.Api });
        //        }

        //        return true;
        //    }


        //    /// <summary>
        //    /// Устанавливаем статус "Робот взял в работу", пишем в историю работы роботов инф о начале работ
        //    /// </summary>
        //    /// <param name="taskId"></param>
        //    /// <returns></returns>
        //    private async Task<bool> SetInProgressStatusAsync(Guid taskId)
        //    {
        //        var config = await robotConfigurationService.GetAsync(taskId);

        //        //изменение статуса робота
        //        robotConfigurationService.ChangeRobotStatus(RobotStatusEnum.InProgress, config!);

        //        if (!await robotConfigurationService.CommitAsync())
        //            return false;

        //        //записываем в лог робота
        //        var history = new RobotHistory
        //        {
        //            Id = Guid.NewGuid(),
        //            HistoryLevel = (int)RobotHistoryLevelEnum.Start,
        //            TaskStatusCode = config.TaskStatusCode,
        //            RobotConfigurationId = config.Id,
        //            RobotIp = clientService.GetClientIp()?.ToString()
        //        };

        //        if (!await robotHistoryService.CreateAsync(history) || !await robotHistoryService.CommitAsync())
        //            return false;

        //        return true;
        //    }


        //    /// <summary>
        //    /// Приводит переносы строк в тексте к формату CRLF (\r\n)
        //    /// </summary>
        //    /// <param name="text">Исходный текст</param>
        //    /// <returns>Текст с унифицированными переносами строк</returns>
        //    private string NormalizeLineEndingsToCrlf(string? text)
        //    {
        //        if (string.IsNullOrEmpty(text))
        //            return string.Empty;

        //        // Заменяем любые варианты переносов (\r\n, \r, \n) на единый \r\n
        //        return System.Text.RegularExpressions.Regex.Replace(text, @"\r\n|\r|\n", "\r\n");
        //    }

        #endregion
    }
}
