import logging
import os

from celery import shared_task
from django.conf import settings
from django.contrib.auth.models import User
from django.core.cache import caches

from devices.constants import CACHE_TIMEOUT
from devices.enums import ArmaIndustrialFirewallStatus
from devices.models.firewall import ArmaIndustrialFirewall
from devices.services.firewall import FirewallService
from devices.services.firewall.firewall import firewalls_status_notification_to_ws
from storage.models import DataStorage, get_storage_path

_log = logging.getLogger(__name__)
MEDIA_ROOT = getattr(settings, 'MEDIA_ROOT')


@shared_task
def update_firewall_info_task():
    update_firewall_info()


def update_firewall_info():
    for firewall in ArmaIndustrialFirewall.objects.all():
        info = FirewallService(firewall).get_info()
        ret, status = {'data': info.get('data', info)}, info.get('status', ArmaIndustrialFirewallStatus.error)

        def set_firewall_status(firewall_status, firewall_pk):
            response_json = {
                'status': firewall_status
            }
            caches['redis'].set(f'firewall_{firewall_pk}_status', response_json, CACHE_TIMEOUT)

        if status == ArmaIndustrialFirewallStatus.online:
            set_firewall_status('online', firewall.pk)
            firewall.website = ret['data']['product_website']
            firewall.version = ret['data']['product_version']
            firewall.remote_name = ret['data']['product_name']
            firewall.identification_number = ret['data']['product_id']
            firewall.hash_number = ret['data']['product_hash']
            firewall.flavour = ret['data']['product_flavour']
            firewall.email = ret['data']['product_email']
            firewall.copyright_years = ret['data']['product_copyright_years']
            firewall.copyright_url = ret['data']['product_copyright_url']
            firewall.copyright_owner = ret['data']['product_copyright_owner']
            firewall.architecture = ret['data']['product_arch']
            firewall.abi = ret['data']['product_abi']
            firewall.save()
        elif status == ArmaIndustrialFirewallStatus.offline:
            set_firewall_status('offline', firewall.pk)
        elif status == ArmaIndustrialFirewallStatus.unauthorized:
            set_firewall_status('unauthorized',  firewall.pk)
        else:
            set_firewall_status('error', firewall.pk)
        firewalls_status_notification_to_ws()


@shared_task
def download_files_from_firewall_task(firewall_pk: int, user_pk: int, type_file: str):
    firewall = ArmaIndustrialFirewall.objects.get(pk=firewall_pk)
    user = User.objects.get(pk=user_pk)
    _log.debug(f'[TASK] Start download firewall-{firewall.pk} {type_file}. User: {user}')
    return download_files_from_firewall(firewall, user, type_file)


def download_files_from_firewall(firewall: ArmaIndustrialFirewall, user: 'User', type_file: str) -> int:
    """Скачивания файла с фаервола и сохранения его в локальное Хранилище."""
    _log.debug('[download_files_from_firewall] start')
    format_map = {'rulesets': DataStorage.Format.TAR, 'config': DataStorage.Format.XML}

    store = DataStorage(type=DataStorage.Type.FIREWALL, format=format_map.get(type_file, DataStorage.Format.UNKNOWN),
                        user=user,
                        description=f'{type_file} from {firewall.name} firewall',
                        file='firewall', size=0)
    store.save()
    _log.debug(f'[download_files_from_firewall] create storage [{store.pk}]')

    file_byte, name = FirewallService(firewall).download_file(type_file)
    _log.debug(f'[download_files_from_firewall] get file {name}')
    file_name = get_storage_path(store, name)
    file_path = os.path.join(MEDIA_ROOT, file_name)
    os.makedirs(os.path.dirname(file_path), exist_ok=True)
    _log.debug(f'[download_files_from_firewall] create file {file_path}')
    with open(file_path, 'wb') as file:
        file.write(file_byte)
    store.file = file_name
    store.size = os.path.getsize(file_path)
    store.save()

    _log.debug(f'[download_files_from_firewall] finish.')
    return store.pk
