from django.contrib.auth import get_user_model
from django.shortcuts import reverse
from django.urls import resolve

from .base import BaseUnitTest
from .helpers import DocumentTestHelper

from ..models import Document, DocumentVerifier


class DocumentCreteViewTestCase(BaseUnitTest, DocumentTestHelper):
    def setUp(self):
        super(DocumentCreteViewTestCase, self).setUp()
        self.url = reverse('documents:document:start')

    def test_GET_return_200_status_code(self):
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 200)

    def test_correct_template_used(self):
        response = self.client.get(self.url)
        self.assertTemplateUsed(response, 'document_flow/create.html')

    def test_POST_returns_302_status_code(self):
        data = self.generate_POST(correct=True)
        response = self.client.post(self.url, data)
        self.assertEqual(response.status_code, 302)

    def test_POST_returns_correct_success_url(self):
        data = self.generate_POST(correct=True)
        response = self.client.post(self.url, data)
        resolver = resolve(response.url)
        self.assertEqual(resolver.url_name, 'edit_draft')
        self.assertEqual('documents:document', resolver.namespace)

    def test_saving_verifiers_and_updating_document(self):
        data = self.generate_POST(correct=True)
        self.client.post(self.url, data)
        document = Document.objects.get()

        self.assertEqual(DocumentVerifier.objects.count(), 2)
        self.assertEqual(DocumentVerifier.objects.first().document, document)
        self.assertEqual(document.title, 'test_title')
        self.assertEqual(document.description, 'test_description')

    def test_incorrect_POST(self):
        data = self.generate_POST(correct=False)
        response = self.client.post(self.url, data)

        self.assertEqual(response.status_code, 200)
        self.assertIn('<ul class="errorlist', response.content.decode())


class DocumentEditDraftViewTestCase(BaseUnitTest, DocumentTestHelper):
    def setUp(self):
        super(DocumentEditDraftViewTestCase, self).setUp()
        response = self.create_test_document()
        self.url = response.url

    def create_test_document(self):
        url = reverse('documents:document:start')

        form_data = self.init_form_data('old_title', 'old_description', self.test_user)
        activation_data = self.get_activation_management_form_data()
        formset_data = self.init_formset_data([])

        data = {**form_data, **activation_data, **formset_data}

        return self.client.post(url, data)

    # todo: add possibility to extend, not redact
    def init_correct_POST_data(self):
        form_data = self.init_form_data('test_title', 'test_description', self.test_user.id)
        formset_data = self.init_formset_data([1, 2, 3])
        return form_data, formset_data

    def test_GET_return_200_status_code(self):
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 200)

    def test_correct_template_used(self):
        response = self.client.get(self.url)
        self.assertTemplateUsed(response, 'document_flow/edit_draft.html')

    def test_saving_verifiers_and_updating_document(self):
        data = self.generate_POST(correct=True)
        self.client.post(self.url, data)

        document = Document.objects.get()
        self.assertEqual(DocumentVerifier.objects.count(), 3)
        self.assertEqual(DocumentVerifier.objects.first().document, document)

        self.assertEqual(document.title, 'test_title')
        self.assertEqual(document.description, 'test_description')

    def test_incorrect_POST(self):
        data = self.generate_POST(correct=False)
        response = self.client.post(self.url, data)
        self.assertEqual(response.status_code, 200)
        self.assertIn('<ul class="errorlist', response.content.decode())

    def test_POST_returns_correct_success_url(self):
        data = self.generate_POST(correct=True)
        data.update({'_to_next_step': 'yes'})
        response = self.client.post(self.url, data)
        resolver = resolve(response.url)
        self.assertEqual(resolver.url_name, 'verifying')
        self.assertEqual('documents:document', resolver.namespace)

    def test_document_status_change_after_sending(self):
        data = self.generate_POST(correct=True)
        data.update({'_to_next_step': 'yes'})
        self.client.post(self.url, data)

        doc = Document.objects.get()
        self.assertEqual(doc.status, 'verifying')


