import uuid
from unittest.mock import patch

from sentry.issues.grouptype import PerformanceNPlusOneGroupType, ProfileFileIOGroupType
from sentry.models.group import Group
from sentry.testutils.cases import PerformanceIssueTestCase, SnubaTestCase, TestCase
from sentry.testutils.helpers.datetime import before_now, iso_format
from sentry.utils.samples import load_data
from tests.sentry.issues.test_utils import OccurrenceTestMixin


class GroupTestSnuba(TestCase, SnubaTestCase, PerformanceIssueTestCase, OccurrenceTestMixin):
    def test_get_oldest_latest_for_environments(self):
        project = self.create_project()

        min_ago = iso_format(before_now(minutes=1))

        self.store_event(
            data={
                "event_id": "a" * 32,
                "environment": "production",
                "timestamp": min_ago,
                "fingerprint": ["group-1"],
            },
            project_id=project.id,
        )
        self.store_event(
            data={
                "event_id": "b" * 32,
                "environment": "production",
                "timestamp": min_ago,
                "fingerprint": ["group-1"],
            },
            project_id=project.id,
        )
        self.store_event(
            data={"event_id": "c" * 32, "timestamp": min_ago, "fingerprint": ["group-1"]},
            project_id=project.id,
        )

        group = Group.objects.first()

        assert group.get_latest_event_for_environments().event_id == "c" * 32
        assert group.get_latest_event_for_environments(["staging"]) is None
        assert group.get_latest_event_for_environments(["production"]).event_id == "b" * 32
        assert group.get_oldest_event_for_environments().event_id == "a" * 32
        assert (
            group.get_oldest_event_for_environments(["staging", "production"]).event_id == "a" * 32
        )
        assert group.get_oldest_event_for_environments(["staging"]) is None

    def test_perf_issue(self):
        group_fingerprint = f"{PerformanceNPlusOneGroupType.type_id}-group1"

        event_data_1 = load_data("transaction-n-plus-one", fingerprint=[group_fingerprint])
        event_data_1["timestamp"] = iso_format(before_now(seconds=10))
        event_data_1["start_timestamp"] = iso_format(before_now(seconds=11))
        event_data_1["event_id"] = "d" * 32
        event_data_2 = load_data("transaction-n-plus-one", fingerprint=[group_fingerprint])
        event_data_2["timestamp"] = iso_format(before_now(seconds=20))
        event_data_2["start_timestamp"] = iso_format(before_now(seconds=21))
        event_data_2["event_id"] = "f" * 32
        event_data_3 = load_data("transaction-n-plus-one", fingerprint=[group_fingerprint])
        event_data_3["timestamp"] = iso_format(before_now(seconds=30))
        event_data_3["start_timestamp"] = iso_format(before_now(seconds=31))
        event_data_3["event_id"] = "f" * 32

        transaction_event_1 = self.create_performance_issue(
            event_data=event_data_1, fingerprint=group_fingerprint
        )
        self.create_performance_issue(event_data=event_data_2, fingerprint=group_fingerprint)
        self.create_performance_issue(event_data=event_data_3, fingerprint=group_fingerprint)

        perf_group = transaction_event_1.group

        assert perf_group.get_latest_event_for_environments().event_id == "d" * 32
        assert perf_group.get_oldest_event_for_environments().event_id == "f" * 32

    def test_error_issue_get_helpful_for_environments(self):
        project = self.create_project()
        min_ago = iso_format(before_now(minutes=1))
        replay_id = uuid.uuid4().hex

        event_all_helpful_params = self.store_event(
            data={
                "event_id": "a" * 32,
                "timestamp": min_ago,
                "fingerprint": ["group-1"],
                "contexts": {
                    "replay": {"replay_id": replay_id},
                    "trace": {
                        "sampled": True,
                        "span_id": "babaae0d4b7512d9",
                        "trace_id": "a7d67cf796774551a95be6543cacd459",
                    },
                },
                "errors": [],
            },
            project_id=project.id,
            assert_no_errors=False,
        )
        self.store_event(
            data={
                "event_id": "b" * 32,
                "timestamp": min_ago,
                "fingerprint": ["group-1"],
                "contexts": {
                    "replay": {"replay_id": replay_id},
                },
                "errors": [{"type": "one"}, {"type": "two"}],
            },
            project_id=project.id,
            assert_no_errors=False,
        )
        event_none_helpful_params = self.store_event(
            data={"event_id": "c" * 32, "timestamp": min_ago, "fingerprint": ["group-1"]},
            project_id=project.id,
        )

        group = Group.objects.first()
        assert (
            group.get_recommended_event_for_environments().event_id
            == event_all_helpful_params.event_id
        )
        assert (
            group.get_latest_event_for_environments().event_id == event_none_helpful_params.event_id
        )
        assert (
            group.get_oldest_event_for_environments().event_id == event_all_helpful_params.event_id
        )

    def test_perf_issue_helpful(self):
        group_fingerprint = f"{PerformanceNPlusOneGroupType.type_id}-group1"

        transaction_event_data_with_all_helpful = load_data(
            "transaction-n-plus-one", fingerprint=[group_fingerprint]
        )
        transaction_event_data_with_all_helpful["timestamp"] = iso_format(before_now(seconds=10))
        transaction_event_data_with_all_helpful["start_timestamp"] = iso_format(
            before_now(seconds=11)
        )
        transaction_event_data_with_all_helpful["event_id"] = "d" * 32
        transaction_event_data_with_all_helpful["contexts"].update(
            {"profile": {"profile_id": uuid.uuid4().hex}}
        )
        transaction_event_data_with_all_helpful["contexts"].update(
            {"replay": {"replay_id": uuid.uuid4().hex}}
        )
        transaction_event_data_with_all_helpful["contexts"]["trace"]["sampled"] = True
        transaction_event_data_with_all_helpful["errors"] = []

        transaction_event_data_with_none_helpful = load_data(
            "transaction-n-plus-one", fingerprint=[group_fingerprint]
        )
        transaction_event_data_with_none_helpful["timestamp"] = iso_format(before_now(seconds=20))
        transaction_event_data_with_none_helpful["start_timestamp"] = iso_format(
            before_now(seconds=21)
        )
        transaction_event_data_with_none_helpful["event_id"] = "f" * 32

        transaction_event_1 = self.create_performance_issue(
            event_data=transaction_event_data_with_all_helpful, fingerprint=group_fingerprint
        )
        transaction_event_2 = self.create_performance_issue(
            event_data=transaction_event_data_with_none_helpful, fingerprint=group_fingerprint
        )

        perf_group = transaction_event_1.group

        assert (
            perf_group.get_recommended_event_for_environments().event_id
            == transaction_event_1.event_id
        )
        assert (
            perf_group.get_latest_event_for_environments().event_id == transaction_event_1.event_id
        )
        assert (
            perf_group.get_oldest_event_for_environments().event_id == transaction_event_2.event_id
        )

    def test_profile_issue_helpful(self):
        event_id_1 = uuid.uuid4().hex
        occurrence, _ = self.process_occurrence(
            event_id=event_id_1,
            project_id=self.project.id,
            event_data={
                "fingerprint": ["group-1"],
                "timestamp": before_now(minutes=2).isoformat(),
                "contexts": {
                    "profile": {"profile_id": uuid.uuid4().hex},
                    "replay": {"replay_id": uuid.uuid4().hex},
                    "trace": {
                        "sampled": True,
                        "span_id": "babaae0d4b7512d9",
                        "trace_id": "a7d67cf796774551a95be6543cacd459",
                    },
                },
                "errors": [],
            },
        )

        event_id_2 = uuid.uuid4().hex
        occurrence_2, _ = self.process_occurrence(
            event_id=event_id_2,
            project_id=self.project.id,
            event_data={
                "fingerprint": ["group-1"],
                "timestamp": before_now(minutes=1).isoformat(),
            },
        )

        group = Group.objects.first()
        group.update(type=ProfileFileIOGroupType.type_id)

        group_event = group.get_recommended_event_for_environments()
        assert group_event.event_id == occurrence.event_id
        self.assert_occurrences_identical(group_event.occurrence, occurrence)

        assert group.get_latest_event_for_environments().event_id == occurrence_2.event_id
        assert group.get_oldest_event_for_environments().event_id == occurrence.event_id

    @patch("sentry.quotas.backend.get_event_retention")
    def test_get_recommended_event_for_environments_retention_limit(self, mock_get_event_retention):
        """
        If last_seen is outside of the retention limit, falls back to the latest event behavior.
        """
        mock_get_event_retention.return_value = 90
        project = self.create_project()
        outside_retention_date = before_now(days=91)

        event = self.store_event(
            data={
                "event_id": "a" * 32,
                "timestamp": iso_format(outside_retention_date),
                "fingerprint": ["group-1"],
                "contexts": {},
                "errors": [],
            },
            project_id=project.id,
            assert_no_errors=False,
        )

        group = Group.objects.first()
        group.last_seen = before_now(days=91)
        assert group.get_recommended_event_for_environments().event_id == event.event_id