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

"""
import mimetypes
from datetime import timedelta

from django.core.exceptions import ObjectDoesNotExist
from django.test import RequestFactory
from django.utils.translation import gettext_lazy as _
from django.core.files.uploadedfile import SimpleUploadedFile
from django.utils.timezone import now

from compensation.forms.modals.document import NewEcoAccountDocumentModalForm, NewCompensationDocumentModalForm
from compensation.models import Payment
from ema.forms import NewEmaDocumentModalForm
from intervention.forms.modals.document import NewInterventionDocumentModalForm
from intervention.models import InterventionDocument
from konova.forms.modals import EditDocumentModalForm, NewDocumentModalForm, RecordModalForm, RemoveModalForm, \
    RemoveDeadlineModalForm, ResubmissionModalForm
from konova.models import Resubmission
from konova.tests.test_views import BaseTestCase
from konova.utils.generators import generate_random_string
from konova.utils.message_templates import DOCUMENT_EDITED, DEADLINE_REMOVED
from user.models import UserAction


class NewDocumentModalFormTestCase(BaseTestCase):
    def setUp(self) -> None:
        super().setUp()
        self.request = RequestFactory().request()
        self.request.user = self.superuser
        self.dummy_file = SimpleUploadedFile(
            "some_file.pdf",
            b"Some conent in this file",
            mimetypes.types_map[".pdf"]
        )
        dummy_file_dict = {
            "file": self.dummy_file
        }
        self.data = {
            "title": generate_random_string(length=5, use_letters_lc=True),
            "creation_date": now().date(),
            "comment": generate_random_string(length=50, use_letters_uc=True),
        }
        self.forms = [
            NewInterventionDocumentModalForm(self.data, dummy_file_dict, request=self.request, instance=self.intervention),
            NewCompensationDocumentModalForm(self.data, dummy_file_dict, request=self.request, instance=self.compensation),
            NewEmaDocumentModalForm(self.data, dummy_file_dict, request=self.request, instance=self.ema),
            NewEcoAccountDocumentModalForm(self.data, dummy_file_dict, request=self.request, instance=self.eco_account),
        ]

    def test_init(self):
        for form in self.forms:
            self.assertEqual(form.form_title, str(_("Add new document")))
            self.assertEqual(form.form_caption, str(_("")))
            self.assertEqual(
                form.form_attrs,
                {
                    "enctype": "multipart/form-data"
                }
            )
            self.assertEqual(form.request, self.request)
            self.assertEqual(form.user, self.superuser)

        try:
            NewDocumentModalForm(request=self.request, instance=self.intervention)
            self.fail("Base form NewDocumentModalForm should not be creatable")
        except NotImplementedError:
            pass

    def test_is_valid(self):
        for form in self.forms:
            self.assertTrue(
                form.is_valid(), msg=form.errors
            )

    def test_save(self):
        for form in self.forms:
            form.is_valid()
            obj = form.save()
            self.assertEqual(obj.created.action, UserAction.CREATED)
            self.assertEqual(obj.created.user, self.superuser)
            self.assertEqual(obj.title, self.data["title"])
            self.assertEqual(obj.date_of_creation, self.data["creation_date"])
            self.assertEqual(obj.comment, self.data["comment"])
            self.assertIsNotNone(obj.file)

            last_log = obj.instance.log.first()
            self.assertEqual(last_log.action, UserAction.EDITED)
            self.assertEqual(last_log.user, self.request.user)
            self.assertEqual(last_log.comment, str(_("Added document")))
            self.assertEqual(obj.instance.modified, last_log)


class EditDocumentModalFormTestCase(NewDocumentModalFormTestCase):
    def setUp(self) -> None:
        super().setUp()
        dummy_file_dict = {
            "file": self.dummy_file
        }
        self.doc = self.create_dummy_document(
            InterventionDocument,
            instance=self.intervention
        )
        self.form = EditDocumentModalForm(
            self.data,
            dummy_file_dict,
            request=self.request,
            instance=self.intervention,
            document=self.doc
        )

    def test_init(self):
        self.assertEqual(self.form.form_title, str(_("Edit document")))
        self.assertEqual(self.form.document, self.doc)
        self.assertEqual(self.form.request, self.request)
        self.assertEqual(self.form.user, self.request.user)
        self.assertEqual(self.form.fields["title"].initial, self.doc.title)
        self.assertEqual(self.form.fields["comment"].initial, self.doc.comment)
        self.assertEqual(self.form.fields["creation_date"].initial, self.doc.date_of_creation)
        self.assertEqual(self.form.fields["file"].initial, self.doc.file)

    def test_save(self):
        self.assertTrue(self.form.is_valid(), msg=self.form.errors)
        obj = self.form.save()
        self.assertEqual(obj.title, self.data["title"])
        self.assertEqual(obj.comment, self.data["comment"])
        self.assertEqual(obj.date_of_creation, self.data["creation_date"])

        last_log = obj.instance.log.first()
        self.assertEqual(last_log.action, UserAction.EDITED)
        self.assertEqual(last_log.user, self.request.user)
        self.assertEqual(last_log.comment, DOCUMENT_EDITED)


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

        self.fill_out_compensation(self.compensation)

    def test_init(self):
        form = RecordModalForm(
            request=self.request,
            instance=self.intervention
        )
        self.assertEqual(form.form_title, str(_("Record data")))
        self.assertEqual(form.form_caption, str(
            _("The necessary control steps have been performed:").format(
            self.user.first_name,
            self.user.last_name
            )
        ))

        self.intervention.set_recorded(self.user)
        self.intervention.refresh_from_db()
        form = RecordModalForm(
            request=self.request,
            instance=self.intervention
        )
        self.assertEqual(form.form_title, str(_("Unrecord data")))
        self.assertEqual(form.fields["confirm"].label, str(_("Confirm unrecord")))
        self.assertEqual(form.form_caption, str(
            _("I, {} {}, confirm that this data must be unrecorded.").format(
            self.user.first_name,
            self.user.last_name
        )))

    def test_is_valid(self):
        data = {
            "confirm": True
        }
        form = RecordModalForm(data, request=self.request, instance=self.intervention)
        self.assertFalse(self.intervention.is_recorded)
        self.assertFalse(form.is_valid(), msg=form.errors)  # intervention not complete

        self.intervention = self.fill_out_intervention(self.intervention)
        form = RecordModalForm(data, request=self.request, instance=self.intervention)
        self.assertTrue(form.is_valid(), msg=form.errors)

    def test_save(self):
        data = {
            "confirm": True
        }
        self.intervention = self.fill_out_intervention(self.intervention)
        form = RecordModalForm(data, request=self.request, instance=self.intervention)
        self.assertTrue(form.is_valid(), msg=form.errors)

        form.save()
        self.assertEqual(self.intervention.recorded.action, UserAction.RECORDED)
        self.assertEqual(self.intervention.recorded.user, self.request.user)
        self.assertEqual(self.intervention.recorded, self.intervention.log.first())


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

    def test_init(self):
        form = RemoveModalForm(request=self.request, instance=self.intervention)
        self.assertEqual(form.form_title, str(_("Remove")))
        self.assertEqual(form.form_caption, str(_("Are you sure?")))
        self.assertEqual(form.template, "modal/modal_form.html")
        self.assertEqual(form.request, self.request)
        self.assertEqual(form.user, self.request.user)

    def test_save(self):
        data = {
            "confirm": True,
        }
        form = RemoveModalForm(
            data,
            request=self.request,
            instance=self.intervention
        )
        self.assertTrue(form.is_valid(), msg=form.errors)

        form.save()
        self.assertEqual(self.intervention.deleted.action, UserAction.DELETED)
        self.assertEqual(self.intervention.deleted.user, self.request.user)

        payment = Payment.objects.create(
            amount=1.0,
            intervention=self.intervention
        )
        form = RemoveModalForm(
            data,
            request=self.request,
            instance=payment
        )
        self.assertTrue(form.is_valid(), msg=form.errors)
        form.save()
        try:
            payment.refresh_from_db()
            self.fail("Payment still exists")
        except ObjectDoesNotExist:
            pass


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

    def test_init(self):
        form = RemoveDeadlineModalForm(
            request=self.request,
            instance=self.compensation,
            deadline=self.finished_deadline
        )
        self.assertEqual(form.form_title, str(_("Remove")))
        self.assertEqual(form.form_caption, str(_("Are you sure?")))
        self.assertEqual(form.template, "modal/modal_form.html")
        self.assertEqual(form.request, self.request)
        self.assertEqual(form.user, self.request.user)

    def test_save(self):
        self.compensation.deadlines.add(self.finished_deadline)
        data = {
            "confirm": True
        }
        form = RemoveDeadlineModalForm(
            data,
            request=self.request,
            instance=self.compensation,
            deadline=self.finished_deadline
        )
        self.assertTrue(form.is_valid(), msg=form.errors)
        form.save()

        try:
            self.finished_deadline.refresh_from_db()
            self.fail("Deadline still exists")
        except ObjectDoesNotExist:
            pass

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


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

    def test_init(self):
        # Resubmission nonexistent
        form = ResubmissionModalForm(request=self.request, instance=self.intervention)
        self.assertEqual(form.form_title, str(_("Resubmission")))
        self.assertEqual(form.form_caption, str(_("Set your resubmission for this entry.")))
        self.assertEqual(form.action_url, None)
        self.assertIsNotNone(form.resubmission)

        resubmission = Resubmission.objects.create(
            user=self.request.user,
            resubmit_on=now().date(),
            comment=generate_random_string(length=10, use_letters_lc=True)
        )
        self.intervention.resubmissions.add(resubmission)

        # Resubmission exists
        form = ResubmissionModalForm(request=self.request, instance=self.intervention)
        self.assertEqual(form.form_title, str(_("Resubmission")))
        self.assertEqual(form.form_caption, str(_("Set your resubmission for this entry.")))
        self.assertEqual(form.action_url, None)
        self.assertEqual(form.fields["date"].initial, str(resubmission.resubmit_on))
        self.assertEqual(form.fields["comment"].initial, resubmission.comment)
        self.assertEqual(form.resubmission, resubmission)

    def test_is_valid(self):
        yesterday = now().date() - timedelta(days=1)
        data = {
            "date": yesterday,
            "comment": "Edited comment"
        }
        form = ResubmissionModalForm(
            data,
            request=self.request,
            instance=self.intervention
        )
        self.assertFalse(form.is_valid(), msg=form.errors)
        self.assertTrue(form.has_error("date"))

        tomorrow = yesterday + timedelta(days=2)
        data = {
            "date": tomorrow,
            "comment": "Edited comment"
        }
        form = ResubmissionModalForm(
            data,
            request=self.request,
            instance=self.intervention
        )
        self.assertTrue(form.is_valid(), msg=form.errors)

    def test_save(self):
        data = {
            "date": now().date() + timedelta(days=1),
            "comment": "New comment for new resubmission"
        }
        form = ResubmissionModalForm(
            data,
            request=self.request,
            instance=self.intervention
        )
        self.assertTrue(form.is_valid(), msg=form.errors)
        obj = form.save()
        self.assertIn(obj, self.intervention.resubmissions.all())
        self.assertEqual(obj.resubmit_on, data["date"])
        self.assertEqual(obj.comment, data["comment"])
        self.assertEqual(obj.resubmission_sent, False)
        self.assertEqual(obj.user, self.request.user)
