# -- encoding: UTF-8 --
import json
import uuid

from admin_export_action import report
from admin_export_action.admin import export_selected_objects
from admin_export_action.config import default_config, get_config

from django.contrib.admin.sites import AdminSite
from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.test import TestCase, RequestFactory
from django.urls import reverse
from django.utils.http import urlencode
from news.models import Attachment, Category, News, NewsTag, Video
from news.admin import NewsAdmin


class FakeDict(object):

    def __getitem__(self, key):
        return object()


class WS(object):
    def __init__(self):
        self.rows = []
        self.cells = []
        self.column_dimensions = FakeDict()

    def cell(self, row, column):
        pass

    def append(self, row):
        self.rows.append(row)


class FakeQueryset(object):
    def __init__(self, num):
        self.num = num
        self.model = News

    def values_list(self, field, flat=True):
        return [i for i in range(1, self.num)]


class AdminExportActionTest(TestCase):
    fixtures = ["tests.json"]

    def test_config(self):
        self.assertEqual(default_config.get('ENABLE_SITEWIDE'), True)
        self.assertEqual(get_config('ENABLE_SITEWIDE'), False)

        with self.settings(ADMIN_EXPORT_ACTION=None):
            self.assertEqual(get_config('ENABLE_SITEWIDE'), True)

    def test_export_selected_objects_session(self):
        factory = RequestFactory()
        request = factory.get('/news/admin/')
        request.session = {}
        modeladmin = NewsAdmin(model=News, admin_site=AdminSite())
        qs = FakeQueryset(2000)

        self.assertEqual(len(request.session), 0)
        export_selected_objects(modeladmin, request, qs)
        self.assertEqual(len(request.session), 1)
        els = list(request.session.items())
        self.assertEqual(els[0][1], qs.values_list('id'))

    def test_get_field_verbose_name(self):
        res = report.get_field_verbose_name(News.objects, 'tags__name')
        assert res == 'all tags verbose name'
        res = report.get_field_verbose_name(News.objects, 'share')
        assert res == 'share'

    def test_list_to_method_response_should_return_200_and_correct_values(
            self):
        admin = User.objects.get(pk=1)
        data, messages = report.report_to_list(News.objects.all(),
                                               ['id', 'title', 'status'],
                                               admin)
        method = getattr(report, 'list_to_{}_response'.format('html'))
        res = method(data)
        assert res.status_code == 200

        method = getattr(report, 'list_to_{}_response'.format('csv'))
        res = method(data)

        assert res.status_code == 200
        assert res.content == b'1,Lucio Dalla,published\r\n2,La mano de Dios,draft\r\n'

        method = getattr(report, 'list_to_{}_response'.format('xlsx'))
        res = method(data)
        assert res.status_code == 200

        method = getattr(report, 'list_to_{}_response'.format('json'))
        res = method(data, header=['id', 'title', 'status'])
        d = json.loads(res.content)
        assert d[0]['id'] == 1
        assert d[0]['title'] == "Lucio Dalla"
        assert d[0]['status'] == 'published'
        assert d[1]['id'] == 2
        assert d[1]['title'] == "La mano de Dios"
        assert d[1]['status'] == 'draft'
        assert res.status_code == 200

        data, messages = report.report_to_list(News.objects.all(),
                                               ['id', 'title', 'status'],
                                               admin,
                                               raw_choices=True)

        method = getattr(report, 'list_to_{}_response'.format('json'))
        res = method(data, header=['id', 'title', 'status'])
        d = json.loads(res.content)
        assert d[0]['id'] == 1
        assert d[0]['title'] == "Lucio Dalla"
        assert d[0]['status'] == 2
        assert d[1]['id'] == 2
        assert d[1]['title'] == "La mano de Dios"
        assert d[1]['status'] == 1
        assert res.status_code == 200

    def test_list_to_csv_response_should_have_expected_content(self):
        admin = User.objects.get(pk=1)
        data, messages = report.report_to_list(News.objects.all(),
                                               ['id', 'title'], admin)

        method = getattr(report, 'list_to_{}_response'.format('csv'))
        res = method(data)

        assert res.status_code == 200
        assert res.content == b'1,Lucio Dalla\r\n2,La mano de Dios\r\n'

    def test_list_to_json_response_should_have_expected_content(self):
        admin = User.objects.get(pk=1)
        data, messages = report.report_to_list(News.objects.all(),
                                               ['id', 'title'], admin)

        method = getattr(report, 'list_to_{}_response'.format('json'))
        res = method(data, header=['id', 'title'])
        d = json.loads(res.content)
        assert d[0]['id'] == 1
        assert d[0]['title'] == "Lucio Dalla"
        assert d[1]['id'] == 2
        assert d[1]['title'] == "La mano de Dios"
        assert res.status_code == 200

    def test_admin_export_post_should_return_200(self):
        for output_format in ['html', 'csv', 'xslx', 'json']:
            params = {
                'ct':
                ContentType.objects.get_for_model(News).pk,
                'ids':
                ','.join(
                    repr(pk)
                    for pk in News.objects.values_list('pk', flat=True))
            }
            data = {
                "title": "on",
                "__format": output_format,
            }
            url = "{}?{}".format(reverse('admin_export_action:export'),
                                 urlencode(params))
            self.client.login(username='admin', password='admin')
            response = self.client.post(url, data=data)
            assert response.status_code == 200

    def test_admin_export_get_should_return_200(self):
        params = {
            'ct':
            ContentType.objects.get_for_model(News).pk,
            'ids':
            ','.join(
                repr(pk) for pk in News.objects.values_list('pk', flat=True))
        }
        url = "{}?{}".format(reverse('admin_export_action:export'),
                             urlencode(params))
        self.client.login(username='admin', password='admin')
        response = self.client.get(url)
        assert response.status_code == 200

    def test_admin_export_with_related_get_should_return_200(self):
        params = {
            'related': True,
            'model_ct': ContentType.objects.get_for_model(News).pk,
            'field': 'category',
            'path': 'category.name',
        }
        url = "{}?{}".format(reverse('admin_export_action:export'),
                             urlencode(params))
        self.client.login(username='admin', password='admin')
        response = self.client.get(url)
        assert response.status_code == 200

    def test_admin_export_with_related_of_indirect_field_get_should_return_200(
            self):
        params = {
            'related': True,
            'model_ct': ContentType.objects.get_for_model(News).pk,
            'field': 'newstag',
            'path': 'newstag.id',
        }
        url = "{}?{}".format(reverse('admin_export_action:export'),
                             urlencode(params))
        self.client.login(username='admin', password='admin')
        response = self.client.get(url)

        assert response.status_code == 200

    def test_admin_export_with_unregistered_model_should_raise_ValueError(
            self):
        params = {
            'ct':
            ContentType.objects.get_for_model(NewsTag).pk,
            'ids':
            ','.join(
                repr(pk)
                for pk in NewsTag.objects.values_list('pk', flat=True))
        }
        url = "{}?{}".format(reverse('admin_export_action:export'),
                             urlencode(params))

        self.client.login(username='admin', password='admin')
        try:
            self.client.get(url)
            self.fail()
        except ValueError:
            pass

    def test_admin_action_should_redirect_to_export_view(self):
        objects = News.objects.all()

        ids = [repr(obj.pk) for obj in objects]
        data = {
            "action": "export_selected_objects",
            "_selected_action": ids,
        }
        url = reverse('admin:news_news_changelist')
        self.client.login(username='admin', password='admin')
        response = self.client.post(url, data=data)

        expected_url = "{}?ct={ct}&ids={ids}".format(
            reverse('admin_export_action:export'),
            ct=ContentType.objects.get_for_model(News).pk,
            ids=','.join(reversed(ids)))
        assert response.status_code == 302
        assert response.url.endswith(expected_url)

    def test_export_with_related_should_return_200(self):
        for output_format in ['html', 'csv', 'xslx', 'json']:
            news = News.objects.all()

            params = {
                'ct':
                ContentType.objects.get_for_model(News).pk,
                'ids':
                ','.join(
                    repr(pk)
                    for pk in News.objects.values_list('pk', flat=True))
            }
            data = {
                'id': 'on',
                'title': 'on',
                'status': 'on',
                'category__name': 'on',
                'tags__name': 'on',
                'newstag__created_on': 'on',
                "__format": output_format,
            }
            url = "{}?{}".format(reverse('admin_export_action:export'),
                                 urlencode(params))
            self.client.login(username='admin', password='admin')
            response = self.client.post(url, data=data)
            assert response.status_code == 200
            assert response.content

    def test_build_sheet_convert_function(self):
        data = [
            ['1', 5, 'convert', 9, {"foo": "bar"}, [1, 2], uuid.UUID("12345678123456781234567812345678")],
        ]

        ws = WS()

        report.build_sheet(data, ws, sheet_name='report', header=None, widths=None)
        self.assertEqual(ws.rows, [['1', 5, 'converted', 9, "{'foo': 'bar'}", '[1, 2]', '12345678-1234-5678-1234-567812345678']])

