from uuid import uuid4
import os
import base64
from io import BytesIO as StringIO

from PIL import Image
from django.test import TestCase, override_settings
from django.urls import reverse
from rest_captcha.serializers import RestCaptchaSerializer
from django.core.cache import cache

from .settings import api_settings
from . import utils


class RestCaptchaTests(TestCase):
    def test_views(self):
        result = self.client.post(reverse("rest_captcha")).json()
        assert "captcha_key" in result
        assert "captcha_image" in result
        assert base64.b64decode(result["captcha_image"])

    def test_validation_valid1(self):
        result = self.client.post(reverse("rest_captcha")).json()
        key = utils.get_cache_key(result["captcha_key"])
        value = cache.get(key)

        data = dict(captcha_key=result["captcha_key"], captcha_value=value)
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is True

    def test_validation_valid2(self):
        result = self.client.post(reverse("rest_captcha")).json()
        key = utils.get_cache_key(result["captcha_key"])
        cache.set(key, "GOOD")

        data = dict(captcha_key=result["captcha_key"], captcha_value="GoOD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is True

    def test_validation_empty_value(self):
        result = self.client.post(reverse("rest_captcha")).json()

        data = dict(captcha_key=result["captcha_key"], captcha_value="")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is False

    def test_validation_second_try(self):
        result = self.client.post(reverse("rest_captcha")).json()
        key = utils.get_cache_key(result["captcha_key"])
        cache.set(key, "GOOD")

        data = dict(captcha_key=result["captcha_key"], captcha_value="BAD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is False

        # second try with GOOD VAL
        data = dict(captcha_key=result["captcha_key"], captcha_value="GOOD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is False

    def test_validation_with_broken_keys(self):
        data = dict(captcha_key=str(uuid4()), captcha_value_123="ABCD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is False
        self.assertDictEqual(
            serial.errors, {"captcha_value": ["This field is required."]}
        )

    def test_validation_with_undefined_key(self):
        data = dict(captcha_key=str(uuid4()), captcha_value="ABCD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is False
        assert "non_field_errors" in serial.errors
        self.assertEqual(
            "Invalid or expired captcha key", str(serial.errors["non_field_errors"][0])
        )

    def test_validation_with_broken_value(self):
        result = self.client.post(reverse("rest_captcha")).json()
        data = dict(captcha_key=result["captcha_key"], captcha_value="ABCD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is False
        self.assertDictEqual(
            serial.errors, {"non_field_errors": ["Invalid captcha value"]}
        )


@override_settings()
class ImageGenTests(TestCase):
    def test_change_image_size(self):
        result = self.client.post(reverse("rest_captcha")).json()
        image_bytes = base64.b64decode(result["captcha_image"])
        image = Image.open(StringIO(image_bytes))
        assert image.size == api_settings.CAPTCHA_IMAGE_SIZE

        api_settings.CAPTCHA_IMAGE_SIZE = (251, 144)
        result = self.client.post(reverse("rest_captcha")).json()
        image_bytes = base64.b64decode(result["captcha_image"])
        image = Image.open(StringIO(image_bytes))
        assert image.size == api_settings.CAPTCHA_IMAGE_SIZE

    def test_image(self):
        api_settings.CAPTCHA_IMAGE_SIZE = (100, 50)
        api_settings.CAPTCHA_LETTER_ROTATION = None
        utils.random_char_challenge = lambda x: "CAPTCHA"
        api_settings.FILTER_FUNCTION = lambda x: x
        api_settings.NOISE_FUNCTION = lambda x, y: x

        result = self.client.post(reverse("rest_captcha")).json()
        fname = "captcha.png"
        path = os.path.join(os.path.dirname(__file__), fname)
        image = base64.b64decode(result["captcha_image"])
        # with open('captcha_py3.png', 'wb') as f:
        #     f.write(image)
        image2 = open(path, "rb").read()
        assert image2 == image

    def test_master_captcha(self):
        api_settings.MASTER_CAPTCHA = {"master_key": "GOOD"}
        data = dict(captcha_key="master_key", captcha_value="BAD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is False

        data = dict(captcha_key="master_key", captcha_value="GOOD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is True

from uuid import uuid4
import os
import base64
from io import BytesIO as StringIO

from PIL import Image
from django.test import TestCase, override_settings
from django.urls import reverse
from rest_captcha.serializers import RestCaptchaSerializer
from django.core.cache import cache

from .settings import api_settings
from . import utils


class RestCaptchaTests(TestCase):
    def test_views(self):
        result = self.client.post(reverse("rest_captcha")).json()
        assert "captcha_key" in result
        assert "captcha_image" in result
        assert base64.b64decode(result["captcha_image"])

    def test_validation_valid1(self):
        result = self.client.post(reverse("rest_captcha")).json()
        key = utils.get_cache_key(result["captcha_key"])
        value = cache.get(key)

        data = dict(captcha_key=result["captcha_key"], captcha_value=value)
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is True

    def test_validation_valid2(self):
        result = self.client.post(reverse("rest_captcha")).json()
        key = utils.get_cache_key(result["captcha_key"])
        cache.set(key, "GOOD")

        data = dict(captcha_key=result["captcha_key"], captcha_value="GoOD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is True

    def test_validation_empty_value(self):
        result = self.client.post(reverse("rest_captcha")).json()

        data = dict(captcha_key=result["captcha_key"], captcha_value="")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is False

    def test_validation_second_try(self):
        result = self.client.post(reverse("rest_captcha")).json()
        key = utils.get_cache_key(result["captcha_key"])
        cache.set(key, "GOOD")

        data = dict(captcha_key=result["captcha_key"], captcha_value="BAD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is False

        # second try with GOOD VAL
        data = dict(captcha_key=result["captcha_key"], captcha_value="GOOD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is False

    def test_validation_with_broken_keys(self):
        data = dict(captcha_key=str(uuid4()), captcha_value_123="ABCD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is False
        self.assertDictEqual(
            serial.errors, {"captcha_value": ["This field is required."]}
        )

    def test_validation_with_undefined_key(self):
        data = dict(captcha_key=str(uuid4()), captcha_value="ABCD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is False
        assert "non_field_errors" in serial.errors
        self.assertEqual(
            "Invalid or expired captcha key", str(serial.errors["non_field_errors"][0])
        )

    def test_validation_with_broken_value(self):
        result = self.client.post(reverse("rest_captcha")).json()
        data = dict(captcha_key=result["captcha_key"], captcha_value="ABCD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is False
        self.assertDictEqual(
            serial.errors, {"non_field_errors": ["Invalid captcha value"]}
        )


@override_settings()
class ImageGenTests(TestCase):
    def test_change_image_size(self):
        result = self.client.post(reverse("rest_captcha")).json()
        image_bytes = base64.b64decode(result["captcha_image"])
        image = Image.open(StringIO(image_bytes))
        assert image.size == api_settings.CAPTCHA_IMAGE_SIZE

        api_settings.CAPTCHA_IMAGE_SIZE = (251, 144)
        result = self.client.post(reverse("rest_captcha")).json()
        image_bytes = base64.b64decode(result["captcha_image"])
        image = Image.open(StringIO(image_bytes))
        assert image.size == api_settings.CAPTCHA_IMAGE_SIZE

    def test_image(self):
        api_settings.CAPTCHA_IMAGE_SIZE = (100, 50)
        api_settings.CAPTCHA_LETTER_ROTATION = None
        utils.random_char_challenge = lambda x: "CAPTCHA"
        api_settings.FILTER_FUNCTION = lambda x: x
        api_settings.NOISE_FUNCTION = lambda x, y: x

        result = self.client.post(reverse("rest_captcha")).json()
        fname = "captcha.png"
        path = os.path.join(os.path.dirname(__file__), fname)
        image = base64.b64decode(result["captcha_image"])
        # with open('captcha_py3.png', 'wb') as f:
        #     f.write(image)
        image2 = open(path, "rb").read()
        assert image2 == image

    def test_master_captcha(self):
        api_settings.MASTER_CAPTCHA = {"master_key": "GOOD"}
        data = dict(captcha_key="master_key", captcha_value="BAD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is False

        data = dict(captcha_key="master_key", captcha_value="GOOD")
        serial = RestCaptchaSerializer(data=data)
        assert serial.is_valid() is True

# second try with GOOD VAL # with open('captcha_py3.png', 'wb') as f: #     f.write(image)