using FluentValidation;
using Microsoft.EntityFrameworkCore;
using PARR.API.Contracts.V1.Requests;
using PARR.Core.Repositories.Interfaces;
using PARR.Core.Repositories.Interfaces.JobGroupRepositories;
using PARR.Core.Repositories.Interfaces.Unit;

namespace PARR.API.Validators
{
    public class JobRequestValidator : AbstractValidator<JobRequest>
    {
        private readonly ITnkRepository _tnkRepository;
        private readonly IJobGroupRepository _jobGroupRepository;
        private readonly IUnitFieldRepository _unitFieldRepository;
        //private JobGroup? jobGroup;

        public JobRequestValidator(
            ITnkRepository tnkRepository,
            IJobGroupRepository jobGroupRepository,
            IUnitFieldRepository unitFieldRepository
            )
        {
            _tnkRepository = tnkRepository;
            _jobGroupRepository = jobGroupRepository;
            _unitFieldRepository = unitFieldRepository;

            RuleFor(t => t.Name)
                .NotNull().NotEmpty();

            RuleFor(t => t.WorkName)
                .NotNull().NotEmpty();

            RuleFor(t => t.TnkId)
                .MustAsync(async (entity, value, c) => await IsTnkExist(entity))
                .WithMessage("Указан несуществующий Id ТНК({PropertyValue})");

            RuleFor(t => t.GroupId)
                .MustAsync(async (entity, value, c) => await IsGroupExist(entity))
                .WithMessage("Указан несуществующий Id группы работ({PropertyValue})");

            RuleForEach(t => t.UnitFilters)
                .NotNull().NotEmpty();

            RuleForEach(t => t.UnitFilters)
                .MustAsync(async (entity, value, c) => await IsUnitFiltersCorrect(entity))
                .WithMessage("Неверно заданы параметры фильтров. Внимательнее, пожалуйста!");

            RuleFor(t => t.Relationships)
                .MustAsync(async (entity, value, c) =>
                {
                    // Relationships должны быть обязательно заполнены если в типе работ IsRelationshipsAllowed==true
                    var relationshipsIsRequired = await jobGroupRepository.Get()
                                                            .AnyAsync(t => t.Id == entity.GroupId && t.GroupType!.IsRelationshipsAllowed, c);

                    if (relationshipsIsRequired && value != null)
                        return true;

                    if (!relationshipsIsRequired && value == null)
                        return true;

                    return false;
                })
                .WithMessage("Некорректные настройки кол-ва связей");

            When(t => t.Relationships != null, () =>
            {
                RuleFor(t => t.Relationships!.MinValueRelationships)
                    .GreaterThanOrEqualTo(0);

                RuleFor(t => t.Relationships!.MaxValueRelationships)
                    .GreaterThanOrEqualTo(t => t.Relationships!.MinValueRelationships);
            });


            RuleFor(t => t.ResponseAreaMask)
                .NotNull().NotEmpty();

            RuleFor(t => t.AutoControl)
                .MustAsync(async (entity, value, c) =>
                {
                    // Автоконтроль разрешен только типам работ, у которых выключен IsJobGroupAutoControl
                    var isAllowedJobAutocontrol = await jobGroupRepository.Get()
                                                        .AnyAsync(t => t.Id == entity.GroupId && t.GroupType!.IsJobGroupAutoControl == false, c);

                    // Разрешен автоконтроль и есть значение
                    if (isAllowedJobAutocontrol && value != null)
                        return true;

                    // Запрещен автоконтроль и нет значения
                    if (!isAllowedJobAutocontrol && value == null)
                        return true;

                    return false;
                })
                .WithMessage("Некорректные параметры автоконтроля");
        }

        private async Task<bool> IsUnitFiltersCorrect(JobRequest entity)
        {
            foreach (var unitFilter in entity.UnitFilters)
            {
                if (string.IsNullOrEmpty(unitFilter.UnitFilterMask))
                    return false;

                //if (unitFilter.FieldFilters == null || !unitFilter.FieldFilters.Any())
                //    return false;

                if (unitFilter.FieldFilters != null && unitFilter.FieldFilters.Any())
                    foreach (var fieldFilter in unitFilter.FieldFilters)
                    {
                        var fieldId = fieldFilter.FieldId;
                        if (await _unitFieldRepository.GetAsync(fieldId) == null)
                            return false;
                    }

                if (unitFilter.RelationshipFilters != null && unitFilter.RelationshipFilters.Any())
                    foreach (var relationshipFilter in unitFilter.RelationshipFilters!)
                    {
                        var fieldId = relationshipFilter.FieldId;
                        if (await _unitFieldRepository.GetAsync(fieldId) == null)
                            return false;
                    }
            }

            return true;
        }

        private async Task<bool> IsGroupExist(JobRequest entity)
        {
            var jobGroup = await _jobGroupRepository.GetAsync(entity.GroupId);

            return jobGroup != null;
        }


        private async Task<bool> IsTnkExist(JobRequest entity)
        {
            return await _tnkRepository.GetAsync(entity.TnkId) != null;
        }
    }
}