using Hangfire.Common;
using Lada.Framework.Data.Domains;
using Lada.Framework.Data.Domains.Categories;
using Lada.Framework.Data.Domains.Cms;
using Lada.Framework.Data.Domains.Hr;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.DTO.SmartTable;
using Lada.Framework.Infrastructures;
using Lada.Framework.Infrastructures.Helpers;
using Ladaer.BackEnd.Infrastructures.DTO;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Categories;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Hr;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Categories;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Cms;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Hr;
using Ladaer.BackEnd.Infrastructures.DTO.Results.Hr;
using Ladaer.BackEnd.Infrastructures.Services.Cms;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;

namespace Ladaer.BackEnd.Infrastructures.Services.Hr
{
    /// <summary>
    /// Giao diện cho dịch vụ quản lý bài đăng tuyển dụng.
    /// </summary>
    public interface IJobPostService
    {
        /// <summary>
        /// Tìm kiếm công việc.
        /// </summary>
        /// <param name="param">Thông số tìm kiếm.</param>
        /// <returns>Kết quả tìm kiếm công việc.</returns>
        Task<SmartTableResult<JobPostItem>> Search(SmartTableParam param);

        /// <summary>
        /// Tạo hoặc cập nhật công việc.
        /// </summary>
        /// <param name="model">Thông tin công việc.</param>
        /// <returns>Kết quả của thao tác.</returns>
        Task<JobPostResult> CreateOrUpdate(JobPostModel model);

        /// <summary>
        /// Lấy thông tin công việc theo ID.
        /// </summary>
        /// <param name="id">ID của công việc.</param>
        /// <returns>Thông tin công việc.</returns>
        Task<JobPostModel> GetById(int id);

        /// <summary>
        /// Xóa công việc theo ID.
        /// </summary>
        /// <param name="id">ID của công việc.</param>
        /// <param name="currentUser">Thông tin người dùng hiện tại.</param>
        /// <returns>Kết quả của thao tác.</returns>
        Task<BaseResult> Delete(int id, CurrentUser currentUser);

        /// <summary>
        /// Cập nhật trạng thái công việc.
        /// </summary>
        /// <param name="model">Thông tin trạng thái công việc.</param>
        /// <param name="newStatus">Trạng thái mới của công việc.</param>
        /// <returns>Kết quả của thao tác.</returns>
        Task<BaseResult> UpdateStatus(JobStatusModel model, JobStatus newStatus);
    }


    /// <summary>
    /// Triển khai dịch vụ quản lý bài đăng tuyển dụng.
    /// </summary>
    public class JobPostService : IJobPostService
    {
        private readonly IRepository<JobPost> _jobPostRepository;
        private readonly IRepository<Tag> _tagRepository;
        private readonly IRepository<Agency> _agencyRepository;
        private readonly IRepository<UrlRecord> _urlRecordRepository;
        private readonly IUrlRecordService _urlRecordService;
        private readonly ITagService _tagService;

        /// <summary>
        /// Khởi tạo một thể hiện của <see cref="JobPostService"/>.
        /// </summary>
        /// <param name="jobPostRepository">Đối tượng IRepository của JobPost.</param>
        /// <param name="agencyRepository">Đối tượng IRepository của Agency.</param>
        /// <param name="urlRecordRepository">Đối tượng IRepository của UrlRecord.</param>
        /// <param name="urlRecordService">Đối tượng IUrlRecordService.</param>
        public JobPostService(IRepository<JobPost> jobPostRepository, IRepository<Agency> agencyRepository,
            IRepository<UrlRecord> urlRecordRepository, IUrlRecordService urlRecordService, IRepository<Tag> tagRepository, ITagService tagService)
        {
            _jobPostRepository = jobPostRepository;
            _agencyRepository = agencyRepository;
            _urlRecordRepository = urlRecordRepository;
            _urlRecordService = urlRecordService;
            _tagRepository = tagRepository;
            _tagService = tagService;
        }

