using Lada.Framework.Data.Domains;
using Lada.Framework.Data.Domains.Cms;
using Lada.Framework.Data.Repositories;
using Lada.Framework.DTO;
using Lada.Framework.DTO.SmartTable;
using Lada.Framework.Infrastructures.Helpers;
using Ladaer.BackEnd.Infrastructures.AppSettings;
using Ladaer.BackEnd.Infrastructures.DTO;
using Ladaer.BackEnd.Infrastructures.DTO.Items.Cms;
using Ladaer.BackEnd.Infrastructures.DTO.Models.Cms;
using Ladaer.BackEnd.Infrastructures.DTO.Results.Cms;
using Microsoft.AspNetCore.Http.HttpResults;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
using static Microsoft.Extensions.Logging.EventSource.LoggingEventSource;
namespace Ladaer.BackEnd.Infrastructures.Services.Cms
{
    /// <summary>
    /// Giao diện cho dịch vụ quản lý dịch vụ.
    /// </summary>
    public interface IProductService
    {
        /// <summary>
        /// Tìm kiếm dịch vụ
        /// </summary>
        /// <param name="param">Thông số tìm kiếm.</param>
        /// <returns>Kết quả tìm kiếm dịch vụ.</returns>
        Task<SmartTableResult<ProductItem>> Search(SmartTableParam param);

        /// <summary>
        /// Lấy thông tin dịch vụ qua Id
        /// </summary>
        /// <param name="productId">Id của dịch vụ.</param>
        /// <returns>Thông tin dịch vụ.</returns>
        Task<ProductModel> GetById(int productId);
        Task<ProductResult> CreateOrUpdate(ProductModel model);

        /// <summary>
        /// Xóa bài viết
        /// </summary>
        /// <param name="productId">Id của bài viết.</param>
        /// <returns>Kết quả của thao tác.</returns>
        Task<BaseResult> DeleteAsync(int productId);
    }



    public class ProductService : IProductService
    {
        private readonly IRepository<Product> _productRepository;
        private readonly IRepository<ProductTag> _productTagRepository;
        private readonly IRepository<ProductCategory> _productCategoryRepository;
        private readonly IUrlRecordService _urlRecordService;
        private readonly IRepository<UrlRecord> _urlRecordRepository;
        private readonly IProductCategoryService _productCategoryService;
        private CmsSetting _cmsSettings;
        private readonly IRepository<Tag> _tagRepository;
        private readonly ITagService _tagService;
        private readonly IRepository<Category> _categoryRepository;

        public ProductService(IRepository<Product> productRepository, IUrlRecordService urlRecordService, IOptions<CmsSetting> cmsSettings, IRepository<Tag> tagRepository, IRepository<ProductTag> productTagRepository, ITagService tagService, IRepository<UrlRecord> urlRecordRepository, IProductCategoryService productCategoryService, IRepository<Category> categoryRepository, IRepository<ProductCategory> productCategoryRepository)
        {
            _productRepository = productRepository;
            _urlRecordService = urlRecordService;
            _cmsSettings = cmsSettings.Value;
            _tagRepository = tagRepository;
            _productTagRepository = productTagRepository;
            _tagService = tagService;
            _urlRecordRepository = urlRecordRepository;
            _productCategoryService = productCategoryService;
            _categoryRepository = categoryRepository;
            _productCategoryRepository = productCategoryRepository;
        }

        public async Task<SmartTableResult<ProductItem>> Search(SmartTableParam param)
        {
            var query = _productRepository.Query();
            if (param.Search.PredicateObject != null)
            {
                dynamic search = param.Search.PredicateObject;
                if (search.Keyword != null)
                {
                    string keyword = search.Keyword;
                    keyword = keyword.Trim().ToLower();
                    query = query.Where(x => x.Name.ToLower().Contains(keyword));
                }
                if (search.CreatedStart != null && search.CreatedEnd != null)
                {
                    DateTimeOffset start = search.CreatedStart;
                    DateTimeOffset end = search.CreatedEnd;
                    DateTimeOffset startParam = start.ToLocalTime().StartOfDay();
                    DateTimeOffset endParam = end.EndOfDay().ToLocalTime().EndOfDay();
                    query = query.Where(x => x.CreatedTime >= startParam && x.CreatedTime <= endParam);
                }
                if (search.CategoryId != null)
                {
                    int catId = search.CategoryId;
                    if (catId > 0)
                    {
                        query = query.Where(x => x.ProductCategories!.Any(pc=>pc.CategoryId== catId));
                    }
                    
                }
                //CategoryId


            }
            param.Sort = new Sort() { Predicate = "Id", Reverse = true };
            var gridData = await query.Include(p => p.UrlRecord).ToSmartTableResultAsync(param, x => x.ToItem());
            return gridData;
        }


