# -*- coding: utf-8 -*-
import datetime

from decimal import Decimal
from io import StringIO

from django.test import TestCase
from django.test.utils import skipUnless
from django.utils.translation import gettext_lazy

from rest_framework_xml.compat import etree
from rest_framework_xml.parsers import XMLParser
from rest_framework_xml.renderers import XMLRenderer


class XMLRendererTestCase(TestCase):
    """
    Tests specific to the XML Renderer
    """

    _complex_data = {
        "creation_date": datetime.datetime(2011, 12, 25, 12, 45, 00),
        "name": "name",
        "sub_data_list": [
            {"sub_id": 1, "sub_name": "first"},
            {"sub_id": 2, "sub_name": "second"},
        ],
    }

    def test_render_string(self):
        """
        Test XML rendering.
        """
        renderer = XMLRenderer()
        content = renderer.render({"field": "astring"}, "application/xml")
        self.assertXMLContains(content, "<field>astring</field>")

    def test_render_integer(self):
        """
        Test XML rendering.
        """
        renderer = XMLRenderer()
        content = renderer.render({"field": 111}, "application/xml")
        self.assertXMLContains(content, "<field>111</field>")

    def test_render_datetime(self):
        """
        Test XML rendering.
        """
        renderer = XMLRenderer()
        content = renderer.render(
            {"field": datetime.datetime(2011, 12, 25, 12, 45, 00)},
            "application/xml",
        )
        self.assertXMLContains(content, "<field>2011-12-25 12:45:00</field>")

    def test_render_float(self):
        """
        Test XML rendering.
        """
        renderer = XMLRenderer()
        content = renderer.render({"field": 123.4}, "application/xml")
        self.assertXMLContains(content, "<field>123.4</field>")

    def test_render_decimal(self):
        """
        Test XML rendering.
        """
        renderer = XMLRenderer()
        content = renderer.render(
            {"field": Decimal("111.2")}, "application/xml"
        )
        self.assertXMLContains(content, "<field>111.2</field>")

    def test_render_none(self):
        """
        Test XML rendering.
        """
        renderer = XMLRenderer()
        content = renderer.render({"field": None}, "application/xml")
        self.assertXMLContains(content, "<field></field>")

    def test_render_complex_data(self):
        """
        Test XML rendering.
        """
        renderer = XMLRenderer()
        content = renderer.render(self._complex_data, "application/xml")
        self.assertXMLContains(content, "<sub_name>first</sub_name>")
        self.assertXMLContains(content, "<sub_name>second</sub_name>")

    def test_render_list(self):
        renderer = XMLRenderer()
        content = renderer.render(self._complex_data, "application/xml")
        self.assertXMLContains(content, "<sub_data_list><list-item>")
        self.assertXMLContains(content, "</list-item></sub_data_list>")

    def test_render_lazy(self):
        renderer = XMLRenderer()
        lazy = gettext_lazy("hello")
        content = renderer.render({"field": lazy}, "application/xml")
        self.assertXMLContains(content, "<field>hello</field>")

    @skipUnless(etree, "defusedxml not installed")
    def test_render_and_parse_complex_data(self):
        """
        Test XML rendering.
        """
        renderer = XMLRenderer()
        content = StringIO(
            renderer.render(self._complex_data, "application/xml")
        )

        parser = XMLParser()
        complex_data_out = parser.parse(content)
        error_msg = "complex data differs!IN:\n %s \n\n OUT:\n %s" % (
            repr(self._complex_data),
            repr(complex_data_out),
        )
        self.assertEqual(self._complex_data, complex_data_out, error_msg)

    def assertXMLContains(self, xml, string):
        self.assertTrue(
            xml.startswith('<?xml version="1.0" encoding="utf-8"?>\n<root>')
        )
        self.assertTrue(xml.endswith("</root>"))
        self.assertTrue(string in xml, "%r not in %r" % (string, xml))
