import datetime

from router_manager.models import Router
from .models import MessageChannel, Notification, MessageSettings, Message
from backup_data.models import RouterBackup
import requests
from django.utils import timezone


def concatenate_notifications(notification_type: str):
    concatenate_count = 0
    message_settings, _ = MessageSettings.objects.get_or_create(name='message_settings')
    message_channel_list = MessageChannel.objects.filter(enabled=True)
    if notification_type == 'status_online':
        notification_text = 'Router status change: Online\n'
        notification_list = Notification.objects.filter(notification_type='status_online')
        message_channel_list = message_channel_list.filter(status_change_online=True)
    elif notification_type == 'status_offline':
        notification_text = 'Router status change: Offline\n'
        notification_list = Notification.objects.filter(notification_type='status_offline')
        message_channel_list = message_channel_list.filter(status_change_offline=True)
    elif notification_type == 'backup_fail':
        notification_text = 'Backup failed report\n'
        notification_list = Notification.objects.filter(notification_type='backup_fail')
        message_channel_list = message_channel_list.filter(backup_fail=True)
    else:
        return 0

    notification_list = notification_list.order_by('created')
    for notification in notification_list:
        notification_text_temp = notification_text
        if notification.router_backup:
            notification_text_temp += f'\n- Backup: {notification.router_backup.id} for router {notification.router_backup.router.name} '
        elif notification.router:
            notification_text_temp += f'\n- Router {notification.router.name} ({notification.router.address})'
        if len(notification_text_temp) < message_settings.max_length:
            notification_text = notification_text_temp
            notification.delete()
            concatenate_count += 1
        else:
            break

    for message_channel in message_channel_list:
        Message.objects.create(
            channel=message_channel,
            subject=notification_text.split('\n')[0],
            message=notification_text
        )
    return concatenate_count


def generate_backup_report(data):
    message_settings, _ = MessageSettings.objects.get_or_create(name='message_settings')
    yesterday = timezone.now() - datetime.timedelta(days=1)
    failed_backup_list = RouterBackup.objects.filter(error=True, updated__gt=yesterday)
    success_backup_list = RouterBackup.objects.filter(success=True, updated__gt=yesterday)
    pending_backup_list = RouterBackup.objects.filter(success=False, error=False, updated__gt=yesterday)
    if data['report_time_exception']:
        message_text = 'Warning: Error calculating report time, please check your timezone settings.\n\n'
    else:
        message_text = ''
    message_text = 'Routerfleet Daily backup report:\n'
    message_text += f'Backups completed: {success_backup_list.count()}\n'
    message_text += f'Backups failed: {failed_backup_list.count()}\n'
    message_text += f'Backups pending: {pending_backup_list.count()}\n'

    if failed_backup_list.count() > 0:
        message_text += '\n=========\n Failed backups:\n'
        message_text_temp = message_text
        truncate_text = 'There are more failed backups, please check the web interface for the full list\n\n'
        for backup in failed_backup_list:
            message_text_temp += f'- Backup {backup.id} for router {backup.router.name} ({backup.router.address})\n'
            if len(message_text_temp + truncate_text) < message_settings.max_length:
                message_text = message_text_temp
            else:
                message_text += truncate_text
                break
    for message_channel in MessageChannel.objects.filter(enabled=True, daily_backup_report=True):
        Message.objects.create(
            channel=message_channel,
            subject='Daily backup report',
            message=message_text
        )
    message_settings.last_daily_backup_report = timezone.now()
    message_settings.save()
    return


def generate_status_report(data):
    message_settings, _ = MessageSettings.objects.get_or_create(name='message_settings')
    router_list = Router.objects.filter(enabled=True, monitoring=True)
    offline_count = router_list.filter(routerstatus__status_online=False).count()
    if data['report_time_exception']:
        message_text = 'Warning: Error calculating report time, please check your timezone settings.\n\n'
    else:
        message_text = ''
    message_text += 'Routerfleet Daily status report:\n'
    message_text += f'Monitored routers: {router_list.count()}\n'
    message_text += f'Online: {router_list.filter(routerstatus__status_online=True).count()}\n'
    message_text += f'Offline: {offline_count}\n'

    if offline_count > 0:
        message_text += '\n=========\n Offline routers:\n'
        message_text_temp = message_text
        truncate_text = 'There are more offline routers, please check the web interface for the full list\n\n'
        for router in router_list.filter(routerstatus__status_online=False):
            message_text_temp += f'- {router.name} ({router.address})\n'
            if len(message_text_temp + truncate_text) < message_settings.max_length:
                message_text = message_text_temp
            else:
                message_text += truncate_text
                break

    message_channel_list = MessageChannel.objects.filter(enabled=True, daily_status_report=True)
    for message_channel in message_channel_list:
        Message.objects.create(
            channel=message_channel,
            subject='Daily status report',
            message=message_text
        )
    message_settings.last_daily_status_report = timezone.now()
    message_settings.save()
    return


def send_notification_message(message: Message):
    message_settings, _ = MessageSettings.objects.get_or_create(name='message_settings')
    if message.status != 'pending':
        return
    if message.retry_count > message_settings.max_retry:
        message.status = 'failed'
        message.completed = timezone.now()
        message.save()
        return

    message_response = {'status': 'pending', 'error_message': '', 'error_status_code': 0}
    if message.channel.channel_type == 'callmebot':
        url = f'https://api.callmebot.com/whatsapp.php?phone={message.channel.destination}&text={message.message}&apikey={message.channel.token}'
    elif message.channel.channel_type == 'telegram':
        url = f'https://api.telegram.org/bot{message.channel.token}/sendMessage?chat_id={message.channel.destination}&text={message.message}'
    else:
        message_response['status'] = 'failed'
        message_response['error_message'] = 'Failed to send message: Invalid channel type'
        message_response['error_status_code'] = 0

    if message_response['status'] == 'pending':
        try:
            response = requests.get(url)
            if response.status_code == 200:
                message_response['status'] = 'sent'
            else:
                message_response['status'] = 'failed'
                message_response['error_message'] = response.text
                message_response['error_status_code'] = response.status_code
        except:
            message_response['status'] = 'failed'
            message_response['error_message'] = 'Failed to send message: Request exception'
            message_response['error_status_code'] = 0

    if message_response['status'] == 'sent':
        message.status = 'sent'
        message.completed = timezone.now()
        message.save()
    else:
        message.retry_count += 1
        message.error_message = message_response['error_message']
        message.error_status_code = message_response['error_status_code']
        message.next_retry = timezone.now() + datetime.timedelta(seconds=message_settings.retry_interval)
        message.save()
    return


def notify_router_status_update(router: Router):
    message_channel_list = MessageChannel.objects.filter(enabled=True)
    message_settings, _ = MessageSettings.objects.get_or_create(name='message_settings')

    if message_settings.concatenate_status_change:
        if router.routerstatus.status_online:
            if message_channel_list.filter(status_change_online=True):
                Notification.objects.create(notification_type='status_online', router=router)
        else:
            if message_channel_list.filter(status_change_offline=True):
                Notification.objects.create(notification_type='status_offline', router=router)
    else:
        if router.routerstatus.status_online:
            for message_channel in message_channel_list.filter(status_change_online=True):
                Message.objects.create(
                    channel=message_channel,
                    subject='Router status change: Online',
                    message=f'Router {router.name} ({router.address}) is now online'
                )
        else:
            for message_channel in message_channel_list.filter(status_change_offline=True):
                Message.objects.create(
                    channel=message_channel,
                    subject='Router status change: Offline',
                    message=f'Router {router.name} ({router.address}) is now offline'
                )
    return


def notify_backup_fail(router_backup: RouterBackup):
    message_settings, _ = MessageSettings.objects.get_or_create(name='message_settings')
    message_channel_list = MessageChannel.objects.filter(enabled=True, backup_fail=True)

    if not message_channel_list:
        return

    if message_settings.concatenate_backup_fails:
        Notification.objects.create(notification_type='backup_fail', router=router_backup.router, router_backup=router_backup)
    else:
        error_message = f'Backup {router_backup.id} failed for router {router_backup.router.name} ({router_backup.router.address})'
        if router_backup.error_message:
            error_message += f'\n\nError message: {router_backup.error_message}'
        for message_channel in message_channel_list:
            Message.objects.create(
                channel=message_channel,
                subject=f'Backup failed: {router_backup.id}',
                message=error_message
            )
    return