        /// <summary>
        /// Lấy thông tin dịch vụ qua Id
        /// </summary>
        /// <param name="productId">Id của dịch vụ.</param>
        /// <returns>Thông tin dịch vụ.</returns>
        public async Task<ProductModel> GetById(int productId)
        {
            var model = new ProductModel();
            if (productId <= 0) return model;
            var product = await _productRepository.Query().Include(p => p.ProductCategories!).ThenInclude(pc => pc.Category!)
                .Include(p => p.ProductTags!).ThenInclude(pt=>pt.Tag)
                .FirstOrDefaultAsync(c => c.Id == productId);
            if (product != null && product.Id > 0)
            {
                model = product.ToModel();
            }
            return model;
        }

        #region CreateOrUpdate
        /// <summary>
        /// Tạo hoặc cập nhật dịch vụ
        /// </summary>
        /// <param name="model">Thông tin dịch vụ.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<ProductResult> CreateOrUpdate(ProductModel model)
        {
            var product = model.ToEntity();
            // Cập nhật thông tin chung của thực thể
            product = product.UpdateCommonInt(model.UpdatedBy, model.UpdatedByUserName);

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

        /// <summary>
        /// Cập nhật dịch vụ
        /// </summary>
        /// <param name="product">Thông tin dịch vụ.</param>
        /// <returns>Kết quả của thao tác.</returns>
        private async Task<ProductResult> Update(ProductModel model)
        {
            var result = new ProductResult() { Result = Result.Success };
            var productForUpdate = await _productRepository.Query().Include(p=>p.UrlRecord)
                .FirstOrDefaultAsync(c => c.Id == model.Id);
            var currentTime = DateTimeHelper.CurrentTime();
            if (productForUpdate == null || model.Id <= 0)
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy dịch vụ yêu cầu!";
                return result;
            }

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


                // Cập nhật thông tin của dịch vụ
                productForUpdate.Name = model.Name.Trim();
                productForUpdate.Description = model.Description.Trim();
                productForUpdate.ShortDescription = model.ShortDescription;
                productForUpdate.Thumbnail = model.Thumbnail;
                productForUpdate.IsFeatured = model.IsFeatured;
                productForUpdate.TOC = model.TOC;
                productForUpdate.ProductType = model.ProductType;
                await _tagService.RemoveProductTagByProductIdAsync(productForUpdate.Id);

                #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);
                    }

                    productForUpdate.ProductTags!.Add(new ProductTag { Tag = curTag, Product = productForUpdate, CreatedTime = currentTime, UpdatedTime = currentTime, CreatedBy = model.UpdatedBy, UpdatedBy = model.UpdatedBy, CreatedByUserName = model.UpdatedByUserName, UpdatedByUserName = model.UpdatedByUserName });

                }
                #endregion


                await _productCategoryService.RemoveProductCategoryByProductIdAsync(model.Id);
                var catIds = model.ProductCategoryModels.Select(pc => pc.Id).ToList();
                if (catIds.Any())
                {
                    var cats = await _categoryRepository.Query().Where(c => catIds.Contains(c.Id)).ToListAsync();

                    foreach (var cat in cats)
                    {
                        productForUpdate.ProductCategories!.Add(new ProductCategory() { Category = cat, Product = productForUpdate, CreatedTime = currentTime, UpdatedTime = currentTime, CreatedBy = model.UpdatedBy, UpdatedBy = model.UpdatedBy, CreatedByUserName = model.UpdatedByUserName, UpdatedByUserName = model.UpdatedByUserName });
                    }
                }
                



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

