from django.test import TestCase

from tordonate.containers import Container
from tordonate.forms import CryptocurrencyForm


# When testing the donation form, be mindful of the fact that it expresses donation values in
# whole dollars, whereas the rest of the infrastructure keeps dollar amounts in cents.
# It is good practice to refrain from using hardcoded values in these tests, so that changing
# donation and perk minimums are automatically reflected in these test cases, so
# be mindful of how DonorInfoFormTests.setUp pulls values directly from civicrm.repository
# (which itself gets them fresh from source) and converts them for proper use in testing here.
class BTCPayFormTests(TestCase):
    data = {
        "custom_donation": 25,
    }

    def setUp(self) -> None:
        container = Container()
        self.civi = container.civi()
        # For testing custom_donation amounts at or just around minimum values
        # (because, again, data.custom_donation is an expression of dollars
        # and most stored money values are expressed as cents).
        # We ignore typing on these calls because Mypy gets confused by the conversion performed
        # by tordonate.utils.WithSyncMeta - which provides the below sync versions of async calls.
        # (This is not the only place where typing on these values is enforced, and if they are
        # incorrect then the build will not pass testing, so this is not as unsafe as it appears.)
        self.minimum_donation = self.civi.minimum_donation_sync() / 100  # type: ignore

    def test_form_validation(self) -> None:
        form = CryptocurrencyForm(data=self.data)
        self.assertTrue(form.is_valid())

    def test_form_minimum_donation(self) -> None:
        form = CryptocurrencyForm(
            data={
                **self.data,
                "custom_donation": self.minimum_donation,
            }
        )
        self.assertTrue(form.is_valid())
        self.assertIsNone(form.errors.get("__all__"))

    def test_form_insufficient_donation_amount(self) -> None:
        form = CryptocurrencyForm(
            data={
                **self.data,
                "custom_donation": self.minimum_donation - 1,
            }
        )
        self.assertFalse(form.is_valid())
        self.assertIsNotNone(form.errors.get("__all__"))

    def test_form_invalid_donation_amount(self) -> None:
        form = CryptocurrencyForm(
            data={
                **self.data,
                "custom_donation": "five dollars",
            }
        )
        self.assertFalse(form.is_valid())
        self.assertIsNotNone(form.errors.get("__all__"))
