import logging
from datetime import timedelta
from typing import TYPE_CHECKING

from django.utils import timezone
from tweepy import Client
from tweepy.errors import BadRequest

from main.models import MainHomePage, MainPersonPage

from .models import Tweet

if TYPE_CHECKING:
    from tweepy import Tweet as TweetResponse
    from tweepy import User


logger = logging.getLogger()


class TweetDownloadService:
    """
    Service class starající se o update tweetů z Twitter API, v současné chvíli
    bere tweety z účtu nastavených v (první) MainHomePage stránce (HP pirati.cz).
    """

    client: Client
    days_back: int

    def __init__(self, bearer_token, days_back=1):
        if not bearer_token:
            raise RuntimeError("Twitter bearer token not set, cannot update tweets")

        self.client = Client(bearer_token=bearer_token)
        self.days_back = days_back

    @staticmethod
    def get_latest_saved_tweet_id() -> list[int]:
        """
        Vrací IDs už uložených Tweetů - možná by stálo za to brát jen z určitého
        časového období...
        """
        return Tweet.objects.values_list("twitter_id", flat=True)

    def get_tweets_response(self, user_id) -> list["TweetResponse"]:
        """
        Vrací list tweetů (objektů) pro daného Twitter uživatele.
        """
        tweets_response = self.client.get_users_tweets(
            user_id,
            exclude=["retweets"],
            expansions=["author_id", "entities.mentions.username"],
            max_results=100,
            start_time=timezone.now() - timedelta(days=self.days_back),
            tweet_fields=["author_id", "created_at"],
            user_fields=["name", "username"],
        )

        return tweets_response.data or []

    def get_user_list_data(self) -> list["User"]:
        twitter_usernames_block = MainHomePage.objects.first().twitter_usernames
        person_username_list = (
            MainPersonPage.objects.filter(twitter_username__isnull=False)
            .values_list("twitter_username", flat=True)
            .distinct()
        )
        homepage_username_list = [
            username_data["value"] for username_data in twitter_usernames_block.raw_data
        ]
        username_list = [*person_username_list, *homepage_username_list]

        user_data_list = []

        for username in username_list:
            try:
                user_data_list.append(self.get_user_response(username))
            except BadRequest:
                logger.error(
                    "Cannot download tweets for the username",
                    extra={"username": username},
                )

        return user_data_list

    def get_user_response(self, username) -> "User":
        """
        Vrací informace o daném uživateli.
        """
        user_response = self.client.get_user(
            username=username,
            user_fields=["profile_image_url"],  # id, name, username enabled by default
        )

        return user_response.data

    def perform_update(self) -> int:
        """
        Obaluje celý proces downloadu Tweetů z API do DB.
        """
        user_data_list = self.get_user_list_data()
        existing_tweet_id_list = self.get_latest_saved_tweet_id()

        tweets_to_save = []

        for user_data in user_data_list:
            for tweet in self.get_tweets_response(user_id=user_data.id):
                if str(tweet.id) not in existing_tweet_id_list:
                    tweets_to_save.append(
                        Tweet(
                            author_img_url=user_data.profile_image_url,
                            author_name=user_data.name,
                            author_username=user_data.username,
                            text=tweet.text,
                            twitter_id=str(tweet.id),
                        )
                    )

        return Tweet.objects.bulk_create(tweets_to_save)