using CandidateReviewContracts.BindingModels;
using CandidateReviewContracts.BusinessLogicsContracts;
using CandidateReviewContracts.SearchModels;
using CandidateReviewContracts.StoragesContracts;
using CandidateReviewContracts.ViewModels;
using Microsoft.Extensions.Logging;
using System.Xml.Linq;

namespace CandidateReviewBusinessLogic.BusinessLogic
{
    public class ResumeLogic : IResumeLogic
    {
        private readonly ILogger _logger;
        private readonly IResumeStorage _resumeStorage;
        private readonly IVacancyStorage _vacancyStorage;
        private readonly IUserStorage _userStorage;
        private readonly IAssessmentStorage _assessmentStorage;
        public ResumeLogic(ILogger<ResumeLogic> logger, IResumeStorage resumeStorage, IUserStorage userStorage, IVacancyStorage vacancyStorage, IAssessmentStorage assessmentStorage)
        {
            _logger = logger;
            _resumeStorage = resumeStorage;
            _userStorage = userStorage;
            _vacancyStorage = vacancyStorage;
            _assessmentStorage = assessmentStorage;
        }
        public bool Create(ResumeBindingModel model)
        {
            CheckModel(model);
            if (_resumeStorage.Insert(model) == null)
            {
                _logger.LogWarning("Insert operation failed");
                return false;
            }
            return true;
        }

        public bool Delete(ResumeBindingModel model)
        {
            CheckModel(model, false);
            _logger.LogInformation("Delete. Id: {Id}", model.Id);
            if (_resumeStorage.Delete(model) == null)
            {
                _logger.LogWarning("Delete operation failed");
                return false;
            }
            return true;
        }

        public ResumeViewModel? ReadElement(ResumeSearchModel model)
        {
            if (model == null)
            {
                throw new ArgumentNullException(nameof(model));
            }
            var element = _resumeStorage.GetElement(model);
            if (element == null)
            {
                _logger.LogWarning("ReadElement element not found");
                return null;
            }

            var assessments = _assessmentStorage.GetFilteredList(new AssessmentSearchModel { UserId = element.Id });
            var assessmentViewModels = assessments?.Select(a => new AssessmentViewModel
            {
                Id = a.Id,
                ResumeId = a.ResumeId,
                UserName = a.UserName,
                UserId = a.UserId,
                Comment = a.Comment
            }).ToList() ?? new List<AssessmentViewModel>();

            var resumeViewModel = new ResumeViewModel
            {
                Id = element.Id,
                VacancyId = element.VacancyId,
                VacancyName = _vacancyStorage.GetElement(new VacancySearchModel { Id = element.VacancyId }).JobTitle,
                UserId = element.UserId,
                UserName = _userStorage.GetElement(new UserSearchModel { Id = element.UserId }).Name + " " + _userStorage.GetElement(new UserSearchModel { Id = element.UserId }).Surname,
                Title = element.Title,
                Experience = element.Experience,
                Education = element.Education,
                Description = element.Description,
                Skills = element.Skills,
                Status = element.Status,
                CreatedAt = element.CreatedAt,
                Assessments = assessmentViewModels
            };

            _logger.LogInformation("ReadElement find. Id: {Id}", element.Id);
            return resumeViewModel;
        }

        public List<ResumeViewModel>? ReadList(ResumeSearchModel? model)
        {
            var list = model == null ? _resumeStorage.GetFullList() : _resumeStorage.GetFilteredList(model);
            if (list == null)
            {
                _logger.LogWarning("ReadList return null list");
                return null;
            }
            List<ResumeViewModel> result = new();
            foreach (var element in list)
            {
                var assessments = _assessmentStorage.GetFilteredList(new AssessmentSearchModel { UserId = element.Id });
                var assessmentViewModels = assessments?.Select(a => new AssessmentViewModel
                {
                    Id = a.Id,
                    ResumeId = a.ResumeId,
                    UserId = a.UserId,
                    UserName = a.UserName,
                    Comment = a.Comment
                }).ToList() ?? new List<AssessmentViewModel>();

                var resumeViewModel = new ResumeViewModel
                {
                    Id = element.Id,
                    VacancyId = element.VacancyId,
                    VacancyName = _vacancyStorage.GetElement(new VacancySearchModel { Id = element.VacancyId }).JobTitle,
                    UserId = element.UserId,
                    UserName = _userStorage.GetElement(new UserSearchModel { Id = element.UserId }).Name + " " + _userStorage.GetElement(new UserSearchModel { Id = element.UserId }).Surname,
                    Title = element.Title,
                    Experience = element.Experience,
                    Education = element.Education,
                    Description = element.Description,
                    Skills = element.Skills,
                    Status = element.Status,
                    CreatedAt = element.CreatedAt,
                    Assessments = assessmentViewModels
                };
                result.Add(resumeViewModel);
            }
            _logger.LogInformation("ReadList. Count: {Count}", list.Count);
            return result;
        }

        public bool Update(ResumeBindingModel model)
        {
            CheckModel(model);
            if (_resumeStorage.Update(model) == null)
            {
                _logger.LogWarning("Update operation failed");
                return false;
            }
            return true;
        }

        private void CheckModel(ResumeBindingModel model, bool withParams = true)
        {
            if (model == null)
            {
                throw new ArgumentNullException(nameof(model));
            }

            if (!withParams)
            {
                return;
            }

            if (model.VacancyId <= 0)
            {
                throw new ArgumentException("Нет идентификатора вакансии", nameof(model.VacancyId));
            }

            if (model.UserId <= 0)
            {
                throw new ArgumentException("Нет идентификатора пользователя", nameof(model.UserId));
            }

            if (string.IsNullOrEmpty(model.Title))
            {
                throw new ArgumentNullException("Нет названия резюме", nameof(model.Title));
            }

            if (string.IsNullOrEmpty(model.Experience))
            {
                throw new ArgumentNullException("Нет опыта работы в резюме", nameof(model.Experience));
            }

            if (string.IsNullOrEmpty(model.Education))
            {
                throw new ArgumentNullException("Нет образования в резюме", nameof(model.Education));
            }

            if (string.IsNullOrEmpty(model.Skills))
            {
                throw new ArgumentNullException("Нет навыков в резюме", nameof(model.Skills));
            }

            if (string.IsNullOrEmpty(model.Status.ToString()))
            {
                throw new ArgumentNullException("Нет статуса резюме", nameof(model.Status));
            }

            var element = _resumeStorage.GetElement(new ResumeSearchModel
            {
                VacancyId = model.VacancyId,
                UserId = model.UserId,
                Title = model.Title
            });

            if (element != null && element.Id != model.Id)
            {
                throw new InvalidOperationException("Такое резюме уже существует");
            }
        }
    }
}
