import re
import requests
import json
from functools import reduce
from .models import FacebookPage, FacebookReview, FacebookReviewReply

from django.conf import settings

# browser instance
browser_uri = getattr(settings, 'BROWSER_URI', None)

BASE_URL = 'https://graph.facebook.com'


RECOMMENDATION_STR2NUM = {'negative': False, 'positive': True}

def remove_emoji(string):
    emoji_pattern = re.compile("["
                           u"\U0001F600-\U0001F64F"  # emoticons
                           u"\U0001F300-\U0001F5FF"  # symbols & pictographs
                           u"\U0001F680-\U0001F6FF"  # transport & map symbols
                           u"\U0001F1E0-\U0001F1FF"  # flags (iOS)
                           u"\U00002702-\U000027B0"
                           u"\U000024C2-\U0001F251"
                           "]+", flags=re.UNICODE)
    return emoji_pattern.sub(r'', string)

def filter_4bytechar(text):
    return reduce(lambda x,y:x+y  ,filter(lambda x: len(x.encode('utf8'))<4, text))

def get_page_reviews(page_id, n_reviews):
    token = FacebookPage.objects.get(id=page_id).token
    url = f'{BASE_URL}/{page_id}/ratings?fields=open_graph_story&limit={n_reviews}&access_token={token}'
    response = requests.get(url).json()

    # ratings has one field ['data'] which contain all reviews
    data = response.get('data')
    return data


def store_review_reply(review_id, page_id):
    token = FacebookPage.objects.get(id=page_id).token
    url = f'{BASE_URL}/{review_id}/comments?access_token={token}'
    response = requests.get(url).json()
    replies = response.get('data')

    # if review has no reply it will return data=[]
    # if it has reply it it data will return list of reply
    if not replies:
        return
    # we are not interested in all replies.
    # We need the only reply that we did
    for reply in replies:
        from_ = reply.get('from')
        replier_id = from_.get('id') if from_ else None
        if replier_id and replier_id == page_id:
            reply_id = reply.get('id')
            create_time = reply.get('created_time')
            replied_text = reply.get('message')
            # create the review if not exists else update it
            rep = FacebookReviewReply.objects.filter(review_id=review_id).first()
            if rep:
                print('already has an object')
            if not rep:
                FacebookReviewReply.objects.update_or_create(
                    review_id=review_id,
                    reply_id=reply_id,
                    create_time=create_time,
                    replied_text=replied_text
                )
                print('Adding a reply to review....')


def store_reviews_into_db(page_id, n_reviews=25):
    reviews = get_page_reviews(page_id=page_id, n_reviews=n_reviews)
    for review in reviews:
        graph_story = review.get('open_graph_story')
        '''
        >>> graph_story.keys()
            dict_keys(['id', 'message', 'start_time', 'type', 'data'])
        '''
        review_id = graph_story.get('id')
        message = graph_story.get('message')
        message = ' '.join(message.split())
        message = remove_emoji(message)
        message = filter_4bytechar(message)
        start_time = graph_story.get('start_time')
        recommendation_type = RECOMMENDATION_STR2NUM[graph_story.get('data')['recommendation_type']]

        try:
            review = FacebookReview.objects.get(id=review_id)
            review.recommendation_type = recommendation_type
            review.review_text = message
            review.create_time = start_time
            review.page_id = page_id
            review.save()

        except FacebookReview.DoesNotExist:
            review = FacebookReview.objects.create(
                id=review_id,
                recommendation_type=recommendation_type,
                review_text=message,
                create_time=start_time,
                page_id=page_id
            )
            print(f'New Facebook review has been created at {review.page_id}!')

        # store the review reply that is done by signature care
        store_review_reply(review_id=review_id, page_id=page_id)


def populate_facebook_reviews():
    page_ids = FacebookPage.objects.values('id')
    for page_id in page_ids:
        store_reviews_into_db(page_id=page_id.get('id'), n_reviews=10)


def reply2facebook_review(review_id, reply):
    url = browser_uri + f'/facebook/reply'
    payload = {
        'id': review_id,
        'reply': reply
    }
    headers = {'content-type': 'application/json'}
    response = requests.post(url, data=json.dumps(payload), headers=headers)
    return response.status_code


def reply2facebook_review_using_api(review_id, reply):
    token = FacebookReview.objects.filter(pk=review_id).first().page.token
    url = f'{BASE_URL}/{review_id}/comments?message={reply}&access_token={token}'
    response = requests.post(url)
    return response.status_code