import datetime

from io import BytesIO

from django.conf import settings
from django.conf.locale import LANG_INFO
from django.test import TestCase
from django.test.utils import override_settings
from django.urls import reverse
from django.utils import timezone, translation
from openpyxl import load_workbook

from wagtail.admin.views.mixins import ExcelDateFormatter
from wagtail.models import Page, logging
from wagtail.test.utils import WagtailTestUtils


class TestLockedPagesView(TestCase, WagtailTestUtils):
    def setUp(self):
        self.user = self.login()

    def get(self, params={}):
        return self.client.get(reverse('wagtailadmin_reports:locked_pages'), params)

    def test_simple(self):
        response = self.get()
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'wagtailadmin/reports/locked_pages.html')

        # Initially there should be no locked pages
        self.assertContains(response, "No locked pages found.")

        self.page = Page.objects.first()
        self.page.locked = True
        self.page.locked_by = self.user
        self.page.locked_at = timezone.now()
        self.page.save()

        # Now the listing should contain our locked page
        response = self.get()
        self.assertEqual(response.status_code, 200)
        self.assertTemplateUsed(response, 'wagtailadmin/reports/locked_pages.html')
        self.assertNotContains(response, "No locked pages found.")
        self.assertContains(response, self.page.title)

    def test_csv_export(self):

        self.page = Page.objects.first()
        self.page.locked = True
        self.page.locked_by = self.user
        if settings.USE_TZ:
            # 12:00 UTC
            self.page.locked_at = '2013-02-01T12:00:00.000Z'
            self.page.latest_revision_created_at = '2013-01-01T12:00:00.000Z'
        else:
            # 12:00 in no specific timezone
            self.page.locked_at = '2013-02-01T12:00:00'
            self.page.latest_revision_created_at = '2013-01-01T12:00:00'
        self.page.save()

        response = self.get(params={'export': 'csv'})

        # Check response
        self.assertEqual(response.status_code, 200)
        data_lines = response.getvalue().decode().split("\n")
        self.assertEqual(data_lines[0], 'Title,Updated,Status,Type,Locked At,Locked By\r')
        if settings.USE_TZ:
            self.assertEqual(data_lines[1], 'Root,2013-01-01 12:00:00+00:00,live,Page,2013-02-01 12:00:00+00:00,test@email.com\r')
        else:
            self.assertEqual(data_lines[1], 'Root,2013-01-01 12:00:00,live,Page,2013-02-01 12:00:00,test@email.com\r')

    def test_xlsx_export(self):

        self.page = Page.objects.first()
        self.page.locked = True
        self.page.locked_by = self.user
        if settings.USE_TZ:
            # 12:00 UTC
            self.page.locked_at = '2013-02-01T12:00:00.000Z'
            self.page.latest_revision_created_at = '2013-01-01T12:00:00.000Z'
        else:
            # 12:00 in no specific timezone
            self.page.locked_at = '2013-02-01T12:00:00'
            self.page.latest_revision_created_at = '2013-01-01T12:00:00'
        self.page.save()

        response = self.get(params={'export': 'xlsx'})

        # Check response - the locked page info should be in it
        self.assertEqual(response.status_code, 200)
        workbook_data = response.getvalue()
        worksheet = load_workbook(filename=BytesIO(workbook_data))['Sheet1']
        cell_array = [[cell.value for cell in row] for row in worksheet.rows]
        self.assertEqual(cell_array[0], ['Title', 'Updated', 'Status', 'Type', 'Locked At', 'Locked By'])
        self.assertEqual(cell_array[1], ['Root', datetime.datetime(2013, 1, 1, 12, 0), 'live', 'Page', datetime.datetime(2013, 2, 1, 12, 0), 'test@email.com'])
        self.assertEqual(len(cell_array), 2)


class TestFilteredLockedPagesView(TestCase, WagtailTestUtils):
    fixtures = ['test.json']

    def setUp(self):
        self.user = self.login()
        self.unpublished_page = Page.objects.get(url_path='/home/events/tentative-unpublished-event/')
        self.unpublished_page.locked = True
        self.unpublished_page.locked_by = self.user
        self.unpublished_page.locked_at = timezone.now()
        self.unpublished_page.save()

    def get(self, params={}):
        return self.client.get(reverse('wagtailadmin_reports:locked_pages'), params)

    def test_filter_by_live(self):
        response = self.get(params={'live': 'true'})
        self.assertEqual(response.status_code, 200)
        self.assertNotContains(response, "Tentative Unpublished Event")
        self.assertContains(response, "My locked page")

        response = self.get(params={'live': 'false'})
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Tentative Unpublished Event")
        self.assertNotContains(response, "My locked page")

    def test_filter_by_user(self):
        response = self.get(params={'locked_by': self.user.pk})
        self.assertEqual(response.status_code, 200)
        self.assertContains(response, "Tentative Unpublished Event")
        self.assertNotContains(response, "My locked page")


class TestFilteredLogEntriesView(TestCase, WagtailTestUtils):
    fixtures = ['test.json']

    def setUp(self):
        self.user = self.login()
        self.home_page = Page.objects.get(url_path='/home/')

        self.create_log = logging.PageLogEntry.objects.log_action(self.home_page, 'wagtail.create')
        self.edit_log_1 = logging.PageLogEntry.objects.log_action(self.home_page, 'wagtail.edit')
        self.edit_log_2 = logging.PageLogEntry.objects.log_action(self.home_page, 'wagtail.edit')
        self.edit_log_3 = logging.PageLogEntry.objects.log_action(self.home_page, 'wagtail.edit')

        self.create_comment_log = logging.PageLogEntry.objects.log_action(self.home_page, 'wagtail.comments.create', data={
            'comment': {
                'contentpath': 'title',
                'text': 'Foo',
            }
        })
        self.edit_comment_log = logging.PageLogEntry.objects.log_action(self.home_page, 'wagtail.comments.edit', data={
            'comment': {
                'contentpath': 'title',
                'text': 'Edited',
            }
        })
        self.create_reply_log = logging.PageLogEntry.objects.log_action(self.home_page, 'wagtail.comments.create_reply', data={
            'comment': {
                'contentpath': 'title',
                'text': 'Foo',
            }
        })

    def get(self, params={}):
        return self.client.get(reverse('wagtailadmin_reports:site_history'), params)

    def assert_log_entries(self, response, expected):
        actual = set(response.context['object_list'])
        self.assertSetEqual(actual, set(expected))

    def test_unfiltered(self):
        response = self.get()
        self.assertEqual(response.status_code, 200)
        self.assert_log_entries(response, [
            self.create_log,
            self.edit_log_1,
            self.edit_log_2,
            self.edit_log_3,
            self.create_comment_log,
            self.edit_comment_log,
            self.create_reply_log,
        ])

    def test_filter_by_action(self):
        response = self.get(params={'action': 'wagtail.edit'})
        self.assertEqual(response.status_code, 200)
        self.assert_log_entries(response, [
            self.edit_log_1,
            self.edit_log_2,
            self.edit_log_3,
        ])

    def test_hide_commenting_actions(self):
        response = self.get(params={'hide_commenting_actions': 'on'})
        self.assertEqual(response.status_code, 200)
        self.assert_log_entries(response, [
            self.create_log,
            self.edit_log_1,
            self.edit_log_2,
            self.edit_log_3,
        ])


@override_settings(
    USE_L10N=True,
)
class TestExcelDateFormatter(TestCase):
    def test_all_locales(self):
        formatter = ExcelDateFormatter()

        for lang in LANG_INFO.keys():
            with self.subTest(lang), translation.override(lang):
                self.assertNotEqual(formatter.get(), "")
