"""
dj-stripe Webhook Tests.
"""
import json
import warnings
from collections import defaultdict
from copy import deepcopy
from unittest.mock import Mock, PropertyMock, call, patch
from uuid import UUID

import pytest
from django.test import TestCase, override_settings
from django.test.client import Client
from django.urls import reverse

from djstripe import webhooks
from djstripe.models import Event, Transfer, WebhookEventTrigger
from djstripe.models.webhooks import WebhookEndpoint, get_remote_ip
from djstripe.settings import djstripe_settings
from djstripe.webhooks import TEST_EVENT_ID, call_handlers, handler, handler_all

from . import (
    FAKE_CUSTOM_ACCOUNT,
    FAKE_EVENT_TEST_CHARGE_SUCCEEDED,
    FAKE_EVENT_TRANSFER_CREATED,
    FAKE_STANDARD_ACCOUNT,
    FAKE_TRANSFER,
    FAKE_WEBHOOK_ENDPOINT_1,
    IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
)

pytestmark = pytest.mark.django_db


def mock_webhook_handler(webhook_event_trigger):
    webhook_event_trigger.process()


class TestWebhookEventTrigger(TestCase):
    """Test class to test WebhookEventTrigger model and its methods"""

    def _send_event(self, event_data):
        return Client().post(
            reverse("djstripe:webhook"),
            json.dumps(event_data),
            content_type="application/json",
            HTTP_STRIPE_SIGNATURE="PLACEHOLDER",
        )

    def test_webhook_test_event(self):
        self.assertEqual(WebhookEventTrigger.objects.count(), 0)
        resp = self._send_event(FAKE_EVENT_TEST_CHARGE_SUCCEEDED)
        self.assertEqual(resp.status_code, 200)
        self.assertFalse(Event.objects.filter(id=TEST_EVENT_ID).exists())
        self.assertEqual(WebhookEventTrigger.objects.count(), 1)
        event_trigger = WebhookEventTrigger.objects.first()
        self.assertTrue(event_trigger.is_test_event)

    def test___str__(self):
        self.assertEqual(WebhookEventTrigger.objects.count(), 0)
        resp = self._send_event(FAKE_EVENT_TEST_CHARGE_SUCCEEDED)
        self.assertEqual(resp.status_code, 200)
        self.assertEqual(WebhookEventTrigger.objects.count(), 1)
        webhookeventtrigger = WebhookEventTrigger.objects.first()

        self.assertEqual(
            f"id={webhookeventtrigger.id}, valid={webhookeventtrigger.valid}, processed={webhookeventtrigger.processed}",
            str(webhookeventtrigger),
        )

    @override_settings(DJSTRIPE_WEBHOOK_VALIDATION="retrieve_event")
    @patch.object(Transfer, "_attach_objects_post_save_hook")
    @patch(
        "stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True
    )
    @patch(
        "stripe.Event.retrieve",
        return_value=deepcopy(FAKE_EVENT_TRANSFER_CREATED),
        autospec=True,
    )
    def test_webhook_retrieve_event_fail(
        self,
        event_retrieve_mock,
        transfer_retrieve_mock,
        transfer__attach_object_post_save_hook_mock,
    ):

        invalid_event = deepcopy(FAKE_EVENT_TRANSFER_CREATED)
        invalid_event["id"] = "evt_invalid"
        invalid_event["data"]["valid"] = "not really"

        resp = self._send_event(invalid_event)

        self.assertEqual(resp.status_code, 400)
        self.assertFalse(Event.objects.filter(id="evt_invalid").exists())

    @patch.object(
        WebhookEventTrigger.validate,
        "__defaults__",
        (None, "whsec_XXXXX", 300, "retrieve_event"),
    )
    @patch.object(Transfer, "_attach_objects_post_save_hook")
    @patch(
        "stripe.Account.retrieve",
        return_value=deepcopy(FAKE_STANDARD_ACCOUNT),
        autospec=IS_STATICMETHOD_AUTOSPEC_SUPPORTED,
    )
    @patch(
        "stripe.Transfer.retrieve", return_value=deepcopy(FAKE_TRANSFER), autospec=True