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

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

        public async Task AddAuthorsToFavorite(string id, OperationContext context)
        {
            var book = await Tables.Books.GetById(id);
            if (book != null)
            {
                var account_id = context.OperationInitiator.Id;
                var authors = book.AuthorIds;
                if (!string.IsNullOrEmpty(account_id) && authors?.Count > 0)
                {
                    foreach (var author_id in authors)
                    {
                        if (await Tables.FavoriteAuthors.Exists(Filters.FavoriteAuthors.Exact(author_id, account_id)) == false)
                        {
                            await Tables.FavoriteAuthors.Write(new FavoriteAuthor { AuthorId = author_id, UserId = account_id });
                        }
                    }
                }
            }
        }

        public async Task AddBookToReadingQueue(string id, OperationContext context)
        {
            if (await Tables.Books.ExistById(id))
            {
                var account_id = context.OperationInitiator.Id;
                if (!string.IsNullOrEmpty(account_id))
                {
                    if (await Tables.ReadQueue.Exists(Filters.BooksToRead.Exact(id, account_id)) == false)
                    {
                        await Tables.ReadQueue.Write(new ReadQueueItem { BookId = id, UserId = account_id, Timestamp = Timestamp.UtcNow });
                    }
                }
            }
        }

        public async Task AddToFavorite(string id, OperationContext context)
        {
            if (await Tables.Books.ExistById(id))
            {
                var account_id = context.OperationInitiator.Id;
                if (!string.IsNullOrEmpty(account_id))
                {
                    if (await Tables.FavoriteBooks.Exists(Filters.FavoriteBooks.ByBook(id, account_id)) == false)
                    {
                        await Tables.FavoriteBooks.Write(new FavoriteBook { BookId = id, UserId = account_id });
                    }
                }
            }
        }

        public async Task BlockBook(string id, OperationContext context)
        {
            if (await Tables.Books.ExistById(id))
            {
                var account_id = context.OperationInitiator.Id;
                if (!string.IsNullOrEmpty(account_id))
                {
                    if (await Tables.DisgustingBooks.Exists(Filters.DisgustingBooks.ByBook(id, account_id)) == false)
                    {
                        await Tables.DisgustingBooks.Write(new DisgustingBook { BookId = id, UserId = account_id });
                    }
                }
            }
        }

        public async Task BlockBookAuthor(string id, OperationContext context)
        {
            var book = await Tables.Books.GetById(id);
            if (book != null)
            {
                var account_id = context.OperationInitiator.Id;
                var authors = book.AuthorIds;
                if (!string.IsNullOrEmpty(account_id) && authors?.Count > 0)
                {
                    foreach (var author in authors)
                    {
                        if (await Tables.DisgustingAuthors.Exists(Filters.DisgustingAuthors.ByAuthor(author, account_id)) == false)
                        {
                            await Tables.DisgustingAuthors.Write(new DisgustingAuthor { AuthorId = author, UserId = account_id });
                        }
                    }
                }
            }
        }

        public async Task<(string, MemoryStream)> GetBlobData(string id, OperationContext context)
        {
            var content = new System.IO.MemoryStream();
            var book = await _library.DownloadToStream(content, id);
            string name = id;
            if (book != null && string.IsNullOrWhiteSpace(book.Title) == false)
            {
                name = FSUtils.FileNameCorrection(book.Title);
            }
            content.Position = 0;
            return (name, content);
        }

        public async Task RemoveFromFavorite(string id, OperationContext context)
        {
            var records = await Tables.FavoriteBooks.Get(Filters.FavoriteBooks.ByBook(id, context.OperationInitiator.Id));
            foreach (var record in records)
            {
                await Tables.FavoriteBooks.TryRemoveById(record.Id);
            }
        }

        public async Task RemoveFromReadingQueue(string id, OperationContext context)
        {
            var records = await Tables.ReadQueue.Get(Filters.BooksToRead.Exact(id, context.OperationInitiator.Id));
            foreach (var record in records)
            {
                await Tables.ReadQueue.TryRemoveById(record.Id);
            }
        }

        public async Task<IEnumerable<BookInfo>> Search(string query, string? tag, OperationContext context)
        {
            if (string.IsNullOrWhiteSpace(query) == false)
            {
                switch (query.Trim().ToLowerInvariant())
                {
                    case "@favorites":
                        {
                            var books = (await _library.SearchFavoritesBooks(context.OperationInitiator.Id)).ToArray();
                            return await BookEntityMapper.Map(books, context);
                        }
                    case "@favoriteauthors":
                        {
                            var books = (await _library.SearchFavoriteAuthorsBooks(context.OperationInitiator.Id)).ToArray();
                            return await BookEntityMapper.Map(books, context);
                        }
                    case "@tagged":
                        {
                            var books = (await _library.SearchTaggedBooks(context.OperationInitiator.Id, tag: tag!)).ToArray();
                            return await BookEntityMapper.Map(books, context);
                        }

                    case "@blocked":
                        {
                            var books = (await _library.SearchBlockedBooks(context.OperationInitiator.Id)).ToArray();
                            return await BookEntityMapper.Map(books, context);
                        }

                    case "@toread":
                        {
                            var books = (await _library.SearchToReadBooks(context.OperationInitiator.Id)).ToArray();
                            return await BookEntityMapper.Map(books, context);
                        }

                    default:
                        {
                            var books = (await _library.SearchBooks(query)).ToArray();
                            return await BookEntityMapper.Map(books, context);
                        }
                }
            }
            return Enumerable.Empty<BookInfo>();
        }

        public async Task UnblockBook(string id, OperationContext context)
        {
            var account_id = context.OperationInitiator.Id;
            if (!string.IsNullOrEmpty(account_id))
            {
                var records = await Tables.DisgustingBooks.Get(Filters.DisgustingBooks.ByBook(id, account_id));
                foreach (var record in records)
                {
                    await Tables.DisgustingBooks.TryRemoveById(record.Id);
                }
            }
        }
    }
}