[((58, 18, 58, 34), 'django.test.RequestFactory', 'RequestFactory', ({}, {}), '()', False, 'from django.test import TestCase, RequestFactory\n'), ((65, 8, 65, 56), 'admin_export_action.admin.export_selected_objects', 'export_selected_objects', ({(65, 32, 65, 42): 'modeladmin', (65, 44, 65, 51): 'request', (65, 53, 65, 55): 'qs'}, {}), '(modeladmin, request, qs)', False, 'from admin_export_action.admin import export_selected_objects\n'), ((71, 14, 71, 71), 'admin_export_action.report.get_field_verbose_name', 'report.get_field_verbose_name', ({(71, 44, 71, 56): 'News.objects', (71, 58, 71, 70): '"""tags__name"""'}, {}), "(News.objects, 'tags__name')", False, 'from admin_export_action import report\n'), ((73, 14, 73, 66), 'admin_export_action.report.get_field_verbose_name', 'report.get_field_verbose_name', ({(73, 44, 73, 56): 'News.objects', (73, 58, 73, 65): '"""share"""'}, {}), "(News.objects, 'share')", False, 'from admin_export_action import report\n'), ((78, 16, 78, 38), 'django.contrib.auth.models.User.objects.get', 'User.objects.get', (), '', False, 'from django.contrib.auth.models import User\n'), ((98, 12, 98, 35), 'json.loads', 'json.loads', ({(98, 23, 98, 34): 'res.content'}, {}), '(res.content)', False, 'import json\n'), ((114, 12, 114, 35), 'json.loads', 'json.loads', ({(114, 23, 114, 34): 'res.content'}, {}), '(res.content)', False, 'import json\n'), ((124, 16, 124, 38), 'django.contrib.auth.models.User.objects.get', 'User.objects.get', (), '', False, 'from django.contrib.auth.models import User\n'), ((135, 16, 135, 38), 'django.contrib.auth.models.User.objects.get', 'User.objects.get', (), '', False, 'from django.contrib.auth.models import User\n'), ((141, 12, 141, 35), 'json.loads', 'json.loads', ({(141, 23, 141, 34): 'res.content'}, {}), '(res.content)', False, 'import json\n'), ((231, 18, 231, 36), 'news.models.News.objects.all', 'News.objects.all', ({}, {}), '()', False, 'from news.models import Attachment, Category, News, NewsTag, Video\n'), ((238, 14, 238, 51), 'django.urls.reverse', 'reverse', ({(238, 22, 238, 50): '"""admin:news_news_changelist"""'}, {}), "('admin:news_news_changelist')", False, 'from django.urls import reverse\n'), ((284, 8, 284, 83), 'admin_export_action.report.build_sheet', 'report.build_sheet', (), '', False, 'from admin_export_action import report\n'), ((51, 25, 51, 62), 'admin_export_action.config.default_config.get', 'default_config.get', ({(51, 44, 51, 61): '"""ENABLE_SITEWIDE"""'}, {}), "('ENABLE_SITEWIDE')", False, 'from admin_export_action.config import default_config, get_config\n'), ((52, 25, 52, 54), 'admin_export_action.config.get_config', 'get_config', ({(52, 36, 52, 53): '"""ENABLE_SITEWIDE"""'}, {}), "('ENABLE_SITEWIDE')", False, 'from admin_export_action.config import default_config, get_config\n'), ((79, 47, 79, 65), 'news.models.News.objects.all', 'News.objects.all', ({}, {}), '()', False, 'from news.models import Attachment, Category, News, NewsTag, Video\n'), ((107, 47, 107, 65), 'news.models.News.objects.all', 'News.objects.all', ({}, {}), '()', False, 'from news.models import Attachment, Category, News, NewsTag, Video\n'), ((125, 47, 125, 65), 'news.models.News.objects.all', 'News.objects.all', ({}, {}), '()', False, 'from news.models import Attachment, Category, News, NewsTag, Video\n'), ((136, 47, 136, 65), 'news.models.News.objects.all', 'News.objects.all', ({}, {}), '()', False, 'from news.models import Attachment, Category, News, NewsTag, Video\n'), ((176, 29, 176, 66), 'django.urls.reverse', 'reverse', ({(176, 37, 176, 65): '"""admin_export_action:export"""'}, {}), "('admin_export_action:export')", False, 'from django.urls import reverse\n'), ((177, 29, 177, 46), 'django.utils.http.urlencode', 'urlencode', ({(177, 39, 177, 45): 'params'}, {}), '(params)', False, 'from django.utils.http import urlencode\n'), ((189, 29, 189, 66), 'django.urls.reverse', 'reverse', ({(189, 37, 189, 65): '"""admin_export_action:export"""'}, {}), "('admin_export_action:export')", False, 'from django.urls import reverse\n'), ((190, 29, 190, 46), 'django.utils.http.urlencode', 'urlencode', ({(190, 39, 190, 45): 'params'}, {}), '(params)', False, 'from django.utils.http import urlencode\n'), ((203, 29, 203, 66), 'django.urls.reverse', 'reverse', ({(203, 37, 203, 65): '"""admin_export_action:export"""'}, {}), "('admin_export_action:export')", False, 'from django.urls import reverse\n'), ((204, 29, 204, 46), 'django.utils.http.urlencode', 'urlencode', ({(204, 39, 204, 45): 'params'}, {}), '(params)', False, 'from django.utils.http import urlencode\n'), ((220, 29, 220, 66), 'django.urls.reverse', 'reverse', ({(220, 37, 220, 65): '"""admin_export_action:export"""'}, {}), "('admin_export_action:export')", False, 'from django.urls import reverse\n'), ((221, 29, 221, 46), 'django.utils.http.urlencode', 'urlencode', ({(221, 39, 221, 45): 'params'}, {}), '(params)', False, 'from django.utils.http import urlencode\n'), ((243, 12, 243, 49), 'django.urls.reverse', 'reverse', ({(243, 20, 243, 48): '"""admin_export_action:export"""'}, {}), "('admin_export_action:export')", False, 'from django.urls import reverse\n'), ((251, 19, 251, 37), 'news.models.News.objects.all', 'News.objects.all', ({}, {}), '()', False, 'from news.models import Attachment, Category, News, NewsTag, Video\n'), ((55, 29, 55, 58), 'admin_export_action.config.get_config', 'get_config', ({(55, 40, 55, 57): '"""ENABLE_SITEWIDE"""'}, {}), "('ENABLE_SITEWIDE')", False, 'from admin_export_action.config import default_config, get_config\n'), ((61, 54, 61, 65), 'django.contrib.admin.sites.AdminSite', 'AdminSite', ({}, {}), '()', False, 'from django.contrib.admin.sites import AdminSite\n'), ((162, 33, 162, 70), 'django.urls.reverse', 'reverse', ({(162, 41, 162, 69): '"""admin_export_action:export"""'}, {}), "('admin_export_action:export')", False, 'from django.urls import reverse\n'), ((163, 33, 163, 50), 'django.utils.http.urlencode', 'urlencode', ({(163, 43, 163, 49): 'params'}, {}), '(params)', False, 'from django.utils.http import urlencode\n'), ((171, 12, 171, 51), 'django.contrib.contenttypes.models.ContentType.objects.get_for_model', 'ContentType.objects.get_for_model', ({(171, 46, 171, 50): 'News'}, {}), '(News)', False, 'from django.contrib.contenttypes.models import ContentType\n'), ((185, 24, 185, 63), 'django.contrib.contenttypes.models.ContentType.objects.get_for_model', 'ContentType.objects.get_for_model', ({(185, 58, 185, 62): 'News'}, {}), '(News)', False, 'from django.contrib.contenttypes.models import ContentType\n'), ((199, 24, 199, 63), 'django.contrib.contenttypes.models.ContentType.objects.get_for_model', 'ContentType.objects.get_for_model', ({(199, 58, 199, 62): 'News'}, {}), '(News)', False, 'from django.contrib.contenttypes.models import ContentType\n'), ((214, 12, 214, 54), 'django.contrib.contenttypes.models.ContentType.objects.get_for_model', 'ContentType.objects.get_for_model', ({(214, 46, 214, 53): 'NewsTag'}, {}), '(NewsTag)', False, 'from django.contrib.contenttypes.models import ContentType\n'), ((270, 33, 270, 70), 'django.urls.reverse', 'reverse', ({(270, 41, 270, 69): '"""admin_export_action:export"""'}, {}), "('admin_export_action:export')", False, 'from django.urls import reverse\n'), ((271, 33, 271, 50), 'django.utils.http.urlencode', 'urlencode', ({(271, 43, 271, 49): 'params'}, {}), '(params)', False, 'from django.utils.http import urlencode\n'), ((279, 59, 279, 104), 'uuid.UUID', 'uuid.UUID', ({(279, 69, 279, 103): '"""12345678123456781234567812345678"""'}, {}), "('12345678123456781234567812345678')", False, 'import uuid\n'), ((152, 16, 152, 55), 'django.contrib.contenttypes.models.ContentType.objects.get_for_model', 'ContentType.objects.get_for_model', ({(152, 50, 152, 54): 'News'}, {}), '(News)', False, 'from django.contrib.contenttypes.models import ContentType\n'), ((244, 15, 244, 54), 'django.contrib.contenttypes.models.ContentType.objects.get_for_model', 'ContentType.objects.get_for_model', ({(244, 49, 244, 53): 'News'}, {}), '(News)', False, 'from django.contrib.contenttypes.models import ContentType\n'), ((255, 16, 255, 55), 'django.contrib.contenttypes.models.ContentType.objects.get_for_model', 'ContentType.objects.get_for_model', ({(255, 50, 255, 54): 'News'}, {}), '(News)', False, 'from django.contrib.contenttypes.models import ContentType\n'), ((174, 35, 174, 76), 'news.models.News.objects.values_list', 'News.objects.values_list', (), '', False, 'from news.models import Attachment, Category, News, NewsTag, Video\n'), ((218, 26, 218, 70), 'news.models.NewsTag.objects.values_list', 'NewsTag.objects.values_list', (), '', False, 'from news.models import Attachment, Category, News, NewsTag, Video\n'), ((156, 30, 156, 71), 'news.models.News.objects.values_list', 'News.objects.values_list', (), '', False, 'from news.models import Attachment, Category, News, NewsTag, Video\n'), ((259, 30, 259, 71), 'news.models.News.objects.values_list', 'News.objects.values_list', (), '', False, 'from news.models import Attachment, Category, News, NewsTag, Video\n')]