using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using GxPress.Common.AppOptions;
using GxPress.Common.Page;
using GxPress.Common.Tools;
using GxPress.Entity;
using GxPress.Entity.Article;
using GxPress.Repository.Interface;
using GxPress.Request.Admin.Article;
using GxPress.Request.Article;
using GxPress.Result.Article;
using Microsoft.Extensions.Options;
using Datory;

namespace GxPress.Repository.Implement
{
    public class ArticleRepository : IArticleRepository
    {
        private readonly Repository<Article> _repository;
        private readonly Repository<Comment> _commentRepository;
        private readonly Repository<ArticleGroup> _articleGroupRepository;
        private readonly Repository<Entity.Analyze.Analyze> _analyzeRepository;
        private readonly IMapper _mapper;

        public ArticleRepository(IOptionsMonitor<DatabaseOptions> dbOptionsAccessor, IMapper mapper)
        {
            var databaseType = StringUtils.ToEnum<DatabaseType>(dbOptionsAccessor.CurrentValue.DatabaseType, DatabaseType.MySql);
            var database = new Database(databaseType, dbOptionsAccessor.CurrentValue.ConnectionString);
            _repository = new Repository<Article>(database);
            _commentRepository = new Repository<Comment>(database);
            _articleGroupRepository = new Repository<ArticleGroup>(database);
            _analyzeRepository = new Repository<Entity.Analyze.Analyze>(database);
            _mapper = mapper;
        }

        public IDatabase Database => _repository.Database;
        public string TableName => _repository.TableName;
        public List<TableColumn> TableColumns => _repository.TableColumns;

        public async Task<bool> ExistsAsync(int id)
        {
            return await _repository.ExistsAsync(id);
        }

        public async Task<int> InsertAsync(Article process)
        {
            return await _repository.InsertAsync(process);
        }

        public async Task<PagedList<ArticleResult>> GetUserListAsync(ArticleSearchRequest request, IEnumerable<BlacklistArticle> blacklistArticles)
        {
            var pagedList = new PagedList<ArticleResult>();

            var query = Q.NewQuery();
            if (!string.IsNullOrEmpty(request.Keyword))
            {
                var like = $"%{request.Keyword}%";
                query.WhereLike(nameof(Article.Title), like)
                    .OrWhereLike(nameof(Article.Author), like)
                    .OrWhereLike(nameof(Article.Source), like);
            }

            if (request.GroupId > 0)
                query.Where(nameof(Article.GroupId), request.GroupId);
            //屏蔽文章
            foreach (var item in blacklistArticles)
            {
                if (item.BlacklistType == 1)
                {
                    query.WhereNot(nameof(Article.Author), item.BlacklistValue);
                }
                if (item.BlacklistType == 2)
                {
                    query.WhereNot(nameof(Article.Id), item.BlacklistValue);
                }
            }
            pagedList.Total = await _repository.CountAsync(query);

            query.ForPage(request.Page, request.PerPage);
            var list = await _repository.GetAllAsync(query.OrderByDesc(nameof(Article.IsTop), nameof(Article.Sort), nameof(Article.LastModifiedDate), nameof(Article.Id)));
            pagedList.Items = list.Select(article =>
                new ArticleResult
                {
                    Id = article.Id,
                    Title = article.Title,
                    GroupId = article.GroupId,
                    ImageUrls = StringUtils.StringCollectionToStringList(article.ImageUrls),
                    Summary = article.Summary,
                    Author = article.Author,
                    Source = article.Source,
                    ArticleBlocks = StringUtils.JsonDeserialize<IEnumerable<Block>>(article.Blocks),
                    IsChecked = article.IsChecked,
                    AddDate = article.AddDate,
                    Sort = article.Sort,
                    IsTop = article.IsTop,
                    ReadCount = article.ReadCount,
                    IsBlocks = article.IsBlocks
                }).ToList();
            foreach (var item in pagedList.Items)
            {
                //获取文章的评论数量
                var commentCount = await _commentRepository.CountAsync(Q.Where(nameof(Comment.ArticleId), item.Id).Where(nameof(Comment.TypeValue), 0).Where(nameof(Comment.Pid), 0));
                //获取文章的转发数量
                var retransmissionCunt = await _analyzeRepository.CountAsync(Q.Where(nameof(Entity.Analyze.Analyze.AnalyzeType), 4)
                    .Where(nameof(Entity.Analyze.Analyze.SourceId), item.Id));
                //获取文章的收藏数量
                var collectCount = await _analyzeRepository.CountAsync(Q.Where(nameof(Entity.Analyze.Analyze.AnalyzeType), 3)
                    .Where(nameof(Entity.Analyze.Analyze.SourceId), item.Id));
                //获取文章的点赞数量
                var praiseCount = await _analyzeRepository.CountAsync(Q.Where(nameof(Entity.Analyze.Analyze.AnalyzeType), 1)
                    .Where(nameof(Entity.Analyze.Analyze.SourceId), item.Id));
                item.CommentCount = commentCount;
                item.RetransmissionCount = retransmissionCunt;
                item.CollectCount = collectCount;
                item.PraiseCount = praiseCount;
                item.ReadCount = item.ReadCount;
                //是否转发
                item.IsRetransmission = await _analyzeRepository.CountAsync(
                                                     Q.Where(nameof(Entity.Analyze.Analyze.AnalyzeType), 4).Where(nameof(Entity.Analyze.Analyze.SourceId), item.Id)
                                                         .Where(nameof(Entity.Analyze.Analyze.UserId), request.UserId)) > 0;
                //是否收藏
                item.IsCollect = await _analyzeRepository.CountAsync(
                                                 Q.Where(nameof(Entity.Analyze.Analyze.AnalyzeType), 3).Where(nameof(Entity.Analyze.Analyze.SourceId), item.Id)
                                                     .Where(nameof(Entity.Analyze.Analyze.UserId), request.UserId)) > 0;
                //是否点赞
                item.IsPraise = await _analyzeRepository.CountAsync(
                                           Q.Where(nameof(Entity.Analyze.Analyze.AnalyzeType), 1).Where(nameof(Entity.Analyze.Analyze.SourceId), item.Id)
                                               .Where(nameof(Entity.Analyze.Analyze.UserId), request.UserId)) > 0;
            }
            var pageListItems = pagedList.Items;
            foreach (var item in pageListItems)
            {
                var imageUrls = item.ImageUrls.ToList();
                for (int i = 0; i < imageUrls.Count(); i++)
                {
                    imageUrls[i] = StringUtils.AddDomain(imageUrls[i]);
                }
                item.ImageUrls = imageUrls;

                foreach (var articleBlock in item.ArticleBlocks)
                {
                    if (articleBlock.Data.File != null && !string.IsNullOrEmpty(articleBlock.Data.File.Url))
                        articleBlock.Data.File.Url = StringUtils.AddDomain(articleBlock.Data.File.Url);
                }
            }
            return pagedList;
        }

        public async Task<Article> GetArticleAsync(int id)
        {
            var article = await _repository.GetAsync(id);
            if (article == null)
            {
                return null;
            }

            return article;
        }


        public async Task<Article> GetAsync(int id)
        {
            return await _repository.GetAsync(id);
        }


        public async Task<PagedList<ArticleResult>> GetListAsync(string keyword, PageParameter parameter)
        {
            var pagedList = new PagedList<ArticleResult>();

            var query = Q.NewQuery();
            if (!string.IsNullOrEmpty(keyword))
            {
                var like = $"%{keyword}%";
                query.WhereLike(nameof(Article.Title), like)
                    .OrWhereLike(nameof(Article.Author), like)
                    .OrWhereLike(nameof(Article.Source), like);
            }
            pagedList.Total = await _repository.CountAsync(query);

            query.ForPage(parameter.Page, parameter.PerPage);
            var list = await _repository.GetAllAsync(query.OrderByDesc(nameof(Article.IsTop), nameof(Article.Sort), nameof(Article.Id)));
            pagedList.Items = list.Select(article =>
                new ArticleResult
                {
                    Id = article.Id,
                    Title = article.Title,
                    GroupId = article.GroupId,
                    ImageUrls = StringUtils.StringCollectionToStringList(article.ImageUrls),
                    Summary = article.Summary,
                    Author = article.Author,
                    Source = article.Source,
                    ArticleBlocks = StringUtils.JsonDeserialize<IEnumerable<Block>>(article.Blocks),
                    IsChecked = article.IsChecked,
                    AddDate = article.AddDate,
                    Sort = article.Sort,
                    IsTop = article.IsTop,
                    IsBlocks=article.IsBlocks
                });

            return pagedList;
        }



        public async Task<bool> DeleteAsync(int id)
        {
            return await _repository.DeleteAsync(id);
        }
        /// <summary>
        /// 克隆文章
        /// </summary>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task<bool> CloneArticleAsync(CloneArticleRequest request)
        {
            var article = await _repository.GetAsync(request.ArticleId);
            article.Title = request.ArticleTitle;
            return await _repository.InsertAsync(article) > 0;
        }


        public async Task<IEnumerable<Article>> GetAllAsync()
        {
            var query = Q.NewQuery();
            return await _repository.GetAllAsync(query.OrderByDesc(nameof(Article.IsTop), nameof(Article.Sort), nameof(Article.Id)));
        }

        public async Task<bool> UpdateAsync(Article article)
        {
            return await _repository.UpdateAsync(article);
        }

        public async Task<int?> MaxAsync(string sort)
        {
            return await _repository.MaxAsync(sort);
        }
    }
}