import json
import unittest
from datetime import date, datetime

from django.core.serializers.json import DjangoJSONEncoder
from django.db import connections
from django.test import TestCase
from django.utils import timezone

from explorer.app_settings import EXPLORER_DEFAULT_CONNECTION as CONN
from explorer.exporters import CSVExporter, ExcelExporter, JSONExporter
from explorer.models import QueryResult
from explorer.tests.factories import SimpleQueryFactory
from explorer.utils import is_xls_writer_available


class TestCsv(TestCase):

    def test_writing_unicode(self):
        res = QueryResult(
            SimpleQueryFactory(sql='select 1 as "a", 2 as ""').sql,
            connections[CONN]
        )
        res.execute_query()
        res.process()
        res._data = [[1, None], ["Jenét", '1']]

        res = CSVExporter(query=None)._get_output(res).getvalue()
        self.assertEqual(
            res.encode('utf-8').decode('utf-8-sig'),
            'a,\r\n1,\r\nJenét,1\r\n'
        )

    def test_custom_delimiter(self):
        q = SimpleQueryFactory(sql='select 1, 2')
        exporter = CSVExporter(query=q)
        res = exporter.get_output(delim='|')
        self.assertEqual(
            res.encode('utf-8').decode('utf-8-sig'),
            '1|2\r\n1|2\r\n'
        )

    def test_writing_bom(self):
        q = SimpleQueryFactory(sql='select 1, 2')
        exporter = CSVExporter(query=q)
        res = exporter.get_output()
        self.assertEqual(res, '\ufeff1,2\r\n1,2\r\n')


class TestJson(TestCase):

    def test_writing_json(self):
        res = QueryResult(
            SimpleQueryFactory(sql='select 1 as "a", 2 as ""').sql,
            connections[CONN]
        )
        res.execute_query()
        res.process()
        res._data = [[1, None], ["Jenét", '1']]

        res = JSONExporter(query=None)._get_output(res).getvalue()
        expected = [{'a': 1, '': None}, {'a': 'Jenét', '': '1'}]
        self.assertEqual(res, json.dumps(expected))

    def test_writing_datetimes(self):
        res = QueryResult(
            SimpleQueryFactory(sql='select 1 as "a", 2 as "b"').sql,
            connections[CONN]
        )
        res.execute_query()
        res.process()
        res._data = [[1, date.today()]]

        res = JSONExporter(query=None)._get_output(res).getvalue()
        expected = [{'a': 1, 'b': date.today()}]
        self.assertEqual(res, json.dumps(expected, cls=DjangoJSONEncoder))


class TestExcel(TestCase):

    @unittest.skipIf(not is_xls_writer_available(), 'excel exporter not available')
    def test_writing_excel(self):
        """
        This is a pretty crap test. It at least exercises the code.
        If anyone wants to go through the brain damage of actually building
        an 'expected' xlsx output and comparing it
        (https://github.com/jmcnamara/XlsxWriter/blob/master/xlsxwriter/
        test/helperfunctions.py)
        by all means submit a pull request!
        """
        res = QueryResult(
            SimpleQueryFactory(
                sql='select 1 as "a", 2 as ""',
                title='\\/*[]:?this title is longer than 32 characters'
            ).sql,
            connections[CONN]
        )

        res.execute_query()
        res.process()

        d = datetime.now()
        d = timezone.make_aware(d, timezone.get_current_timezone())

        res._data = [[1, None], ["Jenét", d]]

        res = ExcelExporter(
            query=SimpleQueryFactory()
        )._get_output(res).getvalue()

        expected = b'PK'

        self.assertEqual(res[:2], expected)

    @unittest.skipIf(not is_xls_writer_available(), 'excel exporter not available')
    def test_writing_dict_fields(self):
        res = QueryResult(
            SimpleQueryFactory(
                sql='select 1 as "a", 2 as ""',
                title='\\/*[]:?this title is longer than 32 characters'
            ).sql,
            connections[CONN]
        )

        res.execute_query()
        res.process()

        res._data = [[1, ['foo', 'bar']], [2, {'foo': 'bar'}]]

        res = ExcelExporter(
            query=SimpleQueryFactory()
        )._get_output(res).getvalue()

        expected = b'PK'

        self.assertEqual(res[:2], expected)