        /// <summary>
        /// Tạo hoặc cập nhật công việc.
        /// </summary>
        /// <param name="model">Thông tin công việc.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<JobPostResult> CreateOrUpdate(JobPostModel model)
        {
            //var jobPost = model.ToEntity();

            // Cập nhật thông tin chung của thực thể
            //jobPost = jobPost.UpdateCommonInt(model.UpdatedBy, model.UpdatedByUserName);

            //if (model.Tags.Any())
            //{
            //    jobPost.Tags = await UpdateJobPostTags(model.Tags, model.UpdatedBy, model.UpdatedByUserName);
            //}
            //else
            //{
            //    jobPost.Tags = new List<Tag>();
            //}


            if (model.Id > 0)
            {
                // Cập nhật
                return await Update(model);
            }
            else
            {
                // Thêm mới
                return await Create(model);
            }
        }

        /// <summary>
        /// Tạo mới công việc.
        /// </summary>
        /// <param name="jobPost">Thông tin công việc.</param>
        /// <returns>Kết quả của thao tác.</returns>
        private async Task<JobPostResult> Create(JobPostModel model)
        {
            var result = new JobPostResult();
            var currentTime = DateTimeHelper.CurrentTime();
            try
            {

                var slug = model.Title.NormalizeUrl();
                slug = await _urlRecordService.GenerateUrlRecord(slug, UrlEntityType.JobPost);

                var jobPost = model.ToEntity().UpdateCommonInt(model.UpdatedBy, model.UpdatedByUserName);
                jobPost.JobPostTags = new List<JobPostTag>();

                #region Tags
                var tagNames = model.Tags.Select(t => t.Name.ToLower()).Distinct().ToList();
                var existTags = await _tagRepository.Query().Where(t => tagNames.Contains(t.Name.ToLower())).ToListAsync();
                var addTagNames = new List<string>();
                var addedTags = new List<Tag>();
                foreach (var tagName in tagNames.Distinct(StringComparer.OrdinalIgnoreCase))
                {
                    var curTag = existTags.FirstOrDefault(t => t.Name.ToLower() == tagName);
                    if (curTag == null || curTag.Id <= 0)
                    {
                        curTag = await _tagService.CreateAsync(tagName, model.UpdatedBy, model.UpdatedByUserName);
                    }

                    jobPost.JobPostTags.Add(new JobPostTag { TagId = curTag.Id, CreatedTime = currentTime, UpdatedTime = currentTime, CreatedBy = model.UpdatedBy, UpdatedBy = model.UpdatedBy, CreatedByUserName = model.UpdatedByUserName, UpdatedByUserName = model.UpdatedByUserName });

                }
                #endregion

                jobPost.UrlRecord = new UrlRecord()
                {
                    MetaTitle = jobPost.Title,
                    MetaDescription = jobPost.Title,
                    MetaKeywords = "",
                    Slug = slug,
                    CreatedBy = jobPost.CreatedBy,
                    CreatedByUserName = jobPost.CreatedByUserName,
                    UpdatedBy = jobPost.UpdatedBy,
                    UpdatedByUserName = jobPost.UpdatedByUserName,
                    CreatedTime = jobPost.CreatedTime,
                    UpdatedTime = jobPost.UpdatedTime,
                    JobPostId = jobPost.Id,
                    EntityName = "JobPost",
                    EntityDescription = ""
                };
                await _jobPostRepository.InsertAsync(jobPost);
                result.Id = jobPost.Id;
            }
            catch (Exception e)
            {
                result.Result = Result.SystemError;
                result.Message = e.ToString();
                result.Id = 0;
            }
            return result;
        }

