from __future__ import absolute_import

import six

from datetime import timedelta
from django.utils import timezone
from freezegun import freeze_time

from sentry.testutils import APITestCase, SnubaTestCase
from sentry.testutils.helpers.datetime import iso_format, before_now
from sentry.utils.compat import map


class GroupEventsTest(APITestCase, SnubaTestCase):
    def setUp(self):
        super(GroupEventsTest, self).setUp()
        self.min_ago = before_now(minutes=1)

    def test_simple(self):
        self.login_as(user=self.user)

        event_1 = self.store_event(
            data={
                "event_id": "a" * 32,
                "fingerprint": ["1"],
                "timestamp": iso_format(self.min_ago),
            },
            project_id=self.project.id,
        )
        event_2 = self.store_event(
            data={
                "event_id": "b" * 32,
                "fingerprint": ["1"],
                "timestamp": iso_format(self.min_ago),
            },
            project_id=self.project.id,
        )

        url = u"/api/0/issues/{}/events/".format(event_1.group.id)
        response = self.client.get(url, format="json")

        assert response.status_code == 200, response.content
        assert len(response.data) == 2
        assert sorted(map(lambda x: x["eventID"], response.data)) == sorted(
            [six.text_type(event_1.event_id), six.text_type(event_2.event_id)]
        )

    def test_tags(self):
        self.login_as(user=self.user)
        event_1 = self.store_event(
            data={
                "event_id": "a" * 32,
                "fingerprint": ["1"],
                "tags": {"foo": "baz", "bar": "buz"},
                "timestamp": iso_format(self.min_ago),
            },
            project_id=self.project.id,
        )
        event_2 = self.store_event(
            data={
                "event_id": "b" * 32,
                "fingerprint": ["1"],
                "tags": {"bar": "biz"},
                "timestamp": iso_format(before_now(seconds=61)),
            },
            project_id=self.project.id,
        )
        url = u"/api/0/issues/{}/events/".format(event_1.group.id)
        response = self.client.get(url + "?query=foo:baz", format="json")
        assert response.status_code == 200, response.content
        assert len(response.data) == 1
        assert response.data[0]["eventID"] == six.text_type(event_1.event_id)

        response = self.client.get(url + "?query=!foo:baz", format="json")
        assert response.status_code == 200, response.content
        assert len(response.data) == 1
        assert response.data[0]["eventID"] == six.text_type(event_2.event_id)

        response = self.client.get(url + "?query=bar:biz", format="json")
        assert response.status_code == 200, response.content
        assert len(response.data) == 1
        assert response.data[0]["eventID"] == six.text_type(event_2.event_id)

        response = self.client.get(url + "?query=bar:biz%20foo:baz", format="json")
        assert response.status_code == 200, response.content
        assert len(response.data) == 0

        response = self.client.get(url + "?query=bar:buz%20foo:baz", format="json")
        assert response.status_code == 200, response.content
        assert len(response.data) == 1
        assert response.data[0]["eventID"] == six.text_type(event_1.event_id)

        response = self.client.get(url + "?query=bar:baz", format="json")
        assert response.status_code == 200, response.content
        assert len(response.data) == 0

        response = self.client.get(url + "?query=a:b", format="json")
        assert response.status_code == 200, response.content
        assert len(response.data) == 0

        response = self.client.get(url + "?query=bar:b", format="json")
        assert response.status_code == 200, response.content
        assert len(response.data) == 0

        response = self.client.get(url + "?query=bar:baz", format="json")
        assert response.status_code == 200, response.content
        assert len(response.data) == 0

        response = self.client.get(url + "?query=!bar:baz", format="json")
        assert response.status_code == 200, response.content
        assert len(response.data) == 2
        assert set([e["eventID"] for e in response.data]) == set(
            [event_1.event_id, event_2.event_id]
        )

    def test_search_event_by_id(self):
        self.login_as(user=self.user)
        event_1 = self.store_event(
            data={
                "event_id": "a" * 32,
                "fingerprint": ["group-1"],
                "timestamp": iso_format(self.min_ago),
            },
            project_id=self.project.id,
        )
        self.store_event(
            data={
                "event_id": "b" * 32,
                "fingerprint": ["group-1"],
                "timestamp": iso_format(self.min_ago),
            },
            project_id=self.project.id,
        )
        url = u"/api/0/issues/{}/events/?query={}".format(event_1.group.id, event_1.event_id)
        response = self.client.get(url, format="json")

        assert response.status_code == 200, response.content
        assert len(response.data) == 1
        assert response.data[0]["eventID"] == event_1.event_id

    def test_search_event_by_message(self):
        self.login_as(user=self.user)

        event_1 = self.store_event(
            data={
                "event_id": "a" * 32,
                "fingerprint": ["group-1"],
                "message": "foo bar hello world",
                "timestamp": iso_format(self.min_ago),
            },
            project_id=self.project.id,
        )
        group = event_1.group
        event_2 = self.store_event(
            data={
                "event_id": "b" * 32,
                "fingerprint": ["group-1"],
                "message": "this bar hello world",
                "timestamp": iso_format(self.min_ago),
            },
            project_id=self.project.id,
        )
        assert group == event_2.group

        query_1 = "foo"
        query_2 = "hello+world"

        # Single Word Query
        url = u"/api/0/issues/{}/events/?query={}".format(group.id, query_1)
        response = self.client.get(url, format="json")

        assert response.status_code == 200, response.content
        assert len(response.data) == 1
        assert response.data[0]["eventID"] == event_1.event_id

        # Multiple Word Query
        url = u"/api/0/issues/{}/events/?query={}".format(group.id, query_2)
        response = self.client.get(url, format="json")

        assert response.status_code == 200, response.content
        assert len(response.data) == 2
        assert sorted(map(lambda x: x["eventID"], response.data)) == sorted(
            [six.text_type(event_1.event_id), six.text_type(event_2.event_id)]
        )

    def test_search_by_release(self):
        self.login_as(user=self.user)
        self.create_release(self.project, version="first-release")
        event_1 = self.store_event(
            data={
                "event_id": "a" * 32,
                "fingerprint": ["group-1"],
                "timestamp": iso_format(self.min_ago),
                "release": "first-release",
            },
            project_id=self.project.id,
        )
        url = u"/api/0/issues/{}/events/?query=release:latest".format(event_1.group.id)
        response = self.client.get(url, format="json")

        assert response.status_code == 200, response.content
        assert len(response.data) == 1
        assert response.data[0]["eventID"] == event_1.event_id

    def test_environment(self):
        self.login_as(user=self.user)
        events = {}

        for name in ["production", "development"]:
            events[name] = self.store_event(
                data={
                    "fingerprint": ["put-me-in-group1"],
                    "timestamp": iso_format(self.min_ago),
                    "environment": name,
                },
                project_id=self.project.id,
            )

        # Asserts that all are in the same group
        (group_id,) = set(e.group.id for e in events.values())

        url = u"/api/0/issues/{}/events/".format(group_id)
        response = self.client.get(url + "?environment=production", format="json")

        assert response.status_code == 200, response.content
        assert set(map(lambda x: x["eventID"], response.data)) == set(
            [six.text_type(events["production"].event_id)]
        )

        response = self.client.get(
            url, data={"environment": ["production", "development"]}, format="json"
        )
        assert response.status_code == 200, response.content
        assert set(map(lambda x: x["eventID"], response.data)) == set(
            [six.text_type(event.event_id) for event in events.values()]
        )

        response = self.client.get(url + "?environment=invalid", format="json")

        assert response.status_code == 200, response.content
        assert response.data == []

        response = self.client.get(
            url + "?environment=production&query=environment:development", format="json"
        )

        assert response.status_code == 200, response.content
        assert response.data == []

    def test_filters_based_on_retention(self):
        self.login_as(user=self.user)
        self.store_event(
            data={"fingerprint": ["group_1"], "timestamp": iso_format(before_now(days=2))},
            project_id=self.project.id,
        )
        event_2 = self.store_event(
            data={"fingerprint": ["group_1"], "timestamp": iso_format(self.min_ago)},
            project_id=self.project.id,
        )
        group = event_2.group

        with self.options({"system.event-retention-days": 1}):
            response = self.client.get(u"/api/0/issues/{}/events/".format(group.id))

        assert response.status_code == 200, response.content
        assert len(response.data) == 1
        assert sorted(map(lambda x: x["eventID"], response.data)) == sorted(
            [six.text_type(event_2.event_id)]
        )

    def test_search_event_has_tags(self):
        self.login_as(user=self.user)
        event = self.store_event(
            data={
                "timestamp": iso_format(self.min_ago),
                "message": "foo",
                "tags": {"logger": "python"},
            },
            project_id=self.project.id,
        )

        response = self.client.get(u"/api/0/issues/{}/events/".format(event.group.id))

        assert response.status_code == 200, response.content
        assert len(response.data) == 1
        assert {"key": "logger", "value": "python"} in response.data[0]["tags"]

    @freeze_time()
    def test_date_filters(self):
        self.login_as(user=self.user)
        event_1 = self.store_event(
            data={"timestamp": iso_format(before_now(days=5)), "fingerprint": ["group-1"]},
            project_id=self.project.id,
        )
        event_2 = self.store_event(
            data={"timestamp": iso_format(before_now(days=1)), "fingerprint": ["group-1"]},
            project_id=self.project.id,
        )
        group = event_1.group
        assert group == event_2.group

        response = self.client.get(
            u"/api/0/issues/{}/events/".format(group.id), data={"statsPeriod": "6d"}
        )

        assert response.status_code == 200, response.content
        assert len(response.data) == 2
        assert sorted(map(lambda x: x["eventID"], response.data)) == sorted(
            [six.text_type(event_1.event_id), six.text_type(event_2.event_id)]
        )

        response = self.client.get(
            u"/api/0/issues/{}/events/".format(group.id), data={"statsPeriod": "2d"}
        )

        assert response.status_code == 200, response.content
        assert len(response.data) == 1
        assert response.data[0]["eventID"] == six.text_type(event_2.event_id)

    def test_invalid_period(self):
        self.login_as(user=self.user)
        first_seen = timezone.now() - timedelta(days=5)
        group = self.create_group(first_seen=first_seen)
        response = self.client.get(
            u"/api/0/issues/{}/events/".format(group.id), data={"statsPeriod": "lol"}
        )
        assert response.status_code == 400

    def test_invalid_query(self):
        self.login_as(user=self.user)
        first_seen = timezone.now() - timedelta(days=5)
        group = self.create_group(first_seen=first_seen)
        response = self.client.get(
            u"/api/0/issues/{}/events/".format(group.id),
            data={"statsPeriod": "7d", "query": "foo(bar"},
        )
        assert response.status_code == 400

    def test_multiple_group(self):
        self.login_as(user=self.user)

        event_1 = self.store_event(
            data={
                "fingerprint": ["group_1"],
                "event_id": "a" * 32,
                "message": "foo",
                "timestamp": iso_format(self.min_ago),
            },
            project_id=self.project.id,
        )
        event_2 = self.store_event(
            data={
                "fingerprint": ["group_2"],
                "event_id": "b" * 32,
                "message": "group2",
                "timestamp": iso_format(self.min_ago),
            },
            project_id=self.project.id,
        )

        for event in (event_1, event_2):
            url = u"/api/0/issues/{}/events/".format(event.group.id)
            response = self.client.get(url, format="json")
            assert response.status_code == 200, response.content
            assert len(response.data) == 1, response.data
            assert map(lambda x: x["eventID"], response.data) == [six.text_type(event.event_id)]