import multiprocessing
import multiprocessing.pool

import django.utils.timezone
import requests
from django.core.management.base import BaseCommand

from scrutiny.projects.models import InstalledService, InstalledVersion, Module, Version


class Command(BaseCommand):
    help = 'Scrutiny services for changes'

    def handle(self, verbosity, *args, **options):
        self.verbose = int(verbosity) > 1

        def scrutinise(service):
            if not service.url.endswith('/'):
                service.url = '%s/' % service.url
            if self.verbose:
                print('Checking %s' % service.url)
            try:
                response = requests.get('%s__version__' % service.url, timeout=25, verify=True)
                response.raise_for_status()
            except requests.RequestException as e:
                print('Error with %s (%r)' % (service.url, e))
                return

            try:
                versions = response.json()
            except ValueError:
                print('Non-JSON response for %s' % service.url)
                return

            current_modules = set(service.service.get_modules(platforms=[service.platform]))
            seen_modules = set()

            for module_name, version_string in versions.items():
                try:
                    module = Module.objects.get(name=module_name)
                except Module.DoesNotExist:
                    module = Module()
                    module.name = module_name
                    module.save()

                seen_modules.add(module)
                try:
                    version, _ = Version.objects.get_or_create(module=module, version=version_string)
                except Version.MultipleObjectsReturned:
                    # a race condition occured earlier, gently ignore
                    version = Version.objects.filter(module=module, version=version_string).first()

                try:
                    installed_version = InstalledVersion.objects.get(service=service, version=version)
                except InstalledVersion.DoesNotExist:
                    installed_version = InstalledVersion()
                    installed_version.service = service
                    installed_version.version = version
                    installed_version.timestamp = django.utils.timezone.now()
                    installed_version.save()

            uninstalled_modules = current_modules - seen_modules
            for module in uninstalled_modules:
                try:
                    version = Version.objects.get(module=module, version='')
                except Version.DoesNotExist:
                    version = module.version_set.create(version='')

                installed_version = InstalledVersion()
                installed_version.service = service
                installed_version.version = version
                installed_version.timestamp = django.utils.timezone.now()
                installed_version.save()

        with multiprocessing.pool.ThreadPool() as pool:
            list(pool.imap_unordered(scrutinise, InstalledService.objects.filter(disabled=False)))