        /// <summary>
        /// Cập nhật công việc.
        /// </summary>
        /// <param name="jobPost">Thông tin công việc.</param>
        /// <returns>Kết quả của thao tác.</returns>
        private async Task<JobPostResult> Update(JobPostModel model)
        {
            var result = new JobPostResult() { Result = Result.Success };
            var currentTime = DateTimeHelper.CurrentTime();
            var jobPostForUpdate = await _jobPostRepository.Query().Include(jp => jp.UrlRecord).FirstOrDefaultAsync(c => c.Id == model.Id);
            if (jobPostForUpdate == null || model.Id <= 0)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy hồ sơ yêu cầu!";
                return result;
            }

            try
            {
                #region URLRecord
                var urlRecordId = (jobPostForUpdate.UrlRecord != null && jobPostForUpdate.UrlRecord.Id > 0) ? jobPostForUpdate.UrlRecord.Id : 0;
                var slug = model.Title.NormalizeUrl();
                slug = await _urlRecordService.GenerateUrlRecord(slug, UrlEntityType.JobPost, urlRecordId);
                if (urlRecordId > 0)
                {
                    if (jobPostForUpdate.UrlRecord.Slug != slug)
                    {
                        jobPostForUpdate.UrlRecord.Slug = slug;
                    }
                }
                else
                {
                    //Nếu không có thì tạo
                    jobPostForUpdate.UrlRecord = new UrlRecord()
                    {
                        MetaTitle = model.Title,
                        MetaDescription = model.Title,
                        MetaKeywords = "",
                        Slug = slug,
                        CreatedBy = model.UpdatedBy,
                        CreatedByUserName = model.UpdatedByUserName,
                        UpdatedBy = model.UpdatedBy,
                        UpdatedByUserName = model.UpdatedByUserName,
                        CreatedTime = currentTime,
                        UpdatedTime = currentTime,
                        EntityName = "JobPost",
                        EntityDescription = ""
                    };
                }
                #endregion


                jobPostForUpdate.Title = model.Title;
                jobPostForUpdate.Description = model.Description;
                jobPostForUpdate.Department = model.Department;
                jobPostForUpdate.Email = model.Email;
                jobPostForUpdate.StartDate = model.StartDate.ToLocalTime();
                jobPostForUpdate.EndDate = model.EndDate.ToLocalTime();
                jobPostForUpdate.JobType = model.JobType;
                jobPostForUpdate.Position = model.Position;
                jobPostForUpdate.Thumbnail = model.Thumbnail;
                jobPostForUpdate.WorkingAddress = model.WorkingAddress;
                jobPostForUpdate.MinSalary = model.MinSalary;
                jobPostForUpdate.MaxSalary = model.MaxSalary;

                #region Tags
                await _tagService.RemoveJobPostTagByJobPostIdAsync(jobPostForUpdate.Id);

                var tagNames = model.Tags.Select(t => t.Name.ToLower()).Distinct().ToList();
                var existTags = await _tagRepository.Query().Where(t => tagNames.Contains(t.Name.ToLower())).ToListAsync();
                var addTagNames = new List<string>();
                var addedTags = new List<Tag>();
                foreach (var tagName in tagNames.Distinct(StringComparer.OrdinalIgnoreCase))
                {
                    var curTag = existTags.FirstOrDefault(t => t.Name.ToLower() == tagName);
                    if (curTag == null || curTag.Id <= 0)
                    {
                        curTag = await _tagService.CreateAsync(tagName, model.UpdatedBy, model.UpdatedByUserName);
                    }

                    jobPostForUpdate.JobPostTags!.Add(new JobPostTag { Tag = curTag, JobPost = jobPostForUpdate, CreatedTime = currentTime, UpdatedTime = currentTime, CreatedBy = model.UpdatedBy, UpdatedBy = model.UpdatedBy, CreatedByUserName = model.UpdatedByUserName, UpdatedByUserName = model.UpdatedByUserName });

                }
                #endregion


                // Cập nhật thông tin chung của thực thể
                jobPostForUpdate = jobPostForUpdate.UpdateCommonInt();
                await _jobPostRepository.UpdateAsync(jobPostForUpdate);
                result.Id = jobPostForUpdate.Id;
            }
            catch (Exception e)
            {
                result.Result = Result.SystemError;
                result.Message = e.ToString();
            }

