using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using PARR.API.Contracts.V1;
using PARR.API.Contracts.V1.Requests.BaseRequests;
using PARR.API.Contracts.V1.Responses;
using PARR.API.Contracts.V1.Responses.Base;
using PARR.API.Contracts.V1.Responses.Statistics;
using PARR.API.Controllers.V1.Base;
using PARR.API.Helpers;
using PARR.Core.Repositories.Interfaces;
using PARR.Core.Services.NextRunServices;
using PARR.Domain.Common.Roles;

namespace PARR.API.Controllers.V1.Statistics
{
    /// <summary>
    /// Статистика по нарядам
    /// </summary>
    [Authorize(Roles = ParrRoles.Administrator.Role)]
    public class StatOrderController : BaseApiController
    {
        private readonly IOrderRepository orderService;
        private readonly IOrderStatusRepository orderStatusService;
        private readonly IMapper mapper;
        private readonly INextRunService nextRunService;

        public StatOrderController(
            IOrderRepository orderService,
            IOrderStatusRepository orderStatusService,
            IMapper mapper,
            INextRunService nextRunService
            )
        {
            this.orderService = orderService;
            this.orderStatusService = orderStatusService;
            this.mapper = mapper;
            this.nextRunService = nextRunService;
        }

        /// <summary>
        /// Статистика по нарядам - всего в ПАРР / загружено за сегодня
        /// </summary>
        /// <returns></returns>
        [HttpGet(ApiRoutes.StatOrder.Get)]
        public async Task<IActionResult> Get([FromQuery] TimeZoneOffsetClient timeZoneQuery)
        {
            var todayStartUtc = TimeZoneDateHelper.GetUtcSartOfDay(
                DateOnly.FromDateTime(DateTimeOffset.UtcNow.ToOffset(timeZoneQuery.TimeZoneOffset).DateTime),
                timeZoneQuery.TimeZoneOffset
            );

            var response = new StatOrderResponse
            {
                AllCount = await orderService.Get().AsNoTracking().CountAsync(),
                DownloadedLastDayCount = await orderService.Get().AsNoTracking().CountAsync(t => t.DateCreated.UtcDateTime >= todayStartUtc)
            };

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


        /// <summary>
        /// Статистика по нарядам - кол-во заданий на изменение нарядов в ЕСПП
        /// </summary>
        /// <returns></returns>
        [HttpGet(ApiRoutes.StatOrder.TaskToEspp)]
        public async Task<IActionResult> TaskToEspp()
        {
            var response = new StatTaskToEsppResponse
            {
                AllCount = await orderService.Get().AsNoTracking().CountAsync(),
                // такая же логика в PARR.Master
                TaskCount = await orderService.Get().AsNoTracking().CountAsync(t => t.NextStatusCode.HasValue && t.NextStatusCode.Value != t.StatusCode)
            };

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


        /// <summary>
        /// Статистика по нарядам - по статусам в ПАРР
        /// </summary>
        /// <returns></returns>
        [HttpGet(ApiRoutes.StatOrder.Statuses)]
        public async Task<IActionResult> Statuses()
        {
            var statuses = await orderStatusService.Get().AsNoTracking().OrderBy(t => t.Code).ToListAsync();

            var response = new List<StatOrderStatusesResponse>();
            foreach (var stat in statuses)
            {
                response.Add(new StatOrderStatusesResponse
                {
                    Status = mapper.Map<OrderStatusResponse>(stat),
                    Count = await orderService.Get().AsNoTracking().CountAsync(t => t.StatusCode == stat.Code)
                });
            }

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


        /// <summary>
        /// Статистика по нарядам - по статусу за сегодня
        /// </summary>
        /// <param name="statusCode">1,2,3,4,5</param>
        /// <returns></returns>
        [HttpGet(ApiRoutes.StatOrder.GetStatusesLastDay)]
        public async Task<IActionResult> GetStatusesLastDay([FromRoute] int statusCode, [FromQuery] TimeZoneOffsetClient timeZoneQuery)
        {
            var status = await orderStatusService.Get().AsNoTracking().FirstOrDefaultAsync(t => t.Code == statusCode);

            if (status == null)
                return BadRequest(new Response(false, new List<ErrorModel> { new ErrorModel { Message = $"Не найден статус с кодом: {statusCode}" } }));

            var todayStartUtc = TimeZoneDateHelper.GetUtcSartOfDay(
                DateOnly.FromDateTime(DateTimeOffset.UtcNow.ToOffset(timeZoneQuery.TimeZoneOffset).DateTime),
                timeZoneQuery.TimeZoneOffset
            );

            var response = new StatGetStatusesLastDayResponse
            {
                Count = await orderService.Get().CountAsync(t => (t.DateModified.HasValue && t.DateModified.Value >= todayStartUtc) && t.StatusCode == statusCode),
                Status = mapper.Map<OrderStatusResponse>(status)
            };

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


        /// <summary>
        /// Получить статистику добавления новых нарядов за период
        /// </summary>
        /// <param name="timeZoneQuery"></param>
        /// <param name="startPeriodDays"></param>
        /// <returns></returns>
        [HttpGet(ApiRoutes.StatOrder.GetForPeriod)]
        public async Task<IActionResult> GetForPeriod([FromQuery] TimeZoneOffsetClient timeZoneQuery, [FromQuery] int startPeriodDays = 3)
        {
            // Формируем период
            var userEnd = DateOnly.FromDateTime(DateTimeOffset.UtcNow.ToOffset(timeZoneQuery.TimeZoneOffset).DateTime);
            var userStart = userEnd.AddDays(-startPeriodDays);

            var (utcStart, utcEnd) = TimeZoneDateHelper.GetUtcDateRange(
                                                            userStart,
                                                            userEnd.AddDays(1),
                                                            timeZoneQuery.TimeZoneOffset);

            var allRecords = await orderService.Get()
                         .AsNoTracking()
                         .FilterByDateRangeUtc(t => t.DateCreated, utcStart, utcEnd)
                         .Select(t => new { t.Id, t.DateCreated })
                         .ToListAsync(); ;

            var resultDict = allRecords.GroupByUserDate(t => t.DateCreated, timeZoneQuery.TimeZoneOffset);

            var daysList = await nextRunService.GetWorkDaysAsync(userStart, userEnd, false);

            var response = daysList.Select(date => new StatOrderGetForPeriodResponse
            {
                Date = date,
                OrderCount = resultDict.TryGetValue(date, out var cnt) ? cnt : 0
            }).OrderBy(t => t.Date).ToList();

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


    }
}
