from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist

import requests

from celery.exceptions import Reject
from celery.utils.log import get_task_logger

from newsreader.accounts.models import User
from newsreader.celery import app
from newsreader.news.collection.choices import RuleTypeChoices
from newsreader.news.collection.feed import FeedCollector
from newsreader.news.collection.utils import post
from newsreader.utils.celery import MemCacheLock


logger = get_task_logger(__name__)


class FeedTask(app.Task):
    name = "FeedTask"
    ignore_result = True

    def run(self, user_pk):
        try:
            user = User.objects.get(pk=user_pk)
        except ObjectDoesNotExist:
            message = f"User {user_pk} does not exist"
            logger.exception(message)

            raise Reject(reason=message, requeue=False)

        with MemCacheLock(f"{user.email}-task", self.app.oid) as acquired:
            if acquired:
                logger.info(f"Running task for user {user_pk}")

                rules = user.rules.enabled().filter(type=RuleTypeChoices.feed)

                collector = FeedCollector()
                collector.collect(rules=rules)
            else:
                logger.warning(
                    f"Cancelling task due to existing lock for user {user_pk}"
                )

                raise Reject(reason="Task already running", requeue=False)


class RedditTask(app.Task):
    name = "RedditTask"
    ignore_result = True

    def run(self):
        from newsreader.news.collection.reddit import RedditCollector, RedditScheduler

        with MemCacheLock("reddit-task", self.app.oid) as acquired:
            if acquired:
                logger.info(f"Running reddit task")

                scheduler = RedditScheduler()
                subreddits = scheduler.get_scheduled_rules()

                collector = RedditCollector()
                collector.collect(rules=subreddits)
            else:
                logger.warning(f"Cancelling task due to existing lock")

                raise Reject(reason="Task already running", requeue=False)


class RedditTokenTask(app.Task):
    name = "RedditTokenTask"
    ignore_result = True

    def run(self, user_pk):
        from newsreader.news.collection.reddit import REDDIT_URL

        try:
            user = User.objects.get(pk=user_pk)
        except ObjectDoesNotExist:
            message = f"User {user_pk} does not exist"
            logger.exception(message)

            raise Reject(reason=message, requeue=False)

        if not user.reddit_refresh_token:
            raise Reject(reason=f"User {user_pk} has no refresh token", requeue=False)

        client_auth = requests.auth.HTTPBasicAuth(
            settings.REDDIT_CLIENT_ID, settings.REDDIT_CLIENT_SECRET
        )

        try:
            response = post(
                f"{REDDIT_URL}/api/v1/access_token",
                data={
                    "grant_type": "refresh_token",
                    "refresh_token": user.reddit_refresh_token,
                },
                auth=client_auth,
            )
        except StreamException:
            logger.exception(
                f"Failed refreshing reddit access token for user {user_pk}"
            )

            user.reddit_refresh_token = None
            user.save()
            return

        response_data = response.json()

        user.reddit_access_token = response_data["access_token"]
        user.save()


class TwitterTimelineTask(app.Task):
    name = "TwitterTimelineTask"
    ignore_result = True

    def run(self, user_pk):
        from newsreader.news.collection.twitter import (
            TwitterCollector,
            TwitterTimeLineScheduler,
        )

        try:
            user = User.objects.get(pk=user_pk)
        except ObjectDoesNotExist:
            message = f"User {user_pk} does not exist"
            logger.exception(message)

            raise Reject(reason=message, requeue=False)

        with MemCacheLock("f{user.email}-timeline-task", self.app.oid) as acquired:
            if acquired:
                logger.info(f"Running twitter timeline task for user {user_pk}")

                scheduler = TwitterTimeLineScheduler(user)
                timelines = scheduler.get_scheduled_rules()

                collector = TwitterCollector()
                collector.collect(rules=timelines)
            else:
                logger.warning(f"Cancelling task due to existing lock")

                raise Reject(reason="Task already running", requeue=False)


class FaviconTask(app.Task):
    name = "FaviconTask"
    ignore_result = True

    def run(self, user_pk):
        from newsreader.news.collection.favicon import FaviconCollector

        try:
            user = User.objects.get(pk=user_pk)
        except ObjectDoesNotExist:
            message = f"User {user_pk} does not exist"
            logger.exception(message)

            raise Reject(reason=message, requeue=False)

        with MemCacheLock("f{user.email}-favicon-task", self.app.oid) as acquired:
            if acquired:
                logger.info(f"Running favicon task for user {user_pk}")

                rules = user.rules.enabled().filter(type=RuleTypeChoices.feed)

                collector = FaviconCollector()
                collector.collect(rules=rules)

                third_party_rules = user.rules.enabled().exclude(
                    type=RuleTypeChoices.feed
                )

                for rule in third_party_rules:
                    if rule.type == RuleTypeChoices.subreddit:
                        rule.favicon = "https://www.reddit.com/favicon.ico"
                        rule.save()
                    elif rule.type == RuleTypeChoices.twitter_timeline:
                        rule.favicon = "https://abs.twimg.com/favicons/favicon.ico"
                        rule.save()
            else:
                logger.warning(f"Cancelling task due to existing lock")

                raise Reject(reason="Task already running", requeue=False)


FeedTask = app.register_task(FeedTask())
FaviconTask = app.register_task(FaviconTask())
RedditTask = app.register_task(RedditTask())
RedditTokenTask = app.register_task(RedditTokenTask())
TwitterTimelineTask = app.register_task(TwitterTimelineTask())
