"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: michel.peltriaux@sgdnord.rlp.de
Created on: 08.02.22

"""
import datetime

from django.contrib.gis.geos import MultiPolygon
from django.core.exceptions import ObjectDoesNotExist
from django.urls import reverse

from ema.models import Ema
from konova.settings import ETS_GROUP
from konova.tests.test_views import BaseWorkflowTestCase
from user.models import UserAction


class EmaWorkflowTestCase(BaseWorkflowTestCase):
    ema = None

    @classmethod
    def setUpTestData(cls) -> None:
        super().setUpTestData()

    def setUp(self) -> None:
        super().setUp()
        # Create a fresh dummy (non-valid) compensation before each test
        self.ema = self.create_dummy_ema()

    def test_new(self):
        """ Test the creation of an Ema

        Returns:

        """
        self.superuser.groups.add(self.groups.get(name=ETS_GROUP))
        # Prepare url and form data to be posted
        new_url = reverse("ema:new")
        test_id = self.create_dummy_string()
        test_title = self.create_dummy_string()
        test_geom = self.create_dummy_geometry()
        geom_json = self.create_geojson(test_geom)
        test_conservation_office = self.get_conservation_office_code()
        post_data = {
            "identifier": test_id,
            "title": test_title,
            "geom": geom_json,
            "conservation_office": test_conservation_office.id
        }
        self.client_user.post(new_url, post_data)

        try:
            ema = Ema.objects.get(
                identifier=test_id
            )
        except ObjectDoesNotExist:
            self.fail(msg="Ema not created")

        self.assertEqual(ema.identifier, test_id)
        self.assertEqual(ema.title, test_title)
        self.assert_equal_geometries(ema.geometry.geom, test_geom)
        self.assertEqual(ema.log.count(), 1)

        # Expect logs to be set
        self.assertEqual(ema.log.count(), 1)
        self.assertEqual(ema.log.first().action, UserAction.CREATED)

    def test_edit(self):
        """ Checks that the editing of an Ema works

        Returns:

        """
        self.superuser.groups.add(self.groups.get(name=ETS_GROUP))
        self.ema.users.add(self.superuser)
        url = reverse("ema:edit", args=(self.ema.id,))
        self.ema = self.fill_out_ema(self.ema)
        pre_edit_log_count = self.ema.log.count()

        new_title = self.create_dummy_string()
        new_identifier = self.create_dummy_string()
        new_comment = self.create_dummy_string()
        new_geometry = MultiPolygon(srid=4326)  # Create an empty geometry
        test_conservation_office = self.get_conservation_office_code()

        check_on_elements = {
            self.ema.title: new_title,
            self.ema.identifier: new_identifier,
            self.ema.comment: new_comment,
        }
        for k, v in check_on_elements.items():
            self.assertNotEqual(k, v)

        post_data = {
            "identifier": new_identifier,
            "title": new_title,
            "comment": new_comment,
            "geom": new_geometry.geojson,
            "conservation_office": test_conservation_office.id
        }
        self.client_user.post(url, post_data)
        self.ema.refresh_from_db()

        check_on_elements = {
            self.ema.title: new_title,
            self.ema.identifier: new_identifier,
            self.ema.comment: new_comment,
        }

        for k, v in check_on_elements.items():
            self.assertEqual(k, v)

        self.assert_equal_geometries(self.ema.geometry.geom, new_geometry)

        # Expect logs to be set
        self.assertEqual(pre_edit_log_count + 1, self.ema.log.count())
        self.assertEqual(self.ema.log.first().action, UserAction.EDITED)

    def test_non_editable_after_recording(self):
        """ Tests that the EMA can not be edited after being recorded

        User must be redirected to another page

        Returns:

        """
        self.superuser.groups.add(self.groups.get(name=ETS_GROUP))
        self.assertIsNotNone(self.ema)
        self.ema.share_with_user(self.superuser)
        self.assertFalse(self.ema.is_recorded)
        edit_url = reverse("ema:edit", args=(self.ema.id,))
        response = self.client_user.get(edit_url)
        has_redirect = response.status_code == 302
        self.assertFalse(has_redirect)

        self.ema.set_recorded(self.superuser)
        self.assertTrue(self.ema.is_recorded)

        edit_url = reverse("ema:edit", args=(self.ema.id,))
        response = self.client_user.get(edit_url)
        has_redirect = response.status_code == 302
        self.assertTrue(has_redirect)
        self.ema.set_unrecorded(self.superuser)
        
    def test_recordability(self):
        """
        This tests if the recordability of the Ema is triggered by the quality of it's data (e.g. not all fields filled)

        Returns:

        """
        # Add proper privilege for the user
        self.superuser.groups.add(self.groups.get(name=ETS_GROUP))
        self.ema.users.add(self.superuser)
        pre_record_log_count = self.ema.log.count()

        # Prepare url and form data
        record_url = reverse("ema:record", args=(self.ema.id,))
        post_data = {
            "confirm": True,
        }

        # Make sure the ema is not recorded
        self.assertIsNone(self.ema.recorded)

        # Run the request --> expect fail, since the Ema is not valid, yet
        self.client_user.post(record_url, post_data)

        # Check that the Ema is still not recorded
        self.assertIsNone(self.ema.recorded)

        # Now fill out the data for a compensation
        self.ema = self.fill_out_ema(self.ema)

        # Rerun the request
        self.client_user.post(record_url, post_data)

        # Expect the Ema now to be recorded
        # Attention: We can only test the date part of the timestamp,
        # since the delay in microseconds would lead to fail
        self.ema.refresh_from_db()
        recorded = self.ema.recorded
        self.assertIsNotNone(recorded)
        self.assertEqual(self.superuser, recorded.user)
        self.assertEqual(UserAction.RECORDED, recorded.action)
        self.assertEqual(datetime.date.today(), recorded.timestamp.date())

        # Expect the user action to be in the log
        self.assertIn(recorded, self.ema.log.all())
        self.assertEqual(pre_record_log_count + 1, self.ema.log.count())