import json
from datetime import datetime

import mock
from pyquery import PyQuery as pq

from olympia import amo
from olympia.amo.tests import ESTestCase, TestCase, version_factory
from olympia.amo.urlresolvers import reverse
from olympia.addons.models import Addon, AppSupport
from olympia.addons.utils import generate_addon_guid
from olympia.compat import FIREFOX_COMPAT
from olympia.compat.cron import compatibility_report
from olympia.compat.indexers import AppCompatIndexer
from olympia.compat.models import CompatReport, CompatTotals
from olympia.stats.models import UpdateCount
from olympia.versions.models import ApplicationsVersions


class TestCompatReportModel(TestCase):

    def test_none(self):
        assert CompatReport.get_counts('xxx') == {'success': 0, 'failure': 0}

    def test_some(self):
        guid = '{2fa4ed95-0317-4c6a-a74c-5f3e3912c1f9}'
        CompatReport.objects.create(
            guid=guid,
            works_properly=True,
            app_multiprocess_enabled=True,
            multiprocess_compatible=True)
        CompatReport.objects.create(
            guid=guid,
            works_properly=True,
            app_multiprocess_enabled=False,
            multiprocess_compatible=True)
        CompatReport.objects.create(
            guid=guid,
            works_properly=False,
            app_multiprocess_enabled=False,
            multiprocess_compatible=True)
        CompatReport.objects.create(
            guid='ballin',
            works_properly=True,
            app_multiprocess_enabled=True,
            multiprocess_compatible=True)
        CompatReport.objects.create(
            guid='ballin',
            works_properly=False,
            app_multiprocess_enabled=True,
            multiprocess_compatible=True)
        assert CompatReport.get_counts(guid) == {'success': 2, 'failure': 1}


class TestIncoming(TestCase):

    def setUp(self):
        super(TestIncoming, self).setUp()
        self.url = reverse('compat.incoming')
        # This is the structure sent to /compatibility/incoming from the ACR.
        self.data = {
            'appBuild': '20110429030623',
            'appGUID': '{ec8030f7-c20a-464f-9b0e-13a3a9e97384}',
            'appVersion': '6.0a1',
            'clientOS': 'Intel Mac OS X 10.6',
            'comments': 'what the what',
            'guid': 'jid0-VsMuA0YYTKCjBh5F0pxHAudnEps@jetpack',
            'otherAddons': [['yslow@yahoo-inc.com', '2.1.0']],
            'version': '2.2',
            'worksProperly': False,
            'appMultiprocessEnabled': True,
            'multiprocessCompatible': True,
        }
        self.json = json.dumps(self.data)

    def test_success(self):
        count = CompatReport.objects.count()
        r = self.client.post(self.url, self.json,
                             content_type='application/json')
        assert r.status_code == 204
        assert CompatReport.objects.count() == count + 1

        cr = CompatReport.objects.order_by('-id')[0]
        assert cr.app_build == self.data['appBuild']
        assert cr.app_guid == self.data['appGUID']
        assert cr.works_properly == self.data['worksProperly']
        assert cr.comments == self.data['comments']
        assert cr.client_ip == '127.0.0.1'
        assert cr.app_multiprocess_enabled == (
            self.data['appMultiprocessEnabled'])
        assert cr.multiprocess_compatible == (
            self.data['multiprocessCompatible'])

        # Check that the other_addons field is stored as json.
        vals = CompatReport.objects.filter(id=cr.id).values('other_addons')
        assert vals[0]['other_addons'] == (
            json.dumps(self.data['otherAddons']))

    def test_e10s_status_unknown(self):
        del self.data['multiprocessCompatible']
        self.json = json.dumps(self.data)

        count = CompatReport.objects.count()
        r = self.client.post(self.url, self.json,
                             content_type='application/json')
        assert r.status_code == 204
        assert CompatReport.objects.count() == count + 1

        cr = CompatReport.objects.order_by('-id')[0]
        assert cr.multiprocess_compatible is None

    def test_bad_json(self):
        r = self.client.post(self.url, 'wuuu#$',
                             content_type='application/json')
        assert r.status_code == 400

    def test_bad_field(self):
        self.data['save'] = 1
        js = json.dumps(self.data)
        r = self.client.post(self.url, js, content_type='application/json')
        assert r.status_code == 400


class TestReporter(TestCase):
    fixtures = ['base/addon_3615']

    def setUp(self):
        super(TestReporter, self).setUp()
        self.addon = Addon.objects.get(pk=3615)
        self.url = reverse('compat.reporter') + '?guid={0}'

    def test_success(self):
        r = self.client.get(reverse('compat.reporter'))
        assert r.status_code == 200

    def test_redirect(self):
        CompatReport.objects.create(guid=self.addon.guid,
                                    app_guid=amo.FIREFOX.guid)
        expected = reverse('compat.reporter_detail', args=[self.addon.guid])

        self.assert3xx(
            self.client.get(self.url.format(self.addon.id)), expected)
        self.assert3xx(
            self.client.get(self.url.format(self.addon.slug)), expected)
        self.assert3xx(
            self.client.get(self.url.format(self.addon.guid)), expected)
        self.assert3xx(
            self.client.get(self.url.format(self.addon.guid[:5])), expected)

    @mock.patch('olympia.compat.views.owner_or_unlisted_reviewer',
                lambda r, a: True)
    def test_unlisted_addon_redirect_for_authorized(self):
        """Can display the reports for an unlisted addon if authorized."""
        self.make_addon_unlisted(self.addon)
        self.test_redirect()

    @mock.patch('olympia.compat.views.owner_or_unlisted_reviewer',
                lambda r, a: False)
    def test_unlisted_addon_no_redirect_for_unauthorized(self):
        """If the user isn't authorized, don't redirect to unlisted addon."""
        self.make_addon_unlisted(self.addon)
        CompatReport.objects.create(guid=self.addon.guid,
                                    app_guid=amo.FIREFOX.guid)

        assert self.client.get(
            self.url.format(self.addon.id)).status_code == 200
        assert self.client.get(
            self.url.format(self.addon.slug)).status_code == 200
        assert self.client.get(