using BukiVedi.Shared.Entities;
using MongoDB.Driver;
using System.Net;

namespace BukiVedi.Shared.Services
{
    /// <summary>
    /// Фабрика фильтров
    /// </summary>
    public static class Filters
    {
        /// <summary>
        /// Теги
        /// </summary>
        public static class Tags
        {
            /// <summary>
            /// По пользователю
            /// </summary>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<UserTag> ByUser(string userId) => Builders<UserTag>.Filter.Eq(t => t.UserId, userId);

            /// <summary>
            /// По названию тега
            /// </summary>
            /// <param name="userId">Название тега</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<UserTag> ByName(string name, string userId) =>
                Builders<UserTag>.Filter.And(Builders<UserTag>.Filter.Eq(t => t.UserId, userId), Builders<UserTag>.Filter.Eq(t => t.Name, name));

            /// <summary>
            /// По книге
            /// </summary>
            /// <param name="bookId">Идентификатор книги</param>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<UserTag> ByBook(string bookId, string userId) =>
                Builders<UserTag>.Filter.And(Builders<UserTag>.Filter.Eq(t => t.BookId, bookId), Builders<UserTag>.Filter.Eq(t => t.UserId, userId));

            /// <summary>
            /// По точному совпадению
            /// </summary>
            /// <param name="bookId">Идентификатор книги</param>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <param name="name">Имя тега</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<UserTag> Exact(string bookId, string userId, string name) =>
                Builders<UserTag>.Filter.And(
                    Builders<UserTag>.Filter.Eq(t => t.BookId, bookId),
                    Builders<UserTag>.Filter.Eq(t => t.UserId, userId),
                    Builders<UserTag>.Filter.Eq(t => t.Name, name));

            /// <summary>
            /// По книгам
            /// </summary>
            /// <param name="bookIds">Идентификаторы книг</param>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<UserTag> ByBooks(IEnumerable<string> bookIds, string userId) =>
                Builders<UserTag>.Filter.And(Builders<UserTag>.Filter.In(t => t.BookId, bookIds), Builders<UserTag>.Filter.Eq(t => t.UserId, userId));
        }

        /// <summary>
        /// Избранные книги
        /// </summary>
        public static class FavoriteBooks
        {
            /// <summary>
            /// По пользователю
            /// </summary>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<FavoriteBook> ByUser(string userId) => Builders<FavoriteBook>.Filter.Eq(t => t.UserId, userId);

            /// <summary>
            /// По книге
            /// </summary>
            /// <param name="bookId">Идентификатор книги</param>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<FavoriteBook> ByBook(string bookId, string userId) =>
                Builders<FavoriteBook>.Filter.And(Builders<FavoriteBook>.Filter.Eq(t => t.BookId, bookId), Builders<FavoriteBook>.Filter.Eq(t => t.UserId, userId));

            /// <summary>
            /// По книгам
            /// </summary>
            /// <param name="bookIds">Идентификаторы книг</param>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<FavoriteBook> ByBooks(IEnumerable<string> bookIds, string userId) =>
                Builders<FavoriteBook>.Filter.And(Builders<FavoriteBook>.Filter.In(t => t.BookId, bookIds), Builders<FavoriteBook>.Filter.Eq(t => t.UserId, userId));
        }

        /// <summary>
        /// Избранные авторы
        /// </summary>
        public static class FavoriteAuthors
        {
            /// <summary>
            /// По пользователю
            /// </summary>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<FavoriteAuthor> ByUser(string userId) => Builders<FavoriteAuthor>.Filter.Eq(t => t.UserId, userId);

            /// <summary>
            /// По точному совпадению
            /// </summary>
            /// <param name="authorId">Идентификатор автора</param>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<FavoriteAuthor> Exact(string authorId, string userId) =>
                Builders<FavoriteAuthor>.Filter.And(
                    Builders<FavoriteAuthor>.Filter.Eq(t => t.AuthorId, authorId),
                    Builders<FavoriteAuthor>.Filter.Eq(t => t.UserId, userId));
        }

        /// <summary>
        /// Заблокированные книги
        /// </summary>
        public static class DisgustingBooks
        {
            /// <summary>
            /// По пользователю
            /// </summary>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<DisgustingBook> ByUser(string userId) => Builders<DisgustingBook>.Filter.Eq(t => t.UserId, userId);

            /// <summary>
            /// По книге
            /// </summary>
            /// <param name="bookId">Идентификатор книги</param>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<DisgustingBook> ByBook(string bookId, string userId) =>
                Builders<DisgustingBook>.Filter.And(Builders<DisgustingBook>.Filter.Eq(t => t.BookId, bookId), Builders<DisgustingBook>.Filter.Eq(t => t.UserId, userId));

            /// <summary>
            /// По книгам
            /// </summary>
            /// <param name="bookIds">Идентификаторы книг</param>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<DisgustingBook> ByBooks(IEnumerable<string> bookIds, string userId) =>
                Builders<DisgustingBook>.Filter.And(Builders<DisgustingBook>.Filter.In(t => t.BookId, bookIds), Builders<DisgustingBook>.Filter.Eq(t => t.UserId, userId));
        }

        /// <summary>
        /// Заблокированные авторы
        /// </summary>
        public static class DisgustingAuthors
        {
            /// <summary>
            /// По пользователю
            /// </summary>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<DisgustingAuthor> ByUser(string userId) => Builders<DisgustingAuthor>.Filter.Eq(t => t.UserId, userId);

            /// <summary>
            /// По автору
            /// </summary>
            /// <param name="authorId">Идентификатор автора</param>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<DisgustingAuthor> ByAuthor(string authorId, string userId) =>
                Builders<DisgustingAuthor>.Filter.And(Builders<DisgustingAuthor>.Filter.Eq(t => t.AuthorId, authorId), Builders<DisgustingAuthor>.Filter.Eq(t => t.UserId, userId));

            /// <summary>
            /// По авторам
            /// </summary>
            /// <param name="authorIds">Идентификаторы авторов</param>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<DisgustingAuthor> ByAuthors(IEnumerable<string> authorIds, string userId) =>
                Builders<DisgustingAuthor>.Filter.And(Builders<DisgustingAuthor>.Filter.In(t => t.AuthorId, authorIds), Builders<DisgustingAuthor>.Filter.Eq(t => t.UserId, userId));
        }

        /// <summary>
        /// Книги
        /// </summary>
        public static class Books
        {
            /// <summary>
            /// По идентификаторам книг
            /// </summary>
            /// <param name="userId">Идентификаторы книг</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<Book> ByIds(IEnumerable<string> bookIds) => Builders<Book>.Filter.In(t => t.Id, bookIds);

            /// <summary>
            /// По идентификаторам авторов
            /// </summary>
            /// <param name="authorIds">Идентификаторы авторов</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<Book> ByAuthors(IEnumerable<string> authorIds) => Builders<Book>.Filter.AnyIn(b => b.AuthorIds, authorIds);

            /// <summary>
            /// По идентификатору автора
            /// </summary>
            /// <param name="authorId">Идентификатор автора</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<Book> ByAuthor(string authorId) => Builders<Book>.Filter.AnyEq(b => b.AuthorIds, authorId);

            /// <summary>
            /// По размещению в архиве
            /// </summary>
            /// <param name="archivePath">Путь к акрхиву</param>
            /// <param name="archiveIndex">Индекс в акрхиве</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<Book> ByArchiveLocation(string archivePath, int archiveIndex) => 
                Builders<Book>.Filter.And(Builders<Book>.Filter.Eq(b => b.ArchivePath, archivePath), Builders<Book>.Filter.Eq(b => b.ArchiveIndex, archiveIndex));
        }

        /// <summary>
        /// Книги для чтения
        /// </summary>
        public static class BooksToRead
        {
            /// <summary>
            /// По пользователю
            /// </summary>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<ReadQueueItem> ByUser(string userId) => Builders<ReadQueueItem>.Filter.Eq(t => t.UserId, userId);

            /// <summary>
            /// По точному совпадению
            /// </summary>
            /// <param name="bookId">Идентификатор книги</param>
            /// <param name="userId">Идентификатор пользователя</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<ReadQueueItem> Exact(string bookId, string userId) =>
                Builders<ReadQueueItem>.Filter.And(
                    Builders<ReadQueueItem>.Filter.Eq(t => t.BookId, bookId),
                    Builders<ReadQueueItem>.Filter.Eq(t => t.UserId, userId));
        }

        /// <summary>
        /// Авторы
        /// </summary>
        public static class Authors
        {
            /// <summary>
            /// По идентификаторам авторов
            /// </summary>
            /// <param name="authorIds">Идентификаторы авторов</param>
            /// <returns>Фильтр</returns>
            public static FilterDefinition<Author> ByIds(IEnumerable<string> authorIds) => Builders<Author>.Filter.In(t => t.Id, authorIds);

            /// <summary>
            /// Пустой фильтр
            /// </summary>
            public static FilterDefinition<Author> Empty => Builders<Author>.Filter.Empty;
        }

        /// <summary>
        /// Жанры
        /// </summary>
        public static class Genres
        {
            /// <summary>
            /// Пустой фильтр
            /// </summary>
            public static FilterDefinition<Genre> Empty => Builders<Genre>.Filter.Empty;
        }

        /// <summary>
        /// Авторизация
        /// </summary>
        public static class Auth
        {
            public static FilterDefinition<Member> ByLogin(string login) => Builders<Member>.Filter.Eq(a => a.Login, login);
        }
    }
}
