using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Npgsql;
using PARR.Common.Domain;
using PARR.Constants;
using PARR.DAL.Context;
using PARR.DAL.Contracts;
using PARR.DAL.Models;
using PARR.DAL.Services.Abstracts;
using PARR.DAL.Services.Interfaces;

namespace PARR.DAL.Services.Implementations
{
    internal class TemplateService : BaseService<Template>, ITemplateService
    {
        private readonly DataContext dataContext;
        private readonly ILogger<TemplateService> logger;

        protected override DbSet<Template> EntitySet => dataContext.Templates;

        protected override DataContext EntitiContext => dataContext;

        public TemplateService(DataContext dataContext, ILogger<TemplateService> logger) : base(logger)
        {
            this.dataContext = dataContext;
            this.logger = logger;
        }

        public async Task<Template?> GetTemplateByNameAsync(string name)
        {
            return await GetWithIncludes()
                .Include(t => t.RobotConfigurations)
                .FirstOrDefaultAsync(t => t.Name == name);
        }

        public IQueryable<Template> GetWithIncludes()
        {
            return Get()
                .Include(h => h.Unit)
                    .ThenInclude(t => t!.UnitValues)
                    .ThenInclude(t => t.Value)
                .Include(h => h.Unit)
                    .ThenInclude(t => t!.UnitValues)
                    .ThenInclude(t => t.Field)
                .Include(a => a.Job)
                    .ThenInclude(t => t!.Tnk)
                    .ThenInclude(s => s!.Subprocess)
                    .ThenInclude(p => p!.Process)
                .Include(t => t.Job)
                    .ThenInclude(t => t!.Group)
                        .ThenInclude(t => t!.GroupType);
        }

        public override Task<bool> CreateAsync(Template obj)
        {
            // добавление роботов для шаблона
            obj.RobotConfigurations = new List<RobotConfiguration>
            {
                // робот по управлению шаблоном
                new RobotConfiguration
                {
                    Id = Guid.NewGuid(),
                    DateCreated = DateTimeOffset.UtcNow,
                    TemplateId = obj.Id,
                    RobotCode = (int)RobotsEnum.TemplateOrder,
                    TaskStatusCode = (int)TaskStatusEnum.Creating,
                    RobotStatusCode = (int)RobotStatusEnum.Wait,
                    AttemptsNumber = 0,
                    LastRobotStatusUpdated = null
                },
                // робот по управлениею расписанием
                new RobotConfiguration
                {
                    Id = Guid.NewGuid(),
                    DateCreated = DateTimeOffset.UtcNow,
                    TemplateId = obj.Id,
                    RobotCode = (int)RobotsEnum.ScheduleOrder,
                    TaskStatusCode = (int)TaskStatusEnum.Creating,
                    RobotStatusCode = (int)RobotStatusEnum.Wait,
                    AttemptsNumber = 0,
                    LastRobotStatusUpdated = null
                }
            };

            return base.CreateAsync(obj);
        }


        public async Task<Guid?> ReserveUnusedTemplateAsync(Guid newUnitId, HistoryInitiator initiator)
        {
            var sql = @"
            UPDATE ""Templates"" 
            SET ""StatusTypeId"" = @NewStatus,
                ""DateModified"" = @DateModified,
                ""InitiatorIp"" = @InitiatorIp,
                ""InitiatorParrComponentId"" = @InitiatorComponent,
                ""InitiatorComment"" = @InitiatorComment
            WHERE ""Id"" = (
                SELECT ""Id"" 
                FROM ""Templates"" 
                WHERE ""StatusTypeId"" = @OldStatus 
                  AND ""UnitId"" != @NewUnitId
                ORDER BY ""DateCreated"" ASC
                LIMIT 1
            )
            RETURNING ""Id"";";

            var parameters = new[]
            {
            new NpgsqlParameter("@NewStatus", (int)TemplateStatusTypeEnum.Updating),
            new NpgsqlParameter("@DateModified", DateTimeOffset.UtcNow),
            new NpgsqlParameter("@InitiatorIp", initiator.InitiatorIp ?? (object)DBNull.Value),
            new NpgsqlParameter("@InitiatorComponent",
                initiator.InitiatorParrComponentId.HasValue
                    ? (object)(int)initiator.InitiatorParrComponentId.Value
                    : DBNull.Value),
            new NpgsqlParameter("@InitiatorComment", initiator.InitiatorComment ?? (object)DBNull.Value),
            new NpgsqlParameter("@OldStatus", (int)TemplateStatusTypeEnum.Unused),
            new NpgsqlParameter("@NewUnitId", newUnitId)
        };

            var result = await dataContext.Database
                .SqlQueryRaw<Guid>(sql, parameters)
                .ToListAsync();

            return result.FirstOrDefault();
        }
    }
}
