def remove_user():
    user = request.get_json()['user']
    try:
        Users.objects(username=user).get().delete()
    except DoesNotExist:
        return jsonify({'result': f"User {user} doesn't exist"})

    return jsonify({'result': f"User {user} Removed"})
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 login():
    login_id = request.get_json()['login_id']
    password = request.get_json()['password']

    try:
        response = Users.objects(Q(username=login_id)
                                 or Q(email=login_id)).get()
    except DoesNotExist as err:
        return jsonify({"err": True})

    if bcrypt.check_password_hash(response['password'], password):
        session['user'] = response['username']
        if response.admin:
            return jsonify({
                'admin': True,
                'username': response['username'],
                'profile_pic': response['profile_pic']
            })

        return jsonify({
            'username': response['username'],
            'profile_pic': response['profile_pic']
        })
    else:
        return jsonify({"err": True})
def register():
    username = request.get_json()['username']
    email = request.get_json()['email']
    password = request.get_json()['password']
    date_of_birth = request.get_json()['dob']
    per_desc = request.get_json()['per_desc']

    P = PPredictor()
    C = CPredictor()

    keys = ['OPN', 'CON', 'EXT', 'AGR', 'NEU']
    prediction = P.user_predict([per_desc])
    personlaity = {keys[x]: prediction[x] for x in range(0, 5)}

    cluster = C.user_cluster_predict([prediction])[0]

    password = bcrypt.generate_password_hash(
        request.get_json()['password']).decode('utf-8')

    try:
        Users(username=username,
              email=email,
              date_of_birth=date_of_birth,
              password=password,
              personality_index=personlaity,
              cluster=cluster,
              description=per_desc).save()
    except NotUniqueError:
        return jsonify({"error": "Username or Email is not unique"})
    except:
        return jsonify({"error": "Registration Error, please try again"})

    return jsonify({'result': email + ' registered'})
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 remove_shelf():
    shelf = request.get_json()['shelf']
    user = Users.objects(username=session['user']).get()
    user.shelves.remove(user.shelves.get(shelf_title=shelf))

    user.save()

    return jsonify({'result': True})
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 update_shelf():
    data = request.get_json()['data']

    user = Users.objects(username=session['user']).get()
    shelf = user.shelves.get(shelf_title=data['old_title'])
    shelf.shelf_title = data['new_title']
    shelf.shelf_pic = data['pic']

    user.save()

    return jsonify({'result': 'Shelf has been updated'})
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 update_proflie_data():
    data = request.get_json()['data']

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

    session['user'] = data['username']

    user.profile_pic = data['profile_pic']
    user.username = data['username']
    user.email = data['email']
    user.save()

    return jsonify({"updated": True})
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 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 add_shelf():
    data = request.get_json()['data']

    user = Users.objects(username=session['user']).get()
    for s in user.shelves:
        if s.shelf_title == data['shelf']:
            return jsonify({"result": 'shelf already present'})

    if len(data['pic']) > 0:
        user.shelves.append(
            Shelves(shelf_title=data['shelf'], shelf_pic=data['pic']))
    else:
        user.shelves.append(Shelves(shelf_title=data['shelf']))

    user.save()
    return jsonify({"result": "Shelf created"})
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 get_user_shelf():
    user = Users.objects(username=session['user']).get()

    shelves = []
    for shelf in user.shelves:
        books = []
        for book in shelf.shelved_books:
            books.append({
                'id': str(book.id),
                'title': book.book_title,
                'cover_image': book.cover_image,
                'authors': book.authors
            })
        shelves.append({
            "shelf_title": shelf.shelf_title,
            "shelf_pic": shelf.shelf_pic,
            "books": books
        })

    return jsonify({"shelves": json.dumps(shelves)})
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})
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 get_user():
    user = Users.objects(username=session['user']).get()
    return jsonify({"user": user.to_json()})