                await _productRepository.UpdateAsync(productForUpdate);
                result.Id = productForUpdate.Id;
            }
            catch (Exception e)
            {
                result.Result = Result.SystemError;
                result.Message = e.ToString();
            }

            return result;
        }

        /// <summary>
        /// Tạo dịch vụ
        /// </summary>
        /// <param name="product">Thông tin dịch vụ.</param>
        /// <returns>Kết quả của thao tác.</returns>
        private async Task<ProductResult> Create(ProductModel model)
        {
            var result = new ProductResult();
            var currentTime = DateTimeHelper.CurrentTime();
            try
            {
                

                #region General
                var product = model.ToEntity().UpdateCommonInt(model.UpdatedBy, model.UpdatedByUserName);

                #region URL Record
                var slug = model.Name.NormalizeUrl();
                slug = await _urlRecordService.GenerateUrlRecord(slug, UrlEntityType.Product);
                product.UrlRecord = new UrlRecord()
                {
                    MetaTitle = product.Name.CutWordByLength(_cmsSettings.SeoSetting.MetaTitleLength),
                    MetaDescription = product.ShortDescription.CutWordByLength(_cmsSettings.SeoSetting.MetaDescriptionLength),
                    MetaKeywords = "",
                    Slug = slug,
                    CreatedBy = product.CreatedBy,
                    CreatedByUserName = product.CreatedByUserName,
                    UpdatedBy = product.UpdatedBy,
                    UpdatedByUserName = product.UpdatedByUserName,
                    CreatedTime = product.CreatedTime,
                    UpdatedTime = product.UpdatedTime,
                    EntityName = "Product",
                    EntityDescription = ""
                }; 
                #endregion

                await _productRepository.InsertAsync(product); 
                #endregion

                #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>();
                var productTags = new List<ProductTag>();
                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);
                    }

                    productTags.Add(new ProductTag { TagId = curTag.Id, ProductId=product.Id, CreatedTime = currentTime, UpdatedTime = currentTime, CreatedBy = model.UpdatedBy, UpdatedBy = model.UpdatedBy, CreatedByUserName = model.UpdatedByUserName, UpdatedByUserName = model.UpdatedByUserName });

                }
                if (productTags.Any())
                {
                    await _productTagRepository.InsertAsync(productTags);
                }
                #endregion


                #region Category
                var catIds = model.ProductCategoryModels.Select(pc => pc.Id).ToList();
                var cats = await _categoryRepository.Query().Where(c => catIds.Contains(c.Id)).ToListAsync();

                var productCats = new List<ProductCategory>();
                foreach (var cat in cats)
                {
                    productCats.Add(new ProductCategory() { CategoryId = cat.Id, ProductId = product.Id, CreatedTime = currentTime, UpdatedTime = currentTime, CreatedBy = model.UpdatedBy, UpdatedBy = model.UpdatedBy, CreatedByUserName = model.UpdatedByUserName, UpdatedByUserName = model.UpdatedByUserName });
                }
                if (productCats.Any())
                {
                    await _productCategoryRepository.InsertAsync(productCats);
                }
                #endregion


                result.Id = product.Id;
            }
            catch (Exception e)
            {
                result.Result = Result.SystemError;
                result.Message = e.ToString();
                result.Id = 0;
            }
            return result;
        }
        #endregion


        /// <summary>
        /// Cập nhật thẻ dịch vụ
        /// </summary>
        /// <param name="productTags">Danh sách thẻ dịch vụ.</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>> UpdateProductTags(List<ProductTagModel> productTags, int createdBy, string createdByUserName)
        {
            var result = new List<Tag>();
            var tagNames = productTags.Select(t => t.Name).ToList();
            var existTags = await _tagRepository.Query().Where(t => tagNames.Contains(t.Name)).ToListAsync();
            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;
        }


        /// <summary>
        /// Xóa bài viết
        /// </summary>
        /// <param name="productId">Id của bài viết.</param>
        /// <returns>Kết quả của thao tác.</returns>
        public async Task<BaseResult> DeleteAsync(int productId)
        {
            var result = new BaseResult();
            if (productId <= 0) return result;
            var post = await _productRepository.Query().FirstOrDefaultAsync(c => c.Id == productId);

            if (post != null && post.Id > 0)
            {
                var deleteResult = await _productRepository.DeleteAsync(post);
                if (deleteResult <= 0)
                {
                    result.Result = Result.SystemError;
                    result.Message = "Không thể xóa được";
                }

                var urlRecord = await _urlRecordRepository.Query().FirstOrDefaultAsync(u => u.ProductId == productId);
                if (urlRecord != null && urlRecord.Id > 0)
                {
                    var deleteUrlResult = await _urlRecordRepository.DeleteAsync(urlRecord);
                    if (deleteUrlResult <= 0)
                    {
                        result.Result = Result.SystemError;
                        result.Message = "Không thể xóa urlrecord";
                    }
                }
            }
            else
            {
                result.Result = Result.Failed;
                result.Message = "Không tìm thấy bài viết yêu cầu";
            }
            return result;
        }
    }
}
