import datetime
from dateutil import parser
from urllib.parse import parse_qs, urlparse

from billiard.exceptions import SoftTimeLimitExceeded
from celery.utils.log import get_task_logger
from django.conf import settings
from django.db.models import Subquery
from django.utils import timezone
import facebook

from verify_trusted.companies.models import Review
from verify_trusted.reviews.models import ReviewSource, Platform
from verify_trusted.widgets.models import WidgetReivews, Widget

logger = get_task_logger(__name__)


class FacebookCrawler:
    def get_reviews(self, access_token, page_id):
        try:
            graph = facebook.GraphAPI(access_token=access_token)
            pages_data = graph.get_object("/me/accounts")
            permanent_page_token = None
            for page in pages_data["data"]:
                if page['id'] == page_id:
                    permanent_page_token = page["access_token"]
            if permanent_page_token is not None:
                page_graph = facebook.GraphAPI(access_token=permanent_page_token)
                object = page_graph.get_object(id=page_id, fields="rating_count,overall_star_rating,ratings")
                total_reviews = object['rating_count']
                avg_rating = object['overall_star_rating']
                rvs = object['ratings']['data']
                reviews = []
                for review in rvs:
                    if 'reviewer' in review.keys():
                        r = {
                            'id': None,
                            'author': review['reviewer']['name'],
                            'date': parser.parse(review['created_time']),
                            'headline': '',
                            'body': str(review['review_text'] or '').strip(),
                            'rating': 5 if review['recommendation_type'] == 'positive' else 1
                        }

                    else:
                        r = {
                            'id': None,
                            'author': 'Reviewer',
                            'date': parser.parse(review['created_time']),
                            'headline': '',
                            'body': str(review['review_text'] or '').strip(),
                            'rating': 5 if review['recommendation_type'] == 'positive' else 1
                        }
                    reviews.append(r)
                return total_reviews, avg_rating, reviews
            else:
                return None
        except Exception as e:
            print(e)
            return None

    def sync_reviews(self, review_source: ReviewSource, access_token, page_id, is_add):
        info = {'access_token': access_token, 'page_id':page_id}
        result = self.get_reviews(access_token, page_id)
        if result is None:
            review_source.sync_status = ReviewSource.SyncStatus.FALSE
            review_source.save()
            return
        total_reviews, avg_rating, reviews = result
        reviews = [
            Review(
                source=review_source,
                author=r['author'],
                date=r['date'],
                headline=r['headline'],
                body=r['body'],
                rating=r['rating'],
                date_parse=timezone.now(),
                external_id=r['id'],
            )
            for r in reviews
        ]
        Review.objects.filter(source_id=review_source.id, lock_edit=True).exclude(id__in=Subquery(
            WidgetReivews.objects.values_list('review_id', flat=True)), display_order__isnull=False).delete()
        Review.objects.bulk_create(reviews, ignore_conflicts=False)  # sua lai khi test xong
        try:

            # get ids of widget comments and review has display_order not null
            dup_reviews_ids = Review.objects.filter(source_id=review_source.id, id__in=Subquery(
                WidgetReivews.objects.values_list('review_id', flat=True)), display_order__isnull=False).values_list(
                'id', flat=True)

            # # check if comment not in widget comment then delete
            uncheck_reviews = Review.objects.filter(id__in=dup_reviews_ids)

            for row in uncheck_reviews:
                reviews = Review.objects.filter(source_id=review_source.id, body=row.body, date=row.date).exclude(
                    id__in=list(dup_reviews_ids))
                try:
                    external_id = reviews[0].external_id
                    row.update(external_id=external_id)
                except:
                    pass
                reviews.delete()
            active_reviews = Review.objects.filter(source_id__in=Subquery(ReviewSource.objects.filter(
                company_id=review_source.company_id).values_list('id', flat=True)), is_active=True).order_by(
                'display_order', '-date_modify', '-date')
            num_active_reviews = len(active_reviews)
            if num_active_reviews < 20:
                nested_q = Review.objects.filter(source_id__in=Subquery(ReviewSource.objects.filter(
                    company_id=review_source.company_id).values_list('id', flat=True)), is_active=False).order_by(
                    'display_order', '-date_modify', '-date')[:(20 - num_active_reviews)]
                Review.objects.filter(pk__in=nested_q).update(is_active=True)
            elif num_active_reviews > 20:
                nested_q = Review.objects.filter(source_id__in=Subquery(ReviewSource.objects.filter(
                    company_id=review_source.company_id).values_list('id', flat=True)),
                                                 is_active=True).order_by('display_order', '-date_modify', '-date')[20:]
                Review.objects.filter(pk__in=nested_q).update(is_active=False, display_order=None)

            if is_add is True:
                widget = Widget.objects.filter(company=review_source.company_id).first()
                widget_reviews = WidgetReivews.objects.filter(widget=widget.id, review__source__platform__status=Platform.Status.ACTIVE).values_list('review', flat=True)
                num_widget_reviews = len(widget_reviews)
                ws = []
                if num_widget_reviews < 5:
                    nested_w = Review.objects.filter(source_id__in=Subquery(ReviewSource.objects.filter(
                        company_id=review_source.company_id,platform__status=Platform.Status.ACTIVE).values_list('id', flat=True))).order_by('display_order', '-date_modify', '-date')[:(5-num_widget_reviews)]
                    for w in nested_w:
                        ws.append(WidgetReivews(widget=widget, review=w))
                    WidgetReivews.objects.bulk_create(ws, ignore_conflicts=False)
                elif num_active_reviews > 5:
                    pass

            review_source.sync_status = ReviewSource.SyncStatus.SYNCED
            print(f"{datetime.datetime.now()} - {total_reviews} : {avg_rating}")
            review_source.reviews_count = total_reviews
            print(f"{datetime.datetime.now()} - set total reviews")
            review_source.average_rating = avg_rating
            print(f"{datetime.datetime.now()} - set avg rating")
            review_source.other = info
            review_source.url = f'https://www.facebook.com/profile.php?id={page_id}'
            review_source.save()
            print(f"done")

        except SoftTimeLimitExceeded as e:
            review_source.sync_status = ReviewSource.SyncStatus.FALSE
            review_source.save()
            print(e)

        # return reviews
