def get_book_recommendation():
    user = Users.objects(username=session['user']).get()

    genres = []
    ignore_books = []
    for shelf in user.shelves:
        for book in shelf.shelved_books:
            ignore_books.append(book['id'])
            for genre in book.genres:
                genres.append(genre)

    genres = list(dict(Counter(genres).most_common()).keys())

    books = None
    if len(ignore_books) > 0:
        if len(genres) > 5:
            genres = genres[:5]

        books = Books.objects(
            Q(avg_rating__gte=4.5) & Q(genres__in=list(genres))
            & Q(id__nin=list(set(ignore_books)))).only('book_title', 'id',
                                                       'cover_image',
                                                       'authors', 'genres',
                                                       'avg_rating').to_json()

    else:
        books = Books.objects(avg_rating__gte=4.5).only(
            'book_title', 'id', 'cover_image', 'authors', 'genres',
            'avg_rating').to_json()

    books = json.loads(books)
    books = random.sample(books, 8)

    return jsonify({"rec": json.dumps(books)})
def delete_book():
    id = request.get_json()['id']

    try:
        Books.objects(id=id).get().delete()
    except DoesNotExist:
        return jsonify({'result': "Book Doesn't exist"})

    return jsonify({'result': 'Book Deleted'})
def get_genre_recommendation():
    cluster = Users.objects(username=session['user']).get().cluster
    genres = []
    for gens in Books.objects(cluster=cluster).only('genres'):
        genres += gens.genres

    genres = list(dict(Counter(genres).most_common()).keys())

    return jsonify({'result': genres[:6]})
def remove_review():
    book = request.get_json()['book']

    book = Books.objects(id=book).get()
    book.reviews.remove(book.reviews.get(username=session['user']))
    book.save()
    Users.objects(username=session['user']).get().history.remove(book).save()

    return jsonify({'result': True})
def remove_shelf_book():
    book = request.get_json()['book']
    shelf = request.get_json()['shelf']

    user = Users.objects(username=session['user']).get()
    user.shelves.get(shelf_title=shelf).shelved_books.remove(
        Books.objects(id=book).get())

    user.save()

    return jsonify({'result': True})
def add_book_to_shelf():
    shelf = request.get_json()['shelf']
    book = request.get_json()['book']

    user = Users.objects(username=session['user']).get()
    book = Books.objects(id=book).get()

    if book not in user.shelves.get(shelf_title=shelf).shelved_books:
        user.shelves.get(shelf_title=shelf).shelved_books.append(book)
        user.save()
        return jsonify({"result": 'Book Added'})
    return jsonify({"result": 'Book already present inside shelf'})
def search_book():
    title = request.args.get('title', default=None, type=str)
    genre = request.args.get('genre', default=None, type=str)
    author = request.args.get('author', default=None, type=str)

    books = None
    if title != None:
        books = Books.objects(
            book_title__icontains=title).order_by('-avg_rating')

    elif genre != None:
        books = Books.objects(genres__icontains=genre).order_by('-avg_rating')

    elif author != None:
        books = Books.objects(
            authors__icontains=author).order_by('-avg_rating')

    lim = 10
    total = books.count()
    if total % lim != 0:
        total = int(total / lim) + 1
    else:
        total = int(total / lim)

    if 'user' in session:
        user = Users.objects(username=session['user']).get()
        shelves = []
        for shelf in user['shelves']:
            shelves.append(shelf['shelf_title'])

        return jsonify({
            "books": books.to_json(),
            "total": total,
            "shelves": shelves
        })

    return jsonify({"books": books.to_json(), "total": total})
def recommend_books_by_personality():
    data = Users.objects(username=session['user']).only(
        'personality_index', 'cluster', 'shelves').get()

    if data['cluster'] == -1:
        return jsonify({'nope': 'You have not gotten your personality yet'})

    per = data['personality_index']
    books = Books.objects(cluster=data['cluster']).aggregate(*[
        # {
        #     '$project': {
        #         'id': 1,
        #         'book_title': 1,
        #         'cover_image': 1,
        #         'avg_rating': 1,
        #         'genres': 1,
        #         'authors': 1,
        #         'personality_index': 1
        #     }
        # },
        {
            '$sample': {
                'size': 5
            }
        }
    ])

    books = list(books)

    dis = {}
    up = tuple(per.values())
    for x in range(len(books)):
        bp = tuple(books[x]['personality_index'].values())
        dis[x] = distance.euclidean(up, bp)

    dis = sorted(dis.items(), key=lambda x: x[1])
    sorted_books = []
    for x in dis:
        oid = str(books[x[0]]['_id'])
        del books[x[0]]['_id']
        books[x[0]]['_id'] = {'$oid': oid}

        sorted_books.append(books[x[0]])

    shelves = []
    for shelf in data['shelves']:
        shelves.append(shelf['shelf_title'])

    return jsonify({"books": sorted_books, "total": 1, "shelves": shelves})
def update_book():
    data = request.get_json()['data']

    book = Books.objects(id=data['id']).get()

    book.book_title = data['book_title']
    book.description = data['description']
    book.authors = data['authors']
    book.genres = data['genres']
    book.links = data['links']
    book.cover_image = data['cover_image']
    book.extra_details = data['extra_details']
    book.save()

    return jsonify({'result': 'Book Updated'})
def add_book():
    data = request.get_json()['data']

    try:
        Books(book_title=data['book_title'],
              description=data['description'],
              authors=data['authors'],
              genres=data['genres'],
              links=data['links'],
              cover_image=data['cover_image'],
              extra_details=data['extra_details']).save()
    except NotUniqueError:
        return jsonify({'result': 'Book Description not unique'})

    return jsonify({'result': 'Book Added'})
def get_book(id):
    try:
        book = Books.objects(id=id).get()
    except:
        return jsonify({"err": "Book not found"})

    if 'user' in session:
        user = Users.objects(username=session['user']).get()
        shelves = []
        for shelf in user['shelves']:
            shelves.append(shelf['shelf_title'])

        return jsonify({"book": book.to_json(), "shelves": shelves})

    return jsonify({"book": book.to_json()})
def get_genres():
    genres = Books.objects().distinct('genres')
    dic = {}
    for alp in 'a b c d e f g h i j k l m n o p q r s t u v w x y z'.split():
        dic[alp.upper()] = []
        gen = []
        for genre in genres:
            if genre.lower()[0] == alp:
                if len(gen) < 14:
                    gen.append(genre)
                else:
                    dic[alp.upper()].append(gen)
                    gen = []
        if len(gen) > 0:
            dic[alp.upper()].append(gen)

    return jsonify({'genreResults': dic})
def add_review():
    review = request.get_json()['review']
    book = request.get_json()['book']

    user = Users.objects(username=session['user']).only(
        'username', 'profile_pic').get()
    book = Books.objects(id=book).get()

    try:
        book.reviews.get(username=session['user'])['review_text'] = review
    except DoesNotExist:
        book.reviews.append(
            Reviews(username=user['username'],
                    profile_pic=user['profile_pic'],
                    review_text=review))

    book.save()

    return jsonify({"result": True})
def rate_book():
    book_id = request.get_json()['book']
    rating = request.get_json()['rating']

    book = Books.objects(id=book_id).get()
    user = Users.objects(username=session['user']).get()

    try:
        book.reviews.get(username=session['user'])['rating'] = rating
        book.reviews.get(
            username=session['user'])['created'] = datetime.utcnow()
    except DoesNotExist:
        book.reviews.append(
            Reviews(username=user['username'],
                    profile_pic=user['profile_pic'],
                    rating=rating))
        user.history.append(book)

    book.save()

    return jsonify({"result": True})