from django.db import connection
from django.test import override_settings

from saas.test import SaasTestCase
from tests.demo_app.models import UserConfig, UserNote, UserSecret


class TestUserSecrets(SaasTestCase):
    user_id = SaasTestCase.GUEST_USER_ID

    def get_db_value(self, table: str, field: str, model_id: int):
        cursor = connection.cursor()
        cursor.execute(f'select {field} from {table} where id = {model_id};')
        return cursor.fetchone()[0]

    def test_create_user_secrets(self):
        obj = UserSecret(secret_key=b'test')
        obj.save()
        self.assertEqual(obj.secret_key, b'test')

        db_value = self.get_db_value('demo_app_usersecret', 'secret_key', obj.pk)
        self.assertEqual(len(db_value.split('.')), 5)

    def test_create_none_value(self):
        obj = UserSecret(secret_key=None)
        obj.save()
        self.assertIsNone(obj.secret_key)

        db_value = self.get_db_value('demo_app_usersecret', 'secret_key', obj.pk)
        self.assertIsNone(db_value)

    def test_invalid_type_error(self):
        obj = UserSecret(secret_key='string_not_bytes')
        with self.assertRaises(TypeError):
            obj.save()

    def test_clean_method(self):
        field = UserSecret._meta.get_field('secret_key')
        obj = UserSecret()
        res = field.clean(b'test', obj)
        self.assertEqual(res, b'test')

    def test_key_fallback(self):
        obj = UserSecret(secret_key=b'test')
        obj.save()
        self.assertEqual(obj.secret_key, b'test')

        with override_settings(SECRET_KEY='new-primary-key'):
            new_obj = UserSecret.objects.get(pk=obj.pk)
            # we cannot decrypt it
            self.assertIsNone(new_obj.secret_key)

        with override_settings(SECRET_KEY='new-primary-key', SECRET_KEY_FALLBACKS=['django-insecure']):
            fallback_obj = UserSecret.objects.get(pk=obj.pk)
            self.assertEqual(fallback_obj.secret_key, b'test')

    def test_encrypted_text_field(self):
        obj = UserNote(note='hello world')
        obj.save()
        self.assertEqual(obj.note, 'hello world')

        db_value = self.get_db_value('demo_app_usernote', 'note', obj.pk)
        self.assertEqual(len(db_value.split('.')), 5)

        new_obj = UserNote.objects.get(pk=obj.pk)
        self.assertEqual(new_obj.note, 'hello world')

    def test_encrypted_text_field_none(self):
        obj = UserNote(note=None)
        obj.save()
        self.assertIsNone(obj.note)

    def test_encrypted_json_field(self):
        data = {'a': 1, 'b': [1, 2, 3], 'c': {'d': 'e'}}
        obj = UserConfig(config=data)
        obj.save()
        self.assertEqual(obj.config, data)

        db_value = self.get_db_value('demo_app_userconfig', 'config', obj.pk)
        self.assertEqual(len(db_value.split('.')), 5)

        new_obj = UserConfig.objects.get(pk=obj.pk)
        self.assertEqual(new_obj.config, data)

    def test_encrypted_json_field_none(self):
        obj = UserConfig(config=None)
        obj.save()
        self.assertIsNone(obj.config)
