"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 21.08.23

"""
from django.core.exceptions import ObjectDoesNotExist
from django.test import RequestFactory
from django.utils.translation import gettext_lazy as _

from codelist.models import KonovaCodeList
from codelist.settings import CODELIST_COMPENSATION_ACTION_ID, CODELIST_BIOTOPES_ID
from compensation.forms.modals.compensation_action import NewCompensationActionModalForm, \
    EditCompensationActionModalForm, RemoveCompensationActionModalForm
from compensation.forms.modals.state import NewCompensationStateModalForm, EditCompensationStateModalForm, \
    RemoveCompensationStateModalForm
from compensation.models import UnitChoices
from konova.tests.test_views import BaseTestCase
from konova.utils.generators import generate_random_string
from konova.utils.message_templates import COMPENSATION_ACTION_EDITED, ADDED_COMPENSATION_ACTION, \
    COMPENSATION_ACTION_REMOVED, ADDED_COMPENSATION_STATE, COMPENSATION_STATE_EDITED, \
    COMPENSATION_STATE_REMOVED
from user.models import UserAction


class NewCompensationActionModalFormTestCase(BaseTestCase):

    def setUp(self) -> None:
        super().setUp()
        self.request = RequestFactory().request()
        self.request.user = self.superuser

        self.action_dummy_code = self.create_dummy_codes().first()
        action_list = KonovaCodeList.objects.get_or_create(
            id=CODELIST_COMPENSATION_ACTION_ID,
        )[0]
        action_list.codes.add(self.action_dummy_code)

    def test_init(self):
        form = NewCompensationActionModalForm()
        self.assertEqual(form.form_title, str(_("New action")))
        self.assertEqual(form.form_caption, str(_("Insert data for the new action")))
        self.assertTrue(len(form.fields["action_type"].choices) == 1)

    def test_save(self):
        comment = "TEST_comment"
        unit = UnitChoices.km
        amount = 2.5

        data = {
            "action_type": [self.action_dummy_code.id],
            "action_type_details": [],
            "unit": unit,
            "amount": amount,
            "comment": comment,
        }
        form = NewCompensationActionModalForm(data, request=self.request, instance=self.compensation)
        self.assertTrue(form.is_valid(), msg=form.errors)

        comp_action = form.save()
        last_log = self.compensation.log.first()
        self.assertIn(comp_action, self.compensation.actions.all())
        self.assertEqual(last_log.action, UserAction.EDITED)
        self.assertEqual(last_log.user, self.superuser)
        self.assertEqual(last_log.comment, ADDED_COMPENSATION_ACTION)
        self.assertEqual(comp_action.amount, amount)
        self.assertEqual(comp_action.unit, unit)
        self.assertEqual(comp_action.comment, comment)
        comp_action_types = comp_action.action_type.all()
        self.assertEqual(comp_action_types.count(), 1)
        self.assertEqual(comp_action_types.first(), self.action_dummy_code)


class EditCompensationActionModalFormTestCase(NewCompensationActionModalFormTestCase):

    def setUp(self) -> None:
        super().setUp()
        self.comp_action = self.create_dummy_action()
        self.compensation.actions.add(self.comp_action)

    def test_init(self):
        form = EditCompensationActionModalForm(request=self.request, instance=self.compensation, action=self.comp_action)
        self.assertEqual(form.form_title, str(_("Edit action")))
        self.assertEqual(len(form.fields["action_type"].initial), self.comp_action.action_type.count())
        self.assertEqual(len(form.fields["action_type_details"].initial), self.comp_action.action_type_details.count())
        self.assertEqual(form.fields["amount"].initial, self.comp_action.amount)
        self.assertEqual(form.fields["unit"].initial, self.comp_action.unit)
        self.assertEqual(form.fields["comment"].initial, self.comp_action.comment)

    def test_save(self):
        amount = 25.4
        unit = UnitChoices.cm
        comment = generate_random_string(length=20, use_numbers=True, use_letters_lc=True, use_letters_uc=True)

        data = {
            "action_type": [self.action_dummy_code.id],
            "action_type_details": [],
            "amount": amount,
            "unit": unit,
            "comment": comment,
        }

        form = EditCompensationActionModalForm(data, request=self.request, instance=self.compensation, action=self.comp_action)

        self.assertTrue(form.is_valid())
        action = form.save()

        self.assertEqual(action.action_type.count(), len(data["action_type"]))
        self.assertEqual(action.action_type_details.count(), 0)
        self.assertEqual(float(action.amount), amount)
        self.assertEqual(action.unit, unit)
        self.assertEqual(action.comment, comment)

        last_log = self.compensation.log.first()
        self.assertEqual(last_log.action, UserAction.EDITED)
        self.assertEqual(last_log.user, self.superuser)
        self.assertEqual(last_log.comment, COMPENSATION_ACTION_EDITED)
        self.assertIn(action, self.compensation.actions.all())
        self.assertEqual(self.compensation.actions.count(), 1)


class RemoveCompensationActionModalFormTestCase(EditCompensationActionModalFormTestCase):
    def setUp(self) -> None:
        super().setUp()
        
    def test_init(self):
        self.assertIn(self.comp_action, self.compensation.actions.all())
        form = RemoveCompensationActionModalForm(request=self.request, instance=self.compensation, action=self.comp_action)
        self.assertEqual(form.action, self.comp_action)
        
    def test_save(self):
        data = {
            "confirm": True,
        }
        form = RemoveCompensationActionModalForm(
            data, 
            request=self.request,
            instance=self.compensation,
            action=self.comp_action
        )
        self.assertTrue(form.is_valid())
        self.assertIn(self.comp_action, self.compensation.actions.all())

        form.save()

        last_log = self.compensation.log.first()
        self.assertEqual(last_log.action, UserAction.EDITED)
        self.assertEqual(last_log.user, self.superuser)
        self.assertEqual(last_log.comment, COMPENSATION_ACTION_REMOVED)

        self.assertNotIn(self.comp_action, self.compensation.actions.all())
        try:
            self.comp_action.refresh_from_db()
            self.fail(msg="This action should not be fetchable anymore")
        except ObjectDoesNotExist:
            pass


class NewCompensationStateModalFormTestCase(BaseTestCase):
    def setUp(self) -> None:
        super().setUp()
        self.request = RequestFactory().request()
        self.request.user = self.superuser

        self.comp_biotope_code = self.create_dummy_codes().first()
        self.biotope_codelist = KonovaCodeList.objects.get_or_create(
            id=CODELIST_BIOTOPES_ID
        )[0]
        self.biotope_codelist.codes.add(self.comp_biotope_code)

    def test_init(self):
        form = NewCompensationStateModalForm(request=self.request, instance=self.compensation)

        self.assertEqual(form.form_title, str(_("New state")))
        self.assertEqual(form.form_caption, str(_("Insert data for the new state")))
        self.assertEqual(len(form.fields["biotope_type"].choices), 1)

    def test_save(self):
        test_surface = 123.45
        data = {
            "biotope_type": self.comp_biotope_code.id,
            "biotope_extra": [],
            "surface": test_surface,
        }
        self.assertEqual(self.compensation.before_states.count(), 0)
        self.assertEqual(self.compensation.after_states.count(), 0)

        form = NewCompensationStateModalForm(data, request=self.request, instance=self.compensation)

        self.assertTrue(form.is_valid(), msg=form.errors)

        is_before_state = True
        state = form.save(is_before_state)

        self.assertEqual(self.compensation.before_states.count(), 1)
        self.assertEqual(self.compensation.after_states.count(), 0)
        self.assertIn(state, self.compensation.before_states.all())
        self.assertEqual(state.biotope_type, self.comp_biotope_code)
        self.assertEqual(state.biotope_type_details.count(), 0)
        self.assertEqual(float(state.surface), test_surface)

        last_log = self.compensation.log.first()
        self.assertEqual(last_log.user, self.superuser)
        self.assertEqual(last_log.action, UserAction.EDITED)
        self.assertEqual(last_log.comment, ADDED_COMPENSATION_STATE)

        is_before_state = False
        state = form.save(is_before_state)

        self.assertEqual(self.compensation.before_states.count(), 1)
        self.assertEqual(self.compensation.after_states.count(), 1)
        self.assertIn(state, self.compensation.after_states.all())
        self.assertEqual(state.biotope_type, self.comp_biotope_code)
        self.assertEqual(state.biotope_type_details.count(), 0)
        self.assertEqual(float(state.surface), test_surface)

        last_log = self.compensation.log.first()
        self.assertEqual(last_log.user, self.superuser)
        self.assertEqual(last_log.action, UserAction.EDITED)
        self.assertEqual(last_log.comment, ADDED_COMPENSATION_STATE)


class EditCompensationStateModalFormTestCase(NewCompensationStateModalFormTestCase):
    def setUp(self) -> None:
        super().setUp()
        self.comp_state.biotope_type = self.comp_biotope_code
        self.comp_state.save()

        self.compensation.after_states.add(self.comp_state)

    def test_init(self):
        form = EditCompensationStateModalForm(request=self.request, instance=self.compensation, state=self.comp_state)

        self.assertEqual(form.state, self.comp_state)
        self.assertEqual(form.form_title, str(_("Edit state")))
        self.assertEqual(form.fields["biotope_type"].initial, self.comp_state.biotope_type.id)
        self.assertTrue(
            form.fields["biotope_extra"].initial.difference(
                self.comp_state.biotope_type_details.all()
            ).count() == 0
        )
        self.assertEqual(form.fields["surface"].initial, self.comp_state.surface)

    def test_save(self):
        test_surface = 987.65
        test_code = self.create_dummy_codes().exclude(
            id=self.comp_biotope_code.id
        ).first()
        self.biotope_codelist.codes.add(test_code)

        self.assertEqual(self.compensation.after_states.count(), 1)
        self.assertEqual(self.compensation.before_states.count(), 0)

        data = {
            "biotope_type": test_code.id,
            "biotope_extra": [],
            "surface": test_surface,
        }
        form = EditCompensationStateModalForm(
            data,
            request=self.request,
            instance=self.compensation,
            state=self.comp_state
        )
        self.assertTrue(form.is_valid(), msg=form.errors)

        is_before_state = False
        state = form.save(is_before_state=is_before_state)
        self.assertEqual(state.biotope_type, test_code)
        self.assertEqual(state.biotope_type_details.count(), 0)
        self.assertEqual(float(state.surface), test_surface)

        last_log = self.compensation.log.first()
        self.assertEqual(last_log.action, UserAction.EDITED)
        self.assertEqual(last_log.user, self.superuser)
        self.assertEqual(last_log.comment, COMPENSATION_STATE_EDITED)


class RemoveCompensationStateModalFormTestCase(EditCompensationStateModalFormTestCase):
    def setUp(self) -> None:
        super().setUp()

    def test_init(self):
        form = RemoveCompensationStateModalForm(request=self.request, instance=self.compensation, state=self.comp_state)

        self.assertEqual(form.state, self.comp_state)

    def test_save(self):
        data = {
            "confirm": True
        }
        form = RemoveCompensationStateModalForm(
            data,
            request=self.request,
            instance=self.compensation,
            state=self.comp_state
        )
        self.assertTrue(form.is_valid(), msg=form.errors)

        self.assertIn(self.comp_state, self.compensation.after_states.all())
        self.assertNotIn(self.comp_state, self.compensation.before_states.all())

        form.save()

        self.assertEqual(self.compensation.after_states.count(), 0)
        self.assertEqual(self.compensation.before_states.count(), 0)
        try:
            self.comp_state.refresh_from_db()
            self.fail("Entry should not existing anymore")
        except ObjectDoesNotExist:
            pass

        last_log = self.compensation.log.first()
        self.assertEqual(last_log.user, self.superuser)
        self.assertEqual(last_log.action, UserAction.EDITED)
        self.assertEqual(last_log.comment, COMPENSATION_STATE_REMOVED)