            return result;
        }

        /// <summary>
        /// Xóa công việc theo ID.
        /// </summary>
        /// <param name="id">ID của công việc.</param>
        /// <param name="currentUser">Thông tin người dùng hiện tại.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<BaseResult> Delete(int id, CurrentUser currentUser)
        {
            var result = new BaseResult();
            if (id <= 0)
            {
                result.Result = Result.Failed;
                result.Message = "Yêu cầu xóa công việc không hợp lệ";
                return result;
            }
            var jobPostForUpdate = await _jobPostRepository.Query().FirstOrDefaultAsync(c => c.Id == id);
            if (jobPostForUpdate == null || jobPostForUpdate.Id <= 0)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy công việc yêu cầu";
                return result;
            }
            try
            {
                // Cập nhật thông tin chung của thực thể
                jobPostForUpdate = jobPostForUpdate.UpdateCommonInt();
                var delResult = await _jobPostRepository.DeleteAsync(jobPostForUpdate);
                if (delResult <= 0)
                {
                    result.Result = Result.SystemError;
                    result.Message = "Hệ thống không thể thực hiện yêu cầu lúc này, vui lòng thử lại sau!";
                    return result;
                }
            }
            catch (Exception e)
            {
                result.Result = Result.SystemError;
                result.Message = e.ToString();
            }
            return result;
        }

        /// <summary>
        /// Lấy thông tin công việc theo ID.
        /// </summary>
        /// <param name="jobPostId">ID của công việc.</param>
        /// <returns>Thông tin công việc.</returns>
        public async Task<JobPostModel> GetById(int jobPostId)
        {
            var result = new JobPostModel();
            if (jobPostId <= 0)
            {
                return result;
            }
            var jobPostForUpdate = await _jobPostRepository.Query()
                .Include(p => p.JobPostTags!).ThenInclude(jt => jt.Tag!)
                .FirstOrDefaultAsync(c => c.Id == jobPostId);
            if (jobPostForUpdate == null || jobPostForUpdate.Id <= 0)
            {
                return result;
            }
            result = jobPostForUpdate.ToModel();
            return result;
        }

        /// <summary>
        /// Tìm kiếm công việc.
        /// </summary>
        /// <param name="param">Thông số tìm kiếm.</param>
        /// <returns>Kết quả tìm kiếm công việc.</returns>
        public async Task<SmartTableResult<JobPostItem>> Search(SmartTableParam param)
        {
            var query = _jobPostRepository.Query();
            if (param.Search.PredicateObject != null)
            {
                dynamic search = param.Search.PredicateObject;
                if (search.Keyword != null)
                {
                    string keyword = search.Keyword;
                    keyword = keyword.Trim().ToLower();
                    if (!string.IsNullOrEmpty(keyword))
                    {
                        query = query.Where(x => x.Title.ToLower().Contains(keyword) ||
                                                x.Description.ToLower().Contains(keyword));
                    }
                }
                if (search.CreatedStart != null && search.CreatedEnd != null)
                {
                    DateTimeOffset start = search.CreatedStart;
                    DateTimeOffset end = search.CreatedEnd;
                    DateTimeOffset startParam = start.StartOfDay();
                    DateTimeOffset endParam = end.EndOfDay();
                    query = query.Where(x => x.CreatedTime >= startParam && x.CreatedTime <= endParam);
                }
            }
            param.Sort = new Sort() { Predicate = "Id", Reverse = false };
            var gridData = await query.Include(j => j.UrlRecord).Include(j => j.Candidates).ToSmartTableResultAsync(param, x => x.ToItem());
            return gridData;
        }

        /// <summary>
        /// Cập nhật trạng thái công việc.
        /// </summary>
        /// <param name="model">Thông tin trạng thái công việc.</param>
        /// <param name="newStatus">Trạng thái mới của công việc.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<BaseResult> UpdateStatus(JobStatusModel model, JobStatus newStatus)
        {
            var result = new BaseResult();
            if (model.Id <= 0)
            {
                result.Result = Result.Failed;
                result.Message = "Yêu cầu không hợp lệ";
                return result;
            }
            var jobPostForUpdate = await _jobPostRepository.Query().FirstOrDefaultAsync(c => c.Id == model.Id);
            if (jobPostForUpdate == null || jobPostForUpdate.Id <= 0)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy tin tuyển dụng yêu cầu";
                return result;
            }
            if (newStatus == jobPostForUpdate.JobStatus)
            {
                result.Result = Result.Failed;
                result.Message = "Trạng thái tin đăng đang là: " + newStatus.GetDescription();
                return result;
            }

            try
            {
                jobPostForUpdate.JobStatus = newStatus;
                // Cập nhật thông tin chung của thực thể
                jobPostForUpdate = jobPostForUpdate.UpdateCommonInt(model.UpdatedBy, model.UpdatedByUserName);
                var udpResult = await _jobPostRepository.UpdateAsync(jobPostForUpdate);
                if (udpResult <= 0)
                {
                    result.Result = Result.SystemError;
                    result.Message = "Hệ thống không thể thực hiện yêu cầu lúc này, vui lòng thử lại sau!";
                    return result;
                }
            }
            catch (Exception e)
            {
                result.Result = Result.SystemError;
                result.Message = e.ToString();
            }
            return result;
        }


        /// <summary>
        /// Cập nhật thẻ bài viết
        /// </summary>
        /// <param name="postTags">Danh sách thẻ bài viết.</param>
        /// <param name="createdBy">Người tạo.</param>
        /// <param name="createdByUserName">Tên người tạo.</param>
        /// <returns>Danh sách thẻ đã cập nhật.</returns>
        private async Task<List<Tag>> UpdateJobPostTags(List<JobPostTagModel> postTags, int createdBy, string createdByUserName)
        {
            var result = new List<Tag>();
            var tagNames = postTags.Select(t => t.Name).ToList();
            var existTags = _tagRepository.Query().Where(t => tagNames.Contains(t.Name)).ToList();
            var existTagsName = existTags.Select(t => t.Name).ToList();
            var newTagNames = tagNames.Except(existTagsName).ToList();
            var currentTime = DateTimeHelper.CurrentTime();
            if (newTagNames.Any())
            {
                var newTags = new List<Tag>();
                foreach (var newtagName in newTagNames)
                {
                    var slug = newtagName.NormalizeUrl();
                    slug = await _urlRecordService.GenerateUrlRecord(slug, UrlEntityType.Tag);
                    var tag = new Tag()
                    {
                        Name = newtagName,
                        Description = "",
                        UrlRecord = new UrlRecord()
                        {
                            MetaTitle = newtagName,
                            MetaDescription = newtagName,
                            MetaKeywords = newtagName + "," + newtagName.Unsigned(),
                            Slug = slug,
                            CreatedBy = createdBy,
                            CreatedByUserName = createdByUserName,
                            UpdatedBy = createdBy,
                            UpdatedByUserName = createdByUserName,
                            CreatedTime = currentTime,
                            UpdatedTime = currentTime,
                            EntityName = "Tag",
                            EntityDescription = ""
                        },
                        CreatedBy = createdBy,
                        CreatedByUserName = createdByUserName,
                        UpdatedBy = createdBy,
                        UpdatedByUserName = createdByUserName,
                        CreatedTime = currentTime,
                        UpdatedTime = currentTime,
                    };
                    newTags.Add(tag);
                }
                await _tagRepository.InsertAsync(newTags);
                result = _tagRepository.Query().Where(t => tagNames.Contains(t.Name)).ToList();
            }
            else
            {
                result = existTags;
            }
            return result;
        }
    }
}