import os
import re
from datetime import datetime, timedelta

from django.conf import settings
from django.core.files.storage import default_storage as storage
from django.db import transaction
from django.utils.encoding import force_str

from django_statsd.clients import statsd
from multidb import get_replica

import olympia.core.logger
from olympia import amo
from olympia.addons.models import Addon
from olympia.amo.celery import task
from olympia.amo.decorators import use_primary_db
from olympia.amo.storage_utils import rm_stored_dir
from olympia.constants.blocklist import (
    MLBF_TIME_CONFIG_KEY,
    MLBF_BASE_ID_CONFIG_KEY,
    REMOTE_SETTINGS_COLLECTION_MLBF,
)
from olympia.files.models import File
from olympia.lib.remote_settings import RemoteSettings
from olympia.users.utils import get_task_user
from olympia.zadmin.models import set_config

from .mlbf import MLBF
from .models import Block, BlocklistSubmission, LegacyImport
from .utils import (
    block_activity_log_delete,
    block_activity_log_save,
    datetime_to_ts,
    split_regex_to_list,
)


log = olympia.core.logger.getLogger('z.amo.blocklist')

bracket_open_regex = re.compile(r'(?<!\\){')
bracket_close_regex = re.compile(r'(?<!\\)}')

BLOCKLIST_RECORD_MLBF_BASE = 'bloomfilter-base'


@task
@use_primary_db
def process_blocklistsubmission(multi_block_submit_id, **kw):
    obj = BlocklistSubmission.objects.get(pk=multi_block_submit_id)
    if obj.action == BlocklistSubmission.ACTION_ADDCHANGE:
        # create the blocks from the guids in the multi_block
        obj.save_to_block_objects()
    elif obj.action == BlocklistSubmission.ACTION_DELETE:
        # delete the blocks
        obj.delete_block_objects()


@task
@use_primary_db
@transaction.atomic
def import_block_from_blocklist(record):
    legacy_id = record.get('id')
    using_db = get_replica()
    log.info('Processing block id: [%s]', legacy_id)
    legacy_import, import_created = LegacyImport.objects.update_or_create(
        legacy_id=legacy_id,
        defaults={'record': record, 'timestamp': record.get('last_modified')},
    )
    if not import_created:
        log.info('LegacyRS %s: updating existing LegacyImport object', legacy_id)
        existing_block_ids = list(
            Block.objects.filter(
                legacy_id__in=(legacy_id, f'*{legacy_id}')
            ).values_list('id', flat=True)
        )

    guid = record.get('guid')
    if not guid:
        legacy_import.outcome = LegacyImport.OUTCOME_MISSINGGUID
        legacy_import.save()
        log.error('LegacyRS %s: GUID is falsey, skipping.', legacy_id)
        return
    version_range = (record.get('versionRange') or [{}])[0]
    target_application = version_range.get('targetApplication') or [{}]
    target_GUID = target_application[0].get('guid')
    if target_GUID and target_GUID != amo.FIREFOX.guid:
        legacy_import.outcome = LegacyImport.OUTCOME_NOTFIREFOX
        legacy_import.save()
        log.error(
            'LegacyRS %s: targetApplication (%s) is not Firefox, skipping.',
            legacy_id,
            target_GUID,
        )
        return
    block_kw = {
        'min_version': version_range.get('minVersion', '0'),
        'max_version': version_range.get('maxVersion', '*'),
        'url': record.get('details', {}).get('bug') or '',
        'reason': record.get('details', {}).get('why') or '',
        'legacy_id': legacy_id,
        'updated_by': get_task_user(),
    }
    modified_date = datetime.fromtimestamp(
        record.get('last_modified', datetime_to_ts()) / 1000
    )

    if guid.startswith('/'):
        # need to escape the {} brackets or mysql chokes.
        guid_regexp = bracket_open_regex.sub(r'\{', guid[1:-1])
        guid_regexp = bracket_close_regex.sub(r'\}', guid_regexp)
        # we're going to try to split the regex into a list for efficiency.
        guids_list = split_regex_to_list(guid_regexp)
        if guids_list:
            log.info(
                'LegacyRS %s: Broke down regex into list; '
                'attempting to create Blocks for guids in %s',
                legacy_id,
                guids_list,
            )
            statsd.incr(
                'blocklist.tasks.import_blocklist.record_guid', count=len(guids_list)
            )
            addons_guids_qs = (
                Addon.unfiltered.using(using_db)
                .filter(guid__in=guids_list)
                .values_list('guid', flat=True)
            )
        else:
            log.info(
                'LegacyRS %s: Unable to break down regex into list; '
                'attempting to create Blocks for guids matching [%s]',
                legacy_id,
                guid_regexp,