# -*- coding: UTF-8 -*-
from __future__ import absolute_import

from app.models import ConsultationPlatform, Initiative, Idea, Comment, SocialNetworkApp, ParticipaUser
from app.sync import save_sn_post, save_sn_comment, save_sn_vote, cud_initiative_votes, cud_initiative_ideas, \
                     cud_initiative_comments, invalidate_initiative_content, do_push_content, do_delete_content, \
                     revalidate_initiative_content, notify_new_campaigns, count_other_platform_votes, notify_new_users, \
                     notify_join_group, check_reactivated_accounts_activity, update_IS_user_demographic_data
from app.utils import convert_to_utf8_str, call_social_network_api
from app.error import AppError
from celery import shared_task
from celery.utils.log import get_task_logger
from django.core.cache import cache
from django.db.models import Q
from hashlib import md5

import traceback

logger = get_task_logger(__name__)


def _pull_content_social_network(social_network, initiative):
    if social_network.community:
        params = {'app': social_network}
        posts = call_social_network_api(social_network.connector, 'get_posts', params)
        for post in posts:
            ret_data = save_sn_post(social_network, post, initiative)
            if ret_data:
                if 'comments_array' in post.keys():
                    for comment in post['comments_array']:
                        save_sn_comment(social_network, comment)
                        # Process comment's replies
                        if 'comments_array' in comment.keys():
                            for reply in comment['comments_array']:
                                save_sn_comment(social_network, reply)
                        # Process comment's votes
                        if 'votes_array' in comment.keys():
                            for vote in comment['votes_array']:
                                save_sn_vote(social_network, vote)
                # Save/Update votes
                if 'votes_array' in post.keys():
                    for vote in post['votes_array']:
                        save_sn_vote(social_network, vote)
    else:
        logger.warning('Cannot pull content from the social network {}. Reason: Community not found'.
                       format(social_network.name))


def _pull_content_consultation_platform(platform, initiative):
    cud_initiative_ideas(platform, initiative)
    cud_initiative_comments(platform, initiative)
    cud_initiative_votes(platform, initiative)
    notify_new_campaigns(initiative)
    count_other_platform_votes()
    notify_new_users(initiative)
    notify_join_group(initiative)
    check_reactivated_accounts_activity()
    update_IS_user_demographic_data(initiative)


def _handle_pull_exceptions(initiative, platform, invalidate_filters, update_attrs):
    revalidate_initiative_content(invalidate_filters, update_attrs)
    logger.warning('Problem when trying to pull content of the initiative {} from {}. '
                   'The content was re-validated.'.format(initiative, platform))


def pull_data():
    # Pull data of the active initiatives from the consultation platforms
    # and social networks where they are running on
    initiatives = Initiative.objects.filter(active=True)
    for initiative in initiatives:
        invalidate_filters = {'initiative': initiative, 'is_new': False}
        try:
            invalidate_initiative_content(invalidate_filters, {'exist_cp': False})
            logger.info(u'Pulling content of the initiative {} from the platform {}'.format(initiative,
                                                                                           initiative.platform))
            _pull_content_consultation_platform(initiative.platform, initiative)
            for socialnetwork in initiative.social_network.all():
                if not socialnetwork.subscribed_read_time_updates:
                    try:
                        invalidate_initiative_content(invalidate_filters, {'exist_sn': False})
                        logger.info(u'Pulling content of the initiative {} from the platform {}'.format(initiative,
                                                                                                       socialnetwork))
                        _pull_content_social_network(socialnetwork, initiative)
                    except Exception as e:
                        _handle_pull_exceptions(initiative, socialnetwork, invalidate_filters, {'exist_sn': True})
                        raise AppError(e)
                        
        except Exception as e:
            _handle_pull_exceptions(initiative, initiative.platform, invalidate_filters, {'exist_cp': True})
            raise AppError(e)

def push_data():
    batch_req_ideas = {}
    batch_req_comments = {}
    # Push ideas to consultation platforms and social networks
    logger.info('Pushing ideas to social networks and consultation platforms')
    existing_ideas = Idea.objects.filter(Q(exist_sn=True, sn_id__isnull=False) |
                                         Q(exist_cp=True, cp_id__isnull=False)).\
                                  filter(Q(has_changed=True) | Q(is_new=True)).\
                                  order_by('datetime')
    tot_ideas_to_sn = Idea.objects.filter(Q(exist_sn=True, sn_id__isnull=False) |
                                          Q(exist_cp=True, cp_id__isnull=False)).\
                                   filter(Q(has_changed=True) | Q(is_new=True)).\
                                   filter(source='consultation_platform').filter(is_new=True).count()
    count_ideas_to_sn = 0
    for idea in existing_ideas:
        try:
            if idea.initiative.active:
                if idea.source == 'social_network':
                    if not idea.source_social.subscribed_read_time_updates:
                        do_push_content(idea, 'idea')
                else:
                    if idea.is_new:  count_ideas_to_sn += 1
                    if count_ideas_to_sn == tot_ideas_to_sn:
                        batch_req_ideas = do_push_content(idea, 'idea', True, batch_req_ideas)
                    else:
                        batch_req_ideas = do_push_content(idea, 'idea', False, batch_req_ideas)
        except Exception as e:
            if idea.source == 'consultation_platform':
                logger.warning('Error when trying to publish the idea with the id={} on the social networks. '
                               .format(idea.id))
                logger.warning(traceback.format_exc())
            else:
                logger.warning('Error when trying to publish the idea with the id={} on the consultation platforms.'
                               .format(idea.id))
            raise AppError(e)

    # Push comments to consultation platforms and social networks
    logger.info('Pushing comments to social networks and consultation platforms')
    existing_comments = Comment.objects.filter(Q(exist_sn=True, sn_id__isnull=False) |
                                              Q(exist_cp=True, cp_id__isnull=False)).\