# -*- coding: utf-8 -*-
"""Cinematic Home section (docs/plan/skin-milionar/190-cinema.md): the generated include and what it refers to."""
import os
import re
import sys
import unittest

HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
import gen_cinema  # noqa: E402
import gen_slots  # noqa: E402

SKIN = os.path.join(HERE, '..', '..', 'resources', 'skin.milionar')


def read(*parts):
    with open(os.path.join(SKIN, *parts), encoding='utf-8') as handle:
        return handle.read()


class CinemaTests(unittest.TestCase):
    def test_the_committed_include_is_current(self):
        self.assertEqual(read('xml', 'Includes_MilionarCinema.xml'), gen_cinema.build())
        self.assertIn('<include file="Includes_MilionarCinema.xml" />', read('xml', 'Includes.xml'))

    def test_hero_click_is_shared_and_focuses_the_section_primary_button(self):
        text = gen_cinema.build()
        self.assertIn('condition="$PARAM[hero_click] + !String.IsEmpty(Container($PARAM[list_id]).ListItem.Property(milionar.hero.play))">SetFocus($PARAM[hero_target])', text)
        # the card's own click goes to the service while it listens, else the skin runs it itself (gen_slots.run_lines)
        own = '!$PARAM[hero_click] + !String.IsEmpty(Container($PARAM[list_id]).ListItem.Property(milionar.exec))'
        command = '$INFO[Container($PARAM[list_id]).ListItem.Property(milionar.exec)]'
        for line in gen_slots.run_lines(command, '\t\t\t\t', condition=own):
            self.assertIn(line, text)
        # the hero buttons carry the same two lines as text in their templates
        for sec in gen_cinema.SECTIONS:
            for line in gen_slots.run_lines('$VAR[MilCineB1_{}]'.format(sec), '\t\t\t\t\t'):
                self.assertIn(line, text)
        for line in gen_slots.run_lines('$PARAM[action]', '\t\t\t\t'):
            self.assertIn(line, text)
        self.assertNotIn('<onclick>$', text)                                 # no click left that only starts the plugin
        for sec, (base, _menu, _items) in gen_cinema.SECTIONS.items():
            for n in range(1, gen_cinema.SLOTS + 1):
                self.assertIn('String.IsEqual(Skin.String(mil.{}.{}.click),hero)'.format(sec, n), text)
            self.assertIn('<param name="hero_target" value="{}"/>'.format(base + 905), text)   # the buttons' group list
            for control in (901, 902, 903, 904, 906):
                self.assertEqual(text.count('<control type="button" id="{}">'.format(base + control)), 1)
            self.assertIn('<onback>{}</onback>'.format(base + 1), text)         # Back on a hero button: the rows
        # a genre row's own button layout is read from the item its hero borrows
        self.assertIn('<expression name="MilCineUse_my_series_3_1">String.IsEqual(Window(Home).Property(milionar.row.my_series),30300) + '
                      '$EXP[MilCineIs_my_series_1] + !String.IsEmpty(Container(30100).ListItem.Property(milionar.hero.s3))</expression>', text)
        self.assertIn('<value condition="$EXP[MilCineUse_my_series_3_1]">$INFO[Container(30100).ListItem.Property(milionar.hero.s3.b1l)]</value>', text)
        self.assertIn('MilCineUse_cont_', text)                                      # every section works the same way

    def test_sections_use_the_list_ids_of_the_slots(self):
        self.assertEqual(tuple(gen_cinema.SECTIONS), gen_slots.CINEMA)
        slots = read('xml', 'Includes_MilionarSlots.xml')
        for sec, (base, _menu, items) in gen_cinema.SECTIONS.items():
            self.assertEqual(base, gen_slots.SECTIONS[sec])
            self.assertIs(items, gen_cinema.MUSIC if sec == 'vinyl' else gen_cinema.PLUGIN)
            self.assertNotIn('MilionarSlots_' + sec, slots)                          # drawn here, not as Estuary rows
            for n in range(1, gen_cinema.SLOTS + 1):                                 # every row is a plugin list
                self.assertIn('<variable name="MilionarContent_{}_{}">'.format(sec, n), slots)
        self.assertEqual(set(gen_cinema.PLUGIN), set(gen_cinema.MUSIC))              # both kinds answer every question

    def test_home_draws_the_section_with_the_cinema_includes(self):
        home = read('xml', 'Home.xml')
        self.assertEqual(home.count('<include>MilionarCinemaBackdrop</include>'), 1)
        for sec, (base, _menu, _items) in gen_cinema.SECTIONS.items():
            self.assertEqual(home.count('<include>MilionarCinema_{}</include>'.format(sec)), 1)
            self.assertNotIn('<include>MilionarSlots_{}</include>'.format(sec), home)
            self.assertIn('<defaultcontrol>{}</defaultcontrol>'.format(base + 1), home)      # Right from the menu: the rows

    def test_the_hero_reads_exactly_one_row(self):
        """The slot sources exclude each other: a chosen row wins, otherwise the first film row with items."""
        for sec in gen_cinema.SECTIONS:
            for n in range(1, gen_cinema.SLOTS + 1):
                source = gen_cinema.source(sec, n)
                self.assertTrue(source.startswith('[' + gen_cinema.chosen(sec, n) + ']'))
                self.assertEqual(source.count('![Integer.IsGreater'), n - 1)          # no earlier film row has items
            self.assertEqual(gen_cinema.above(sec, gen_cinema.SLOTS), 'false')         # nothing lies under the last slot

    def test_the_include_is_well_formed_and_every_reference_resolves(self):
        import xml.etree.ElementTree as ET
        text = gen_cinema.build()
        root = ET.fromstring(text.encode('utf-8'))
        defined = {kind: {node.get('name') for node in root.findall(kind)} for kind in ('expression', 'variable', 'include')}
        self.assertNotIn('{', re.sub(r'\$[A-Z]+\[', '', text))                         # no unfilled template field
        self.assertTrue(set(re.findall(r'\$EXP\[(MilCine\w+)\]', text)) <= defined['expression'])
        self.assertTrue(set(re.findall(r'\$VAR\[(MilCine\w+)\]', text)) <= defined['variable'])
        self.assertTrue(set(re.findall(r'<include content="(MilCine\w+)"', text)) <= defined['include'])
        self.assertEqual(sum(len(names) for names in defined.values()), sum(len(root.findall(kind)) for kind in defined))   # no duplicate names

    def test_everything_the_include_refers_to_exists(self):
        text = gen_cinema.build()
        for texture in set(re.findall(r'milionar/cinema/[a-z_]+\.png', text)):
            self.assertTrue(os.path.isfile(os.path.join(SKIN, 'media', texture)), texture)
        colours = read('colors', 'defaults.xml')
        for colour in set(re.findall(r'cinema_[a-z]+', text)):
            self.assertIn('<color name="{}">'.format(colour), colours)
        fonts = read('xml', 'Font.xml')
        for font in ('font20', 'font80_title'):
            self.assertEqual(fonts.count('<name>{}</name>'.format(font)), 2)           # both font sets
        for language in ('cs_cz', 'sk_sk', 'en_gb'):
            self.assertIn('msgctxt "#31991"', read('language', 'resource.language.' + language, 'strings.po'))


if __name__ == '__main__':
    unittest.main()