class DocumentVerifyingInfoViewTestCase(BaseUnitTest, DocumentTestHelper):
    def setUp(self):
        super(DocumentVerifyingInfoViewTestCase, self).setUp()
        self.save_test_document_url()

    def save_test_document_url(self):
        start_url = reverse('documents:document:start')
        data = self.get_create_document_data()
        response = self.client.post(start_url, data)
        edit_draft_url = response.url
        response = self.client.post(edit_draft_url, data)
        self.url = response.url

    def get_create_document_data(self):
        form_data = self.init_form_data('old_title', 'old_description', self.test_user)
        activation_data = self.get_activation_management_form_data()
        formset_data = self.init_formset_data([])

        data = {**form_data, **activation_data, **formset_data}
        data.update({'_to_next_step': 'yes'})
        return data

    def test_GET_return_200_status_code(self):
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 200)

    def test_correct_template_used(self):
        response = self.client.get(self.url)
        self.assertTemplateUsed(response, 'document_flow/verifying_info.html')
        # todo: add POST for getting next step

    def test_response_contain_submit_after_all_answers_were_given(self):
        doc = Document.objects.get()
        doc_verifier = DocumentVerifier.objects.create(document=doc, verifier=self.test_user)
        response = self.client.get(self.url)
        self.assertNotIn('show_submit', response.context_data)

        doc_verifier.is_verified = True
        doc_verifier.save()

        response = self.client.get(self.url)

        self.assertIn('show_submit', response.context_data)

        doc_verifier.is_verified = False
        doc_verifier.save()

        response = self.client.get(self.url)
        self.assertIn('show_submit', response.context_data)


class DocumentVerifyingViewTestCase(BaseUnitTest):
    def setUp(self):
        super(DocumentVerifyingViewTestCase, self).setUp()
        self.create_test_data()
        self.url = '/documents/verifying/1/'

    def create_test_data(self):
        test_doc = Document.objects.create(
            title='test_title', description='test_description', author=self.test_user, status='verifying'
        )
        DocumentVerifier.objects.create(
            document=test_doc, verifier=self.test_user
        )

    def test_verifying_view_return_200_status_code(self):
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 200)

    def test_verifying_view_render_correct_template(self):
        response = self.client.get(self.url)
        self.assertTemplateUsed(response, 'document_flow/verifying.html')

    def test_verifying_view_render_correct_info(self):
        response = self.client.get(self.url)

        self.assertContains(response, 'test_title')
        self.assertContains(response, 'test_description')
        self.assertContains(response, str(self.test_user))

    def test_correct_POST_return_302_status_code(self):
        post_data = {
            'answer': 'test_answer',
            'is_verified': '2',
        }
        response = self.client.post(self.url, post_data)
        self.assertRedirects(response, '/filters/inbox/')

    def test_POST_with_positive_answer_save_it_and_change_status(self):
        post_data = {
            'answer': 'test_answer',
            'is_verified': '2',
        }
        self.client.post(self.url, post_data)

        doc = Document.objects.get()
        doc_verifier = DocumentVerifier.objects.get()

        self.assertEqual(doc.status, 'completed')

        self.assertEqual(doc_verifier.answer, 'test_answer')
        self.assertTrue(doc_verifier.is_verified)

    def test_POST_with_negative_answer_save_it_and_change_status(self):
        post_data = {
            'answer': 'test_answer',
            'is_verified': '3',
        }
        self.client.post(self.url, post_data)

        doc = Document.objects.get()
        doc_verifier = DocumentVerifier.objects.get()

        self.assertEqual(doc.status, 'failed')

        self.assertEqual(doc_verifier.answer, 'test_answer')
        self.assertFalse(doc_verifier.is_verified)

    def test_incorrect_POST(self):
        post_data = {
            'answer': 'test_answer',
            'is_verified': '1',
        }

        response = self.client.post(self.url, post_data)
        self.assertEqual(response.status_code, 200)


# todo: test notifications
# todo: move formset testing to test_forms
# todo: mock process not create, refactor
# todo: add urls tests
# todo: change create_user function in base
# todo: change create_test_document in base
