# (c) cavaliba.com - tests / views / admintools keyname rename - real run

from django.core.cache import cache as cache_django
from django.test import TestCase, override_settings
from django.urls import reverse

import app_home.cache as cache
from app_data.data import Instance
from app_data.models import DataInstance
from tests import helper

URL = "app_home:admintools_keyname"


@override_settings(CAVALIBA_AUTH_MODE="unittest")
class TestAdmintoolsKeynameRealrun(TestCase):
    def setUp(self):
        cache.clear()
        cache_django.clear()
        helper.add_admin_user(login="unittest")
        helper.add_schema("tkn_target", displayname="Target Schema")
        helper.add_schema(
            "tkn_ref",
            displayname="Referrer Schema",
            field_definition={
                "ref_target": {
                    "dataformat": "schema",
                    "dataformat_ext": "tkn_target",
                    "cardinal_max": 1,
                }
            },
        )
        helper.add_instance("tkn_target", "old_key")
        helper.add_instance("tkn_ref", "ref01", fields={"ref_target": "old_key"})

    def _post(self, extra=None):
        data = {
            "mode": "real",
            "classname": "tkn_target",
            "oldkeyname": "old_key",
            "newkeyname": "new_key",
        }
        if extra:
            data.update(extra)
        return self.client.post(reverse(URL), data, follow=True)

    def test_real_run_renames_target(self):
        response = self._post()
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Rename result", status_code=200)
        self.assertFalse(
            DataInstance.objects.filter(classname="tkn_target", keyname="old_key").exists()
        )
        self.assertTrue(
            DataInstance.objects.filter(classname="tkn_target", keyname="new_key").exists()
        )

    def test_real_run_cascades_to_referrer(self):
        self._post()
        referrer = Instance.from_keyname(classname="tkn_ref", keyname="ref01")
        self.assertEqual(referrer.fields["ref_target"].value, ["new_key"])

    def test_real_run_shows_success_message(self):
        response = self._post()
        self.assertContains(response, "Keyname renamed", status_code=200)

    def test_real_run_clears_the_form_after_success(self):
        response = self._post()
        self.assertNotContains(response, 'value="old_key"', status_code=200)

    def test_real_run_on_missing_instance_writes_nothing(self):
        response = self._post({"oldkeyname": "nope"})
        self.assertContains(response, "instance not found", status_code=200)
        self.assertTrue(
            DataInstance.objects.filter(classname="tkn_target", keyname="old_key").exists()
        )
        self.assertFalse(
            DataInstance.objects.filter(classname="tkn_target", keyname="new_key").exists()
        )

    def test_real_run_on_taken_keyname_writes_nothing(self):
        # the mandatory pre-flight dry run must catch this before any write
        helper.add_instance("tkn_target", "taken_key")
        response = self._post({"newkeyname": "taken_key"})
        self.assertContains(response, "newkeyname already exists", status_code=200)
        self.assertTrue(
            DataInstance.objects.filter(classname="tkn_target", keyname="old_key").exists()
        )

    def test_real_run_on_derived_schema_needs_force(self):
        helper.add_user(login="renameme")
        response = self._post(
            {"classname": "user", "oldkeyname": "renameme", "newkeyname": "renamed"}
        )
        self.assertContains(response, "derived schema", status_code=200)
        self.assertTrue(DataInstance.objects.filter(classname="user", keyname="renameme").exists())

    def test_real_run_on_derived_schema_with_force_succeeds(self):
        helper.add_user(login="renameme")
        response = self._post(
            {
                "classname": "user",
                "oldkeyname": "renameme",
                "newkeyname": "renamed",
                "force": "true",
            }
        )
        self.assertContains(response, "Keyname renamed", status_code=200)
        self.assertFalse(DataInstance.objects.filter(classname="user", keyname="renameme").exists())
        self.assertTrue(DataInstance.objects.filter(classname="user", keyname="renamed").exists())

    def test_real_run_on_protected_identity_is_refused_even_with_force(self):
        response = self._post(
            {
                "classname": "role",
                "oldkeyname": "role_admin",
                "newkeyname": "role_boss",
                "force": "true",
            }
        )
        self.assertContains(response, "protected built-in identity", status_code=200)
        self.assertTrue(
            DataInstance.objects.filter(classname="role", keyname="role_admin").exists()
        )
