import datetime
import random
import sys
import traceback

from background_task import background
from background_task import models as taskmodels
from django.conf import settings
from django.db.models import Count
from django.utils import timezone
from telegram.bot import Bot
from telegram.parsemode import ParseMode
from telegram.error import BadRequest
from ..adminModelRegister import registrableModelsInModule
from typing import List, Type

from . import models


@background()
def captcha_kicker():
    captcha_kicker(schedule=5)
    for pendingCaptchaUser in models.PendingCaptchaUser.objects.all():
        td: datetime.timedelta = (pendingCaptchaUser.created + datetime.timedelta(seconds=pendingCaptchaUser.lifetime)) - timezone.now()
        sec_remain = int(td.total_seconds())
        if sec_remain < 0:
            if sec_remain < -1800:
                pendingCaptchaUser.delete()
                continue
            bot_token = pendingCaptchaUser.bot_token
            bot = Bot(token=bot_token)
            try:
                bot.delete_message(
                    chat_id=pendingCaptchaUser.group.telegram_id,
                    message_id=pendingCaptchaUser.captcha_message_id,
                )
            except:
                traceback.print_exc()
            try:
                bot.kick_chat_member(
                    chat_id=pendingCaptchaUser.group.telegram_id,
                    user_id=pendingCaptchaUser.user.telegram_id,
                )
            except:
                traceback.print_exc()
            try:
                bot.unban_chat_member(
                    chat_id=pendingCaptchaUser.group.telegram_id,
                    user_id=pendingCaptchaUser.user.telegram_id,
                )
            except:
                traceback.print_exc()
            pendingCaptchaUser.delete()


@background()
def clean_logs():
    clean_logs(schedule=200)
    TaskModels = [
        taskmodels.CompletedTask,
        taskmodels.Task,
    ]
    for TaskModel in TaskModels:
        for task_name in set(map(lambda a: a['task_name'], TaskModel.objects.values('task_name'))):
            for unwanted_object in taskmodels.Task.objects.filter(task_name=task_name).order_by('-id').all()[100:]:
                unwanted_object.delete()


@background()
def dispatch_periodic_messages():
    dispatch_periodic_messages(schedule=30)
    now = timezone.now()
    for group_preferences in models.GroupPreferences.objects.filter(planned_message_enabled=True).all():
        bot_token = None
        pmi = group_preferences.planned_message_issuer
        if pmi is not None:
            bot_token = pmi.token
        else:
            bot_token = settings.TELEGRAM_TOKEN
        pending_message_dispatch = list(filter(
            lambda pmd: False if (tnd := pmd.time_next_dispatch) is None else tnd <= now,
            group_preferences.planned_message_dispatches.all(),
        ))
        if len(pending_message_dispatch) > 0:
            planned_messages = list(group_preferences.planned_messages.all())
            bot = None
            for dispatch_request in pending_message_dispatch:
                requested_tag_set = set(dispatch_request.tags_as_list)
                compatible_messages = list(filter(
                    lambda planned_message: requested_tag_set.intersection(planned_message.tags_as_list),
                    planned_messages,
                ))
                if len(compatible_messages) == 0:
                    compatible_messages = planned_messages
                if len(compatible_messages) == 0:
                    continue
                message_to_send = random.choice(compatible_messages)
                dispatch_request.time_last_dispatch = now
                dispatch_request.save()
                if bot is None:
                    bot = Bot(token=bot_token)
                failed = False
                try:
                    bot.send_message(
                        chat_id=group_preferences.group.telegram_id,
                        text=message_to_send.message
                        .replace('&nbsp;', ' ')
                        .replace('<br>', '')
                        .replace('<br >', '')
                        .replace('<br/>', '')
                        .replace('<br />', ''),
                        parse_mode=ParseMode.HTML,
                    )
                except:
                    traceback.print_exc()
                    failed = True
                if failed:
                    group_preferences.planned_message_fails += 1
                    if group_preferences.planned_message_fails >= 5:
                        group_preferences.planned_message_enabled = False
                    group_preferences.save()
                else:
                    if group_preferences.planned_message_fails > 0:
                        group_preferences.planned_message_fails = 0
                        group_preferences.save()


@background()
def dispatch_periodic_deletion():
    dispatch_periodic_deletion(schedule=5)
    for self_destructing_message in models.SelfDestructingMessage.objects.all():
        bot = Bot(self_destructing_message.telegram_bot.token)
        try:
            bot.delete_message(self_destructing_message.chat_id,
                               self_destructing_message.message_id)
        except:
            pass
        self_destructing_message.delete()


@background()
def clean_old_objects():
    clean_old_objects(schedule=300)
    model_list: List[Type[models.models.Model]] = registrableModelsInModule(models)
    for model in model_list:
        if getattr(model, 'AUTO_COLLECT', False):
            collection_timeout_seconds = getattr(model, 'COLLECTION_TIMEOUT', 3600*24*28)
            model: Type[models.Timestampable] = model
            for obj in model.objects.all():
                obj: models.Timestampable = obj
                if obj.modified < (timezone.now() - datetime.timedelta(seconds=collection_timeout_seconds)):
                    obj.delete()


taskmodels.Task.objects.filter().delete()
taskmodels.CompletedTask.objects.filter().delete()
captcha_kicker(schedule=5)
dispatch_periodic_messages(schedule=30)
dispatch_periodic_deletion(schedule=5)
clean_logs(schedule=200)
clean_old_objects(schedule=300)
