import os
from datetime import datetime

import pytz

from distribution.utils import (
    date_to_rfc2822_string,
    sanitize_xml_text,
)
from test.utils import get_json
from test.test_adaptors.test_clients.test_rss.base import RSSAdapterBaseTestCase
from test.test_adaptors.test_clients.test_rss.utils import (
    FIXTURES_FOLDER,
    NAMESPACES,
)


class DefaultSpecificationTestCase(RSSAdapterBaseTestCase):
    ITEM_TEMPLATE = 'feed-item.rss'

    def test_general_article_tags(self):
        """Check that general xml tags are correctly generated."""
        data = get_json(
            os.path.join(FIXTURES_FOLDER, 'full.json'))[0]

        tree = self._get_xml_tree_from_data(data)

        item_element = tree.find('.//item')
        self.assertIsNotNone(item_element)

        # Check that the title tag contains the same article title value
        title_element = item_element.find('.//title')
        self.assertIsNotNone(title_element)

        self.assertEqual(title_element.text, data['title'])

        # Check that the dc:abstract tag contains the same article abstract value
        abstract_element = item_element.find('.//{}abstract'.format(NAMESPACES['dc']))
        self.assertIsNotNone(abstract_element)

        self.assertEqual(abstract_element.text, data['abstract'])

        # Check dc:modified tag
        modified_element = item_element.find('.//{}modified'.format(NAMESPACES['dc']))
        self.assertIsNotNone(modified_element)

        last_modified_datetime = datetime.strptime(
            data['last_modified_datetime'], '%Y-%m-%dT%H:%M:%S.%fZ')
        last_modified_datetime = pytz.utc.localize(last_modified_datetime)

        self.assertEqual(
            modified_element.text,
            date_to_rfc2822_string(last_modified_datetime)
        )

        # Check pubDate tag
        pub_date_element = item_element.find('.//pubDate')
        self.assertIsNotNone(pub_date_element)

        self.assertEqual(
            pub_date_element.text,
            date_to_rfc2822_string(last_modified_datetime)
        )

    def test_render_article_without_contributors(self):
        """
        Check that dc:creator tag is generated with the default value
        if there are no contributors.
        """
        data = get_json(
            os.path.join(FIXTURES_FOLDER, 'full.json'))[0]
        data['contributors'] = []

        tree = self._get_xml_tree_from_data(data)

        creator_tags = tree.findall('.//{}creator'.format(NAMESPACES['dc']))
        self.assertEqual(len(creator_tags), 1)

        creator_tag = creator_tags[0]
        self.assertEqual(creator_tag.text, 'National Geographic')

        contributor_tags = tree.findall('.//{}contributor'.format(NAMESPACES['dc']))
        self.assertEqual(contributor_tags, [])

    def test_render_article_with_one_contributor(self):
        """
        Check that dc:creator tag is generated with contributor writer
        name from article contributors.
        """
        data = get_json(
            os.path.join(FIXTURES_FOLDER, 'full.json'))[0]

        tree = self._get_xml_tree_from_data(data)

        creator_tags = tree.findall('.//{}creator'.format(NAMESPACES['dc']))
        self.assertEqual(len(creator_tags), 1)

        creator_tag = creator_tags[0]
        self.assertEqual(creator_tag.text, data['contributors'][0]['name'])

        contributor_tags = tree.findall('.//{}contributor'.format(NAMESPACES['dc']))
        self.assertEqual(contributor_tags, [])

    def test_render_article_with_multiple_contributors(self):
        """
        Check that dc:creator tag is generated with contributor writer name
        from article contributors and that there are the same number of
        dc:contributor tags as the rest of the contributors of the article.
        """
        data = get_json(
            os.path.join(FIXTURES_FOLDER, 'full.json'))[0]
        data['contributors'].extend([{
                "name": "Contributor1",
                "order": 0,
                "role": "",
                "role_other": None,
                "taxonomy_id": "",
                "uri": None
            }, {
                "name": "Contributor2",
                "order": 0,
                "role": "",
                "role_other": None,
                "taxonomy_id": "",
                "uri": None
            }])

        tree = self._get_xml_tree_from_data(data)

        creator_tags = tree.findall('.//{}creator'.format(NAMESPACES['dc']))
        self.assertEqual(len(creator_tags), 1)

        creator_tag = creator_tags[0]
        self.assertEqual(creator_tag.text, data['contributors'][0]['name'])

        contributor_tags = tree.findall('.//{}contributor'.format(NAMESPACES['dc']))
        self.assertEqual(len(contributor_tags), 2)

        for index, contributor_tag in enumerate(contributor_tags):
            self.assertEqual(contributor_tag.text, data['contributors'][index+1]['name'])

    def test_render_article_with_video(self):
        """Check that video media:content tag is correctly generated."""
        data = get_json(os.path.join(FIXTURES_FOLDER, 'video.json'))[0]
        video_content = data['alt_bodies']['structured']['content'][0]['video']

        tree = self._get_xml_tree_from_data(data)

        # Check that only exists one media:content tag (video)
        media_tags = tree.findall('.//{}content'.format(NAMESPACES['media']))
        self.assertEqual(len(media_tags), 1)

        media_tree = media_tags[0]
        media_attrs = media_tree.attrib

        # Check the attributes on the video
        self.assertEqual(media_attrs['url'], video_content['uri'])
        self.assertEqual(media_attrs['duration'], str(video_content['duration']))
        self.assertEqual(media_attrs['type'], video_content['mime_type'])
        self.assertEqual(media_attrs['width'], "")
        self.assertEqual(media_attrs['height'], "")
        self.assertEqual(media_attrs['bitrate'], "0")

        # Check that the video has a thumbnail, title and credit
        thumbnail_element = media_tree.find('.//{}thumbnail'.format(NAMESPACES['media']))
        self.assertIsNotNone(thumbnail_element)

        thumbnail_attrs = thumbnail_element.attrib

        self.assertEqual(thumbnail_attrs['url'], video_content['thumbnail'])

        title_element = media_tree.find('.//{}title'.format(NAMESPACES['media']))
        self.assertIsNotNone(title_element)

        self.assertEqual(title_element.text, video_content['title'])

        credit_element = media_tree.find('.//{}credit'.format(NAMESPACES['media']))
        self.assertIsNone(credit_element)

    def test_render_article_with_gallery(self):
        """
        Check that media:group tag that contains media:content tag for
        each image is correctly generated.
        """
        data = get_json(os.path.join(FIXTURES_FOLDER, 'image_gallery.json'))[0]
        gallery_content = data['alt_bodies']['structured']['content'][0]['image_gallery']
        gallery_content['images'][0]['title'] = 'test_title'

        tree = self._get_xml_tree_from_data(data)

        # Check that media:group tag exists
        media_group_tag = tree.find('.//{}group'.format(NAMESPACES['media']))
        self.assertIsNotNone(media_group_tag)

        # Check that media:group tag contains the correct number of media:content tags (images)
        media_tags = media_group_tag.findall('.//{}content'.format(NAMESPACES['media']))
        self.assertEqual(len(media_tags), len(gallery_content['images']))

        # For each media:content (image) we check that the attributes are correct and
        # all the subtags are generated correctly
        for index, tag in enumerate(media_tags):
            media_attrs = tag.attrib
            correspondent_image = gallery_content['images'][index]

            self.assertEqual(media_attrs['height'], str(correspondent_image['height']))
            self.assertEqual(media_attrs['width'], str(correspondent_image['width']))
            self.assertEqual(media_attrs['url'], correspondent_image['uri'])

            title_element = tag.find('.//{}title'.format(NAMESPACES['media']))

            self.assertIsNotNone(title_element)
            self.assertEqual(
                title_element.text,
                correspondent_image.get('title') or sanitize_xml_text(
                    correspondent_image['caption'])
            )

            credit_element = tag.find('.//{}credit'.format(NAMESPACES['media']))
            self.assertIsNotNone(credit_element)

    def test_render_article_with_image_without_title(self):
        """
        Check that image media:content tag is correctly generated,
        the media:title tag has the caption value and media:text tag
        doesn't exists.
        """
        data = get_json(os.path.join(FIXTURES_FOLDER, 'image.json'))[0]
        image_content = data['alt_bodies']['structured']['content'][0]['image']

        tree = self._get_xml_tree_from_data(data)

        # Check that media:group tag does not exists
        media_group_tag = tree.find('.//{}group'.format(NAMESPACES['media']))
        self.assertIsNone(media_group_tag)

        media_tags = tree.findall('.//{}content'.format(NAMESPACES['media']))
        self.assertEqual(len(media_tags), 1)

        media_tag = media_tags[0]
        media_attrs = media_tag.attrib

        self.assertEqual(media_attrs['height'], str(image_content['height']))
        self.assertEqual(media_attrs['width'], str(image_content['width']))
        self.assertEqual(media_attrs['url'], image_content['uri'])

        title_element = media_tag.find('.//{}title'.format(NAMESPACES['media']))

        self.assertIsNotNone(title_element)
        self.assertEqual(
            title_element.text,
            sanitize_xml_text(image_content['caption'])
        )

        credit_element = media_tag.find('.//{}credit'.format(NAMESPACES['media']))
        self.assertIsNotNone(credit_element)

        text_element = media_tag.find('.//{}text'.format(NAMESPACES['media']))
        self.assertIsNone(text_element)

    def test_render_article_image_with_title(self):
        """
        Check that image media:content tag is correctly generated,
        the media:title tag has the title value and media:text tag
        exists with the caption value.
        """
        data = get_json(os.path.join(FIXTURES_FOLDER, 'image.json'))[0]
        image_content = data['alt_bodies']['structured']['content'][0]['image']
        image_content['title'] = 'test_title'

        tree = self._get_xml_tree_from_data(data)

        media_tags = tree.findall('.//{}content'.format(NAMESPACES['media']))
        self.assertEqual(len(media_tags), 1)

        media_tag = media_tags[0]
        media_attrs = media_tag.attrib

        self.assertEqual(media_attrs['height'], str(image_content['height']))
        self.assertEqual(media_attrs['width'], str(image_content['width']))
        self.assertEqual(media_attrs['url'], image_content['uri'])

        title_element = media_tag.find('.//{}title'.format(NAMESPACES['media']))

        self.assertIsNotNone(title_element)
        self.assertEqual(
            title_element.text,
            image_content['title']
        )

        credit_element = media_tag.find('.//{}credit'.format(NAMESPACES['media']))
        self.assertIsNotNone(credit_element)

        text_element = media_tag.find('.//{}text'.format(NAMESPACES['media']))
        self.assertIsNotNone(text_element)

        self.assertEqual(
            text_element.text,
            sanitize_xml_text(image_content['caption'])
        )

    def test_render_article_immersive_lead_image(self):
        """Check that immersive_lead media:content tag is correctly generated."""
        data = get_json(os.path.join(FIXTURES_FOLDER, 'immersive_lead_image.json'))[0]
        image_content = \
            data['alt_bodies']['structured']['content'][0]['immersive_lead']['lead_media']['image']

        tree = self._get_xml_tree_from_data(data)

        # Check that media:group tag does not exists
        media_group_tag = tree.find('.//{}group'.format(NAMESPACES['media']))
        self.assertIsNone(media_group_tag)

        media_tags = tree.findall('.//{}content'.format(NAMESPACES['media']))
        self.assertEqual(len(media_tags), 1)

        media_tag = media_tags[0]
        media_attrs = media_tag.attrib

        self.assertEqual(media_attrs['height'], str(image_content['height']))
        self.assertEqual(media_attrs['width'], str(image_content['width']))
        self.assertEqual(media_attrs['url'], image_content['uri'])

        title_element = media_tag.find('.//{}title'.format(NAMESPACES['media']))

        self.assertIsNotNone(title_element)
        self.assertEqual(
            title_element.text,
            sanitize_xml_text(image_content['caption'])
        )

        credit_element = media_tag.find('.//{}credit'.format(NAMESPACES['media']))
        self.assertIsNotNone(credit_element)

        text_element = media_tag.find('.//{}text'.format(NAMESPACES['media']))
        self.assertIsNone(text_element)

    def test_render_article_immersive_lead_video(self):
        """Check that immersive_lead media:content tag is correctly generated."""
        data = get_json(os.path.join(FIXTURES_FOLDER, 'immersive_lead_video.json'))[0]
        video_content = \
            data['alt_bodies']['structured']['content'][0]['immersive_lead']['lead_media']['video']['video']

        tree = self._get_xml_tree_from_data(data)

        # Check that only exists one media:content tag (video)
        media_tags = tree.findall('.//{}content'.format(NAMESPACES['media']))
        self.assertEqual(len(media_tags), 1)

        media_tree = media_tags[0]
        media_attrs = media_tree.attrib

        # Check the attributes on the video
        self.assertEqual(media_attrs['url'], video_content['uri'])
        self.assertEqual(media_attrs['duration'], str(video_content['duration']))
        self.assertEqual(media_attrs['type'], video_content['mime_type'])
        self.assertEqual(media_attrs['width'], "")
        self.assertEqual(media_attrs['height'], "")
        self.assertEqual(media_attrs['bitrate'], "0")

        # Check that the video has a thumbnail, title and credit
        thumbnail_element = media_tree.find('.//{}thumbnail'.format(NAMESPACES['media']))
        self.assertIsNotNone(thumbnail_element)

        thumbnail_attrs = thumbnail_element.attrib

        self.assertEqual(thumbnail_attrs['url'], video_content['thumbnail'])

        title_element = media_tree.find('.//{}title'.format(NAMESPACES['media']))
        self.assertIsNotNone(title_element)

        self.assertEqual(title_element.text, video_content['title'])

        credit_element = media_tree.find('.//{}credit'.format(NAMESPACES['media']))
        self.assertIsNone(credit_element)

    def test_render_article_immersive_lead_gallery(self):
        """Check that immersive_lead media:content tag is correctly generated."""
        data = get_json(os.path.join(FIXTURES_FOLDER, 'immersive_lead_gallery.json'))[0]
        gallery_content = \
            data['alt_bodies']['structured']['content'][0]['immersive_lead']['lead_media']['image_gallery']

        tree = self._get_xml_tree_from_data(data)

        # Check that media:group tag exists
        media_group_tag = tree.find('.//{}group'.format(NAMESPACES['media']))
        self.assertIsNotNone(media_group_tag)

        # Check that media:group tag contains the correct number of media:content tags (images)
        media_tags = media_group_tag.findall('.//{}content'.format(NAMESPACES['media']))
        self.assertEqual(len(media_tags), len(gallery_content['images']))

        # For each media:content (image) we check that the attributes are correct and
        # all the subtags are generated correctly
        for index, tag in enumerate(media_tags):
            media_attrs = tag.attrib
            correspondent_image = gallery_content['images'][index]

            self.assertEqual(media_attrs['height'], str(correspondent_image['height']))
            self.assertEqual(media_attrs['width'], str(correspondent_image['width']))
            self.assertEqual(media_attrs['url'], correspondent_image['uri'])

            title_element = tag.find('.//{}title'.format(NAMESPACES['media']))

            self.assertIsNotNone(title_element)
            self.assertEqual(
                title_element.text,
                correspondent_image.get('title') or sanitize_xml_text(
                    correspondent_image['caption'])
            )

            credit_element = tag.find('.//{}credit'.format(NAMESPACES['media']))
            self.assertIsNotNone(credit_element)
