using BukiVedi.Shared.Entities;
using BukiVedi.Shared.Models;
using BukiVedi.Shared.Services;
using BukiVedi.Shared.Services.Mappers;

namespace BukiVedi.Shared.Apps
{
    public class TagsHandler
        : ITagsHandler
    {
        private readonly ILibrary _library;
        public TagsHandler(ILibrary library)
        {
            if (library == null) throw new ArgumentNullException(nameof(library));
            _library = library;
        }

        public async Task<TagInfo> AppendTag(string bookId, string name, OperationContext context)
        {
            if (string.IsNullOrWhiteSpace(name) == false && await Tables.Books.ExistById(bookId))
            {
                name = name.Trim().ToLowerInvariant();
                var tagFilter = Filters.Tags.Exact(bookId, context.OperationInitiator.Id, name);                
                var existTag = await Tables.UserTag.Get(tagFilter);
                if (existTag != null && existTag.Length > 0)
                {
                    return new TagInfo { Id = existTag[0].Id, Name = existTag[0].Name };
                }
                else
                {
                    var userTag = await Tables.UserTag.Write(new UserTag { BookId = bookId, Name = name, UserId = context.OperationInitiator.Id });
                    return new TagInfo { Id = userTag.Id, Name = name };
                }
            }
            return null!;
        }

        public async Task<IEnumerable<TagInfo>> GetBookTags(string bookId, OperationContext context)
        {
            var filter = Filters.Tags.ByBook(bookId, context.OperationInitiator.Id);
            return (await Tables.UserTag.Get(filter))?.Select(t => new TagInfo
            {
                Id = t.Id,
                Name = t.Name,
            })!;
        }

        public async Task<IEnumerable<string>> GetUserTags(OperationContext context)
        {
            return (await Tables.UserTag.Get(Filters.Tags.ByUser(context.OperationInitiator.Id)))?.Select(t => t.Name)!;
        }

        public async Task<bool> RemoveTag(string id, OperationContext context)
        {
            if (string.IsNullOrWhiteSpace(id) == false && await Tables.UserTag.ExistById(id))
            {
                return await Tables.UserTag.TryRemoveById(id);
            }
            return false;
        }

        public async Task<IEnumerable<BookInfo>> Search(string id, OperationContext context)
        {
            if (string.IsNullOrWhiteSpace(id) == false)
            {
                var books = await _library.SearchByTagBooks(context.OperationInitiator.Id, id);
                return await BookEntityMapper.Map(books, context);
            }
            return Enumerable.Empty<BookInfo>();
        }
    }
}
