# -*- coding: utf-8 -*-
"""Shared watch progress of the channels (MyTV / MyCinema) and the library: wcs/library2/shared.py, the channel history
bridge, the tracker contract of a channel's play and the MyTV rows of Home."""
import json
import os
import sys
import tempfile
import unittest
from unittest.mock import patch

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

PROFILE = stubs.install()

import xbmc  # noqa: E402
import xbmcaddon  # noqa: E402
import xbmcgui  # noqa: E402

from test_autoplay import FakePlayer, TestEngine  # noqa: E402
from wcs.ai import ChannelHistory, ProgressManager, channel_play  # noqa: E402
from wcs.library2 import meta, play, shared, store  # noqa: E402
from wcs.skin import refresh, widgets  # noqa: E402

SHOW, OTHER, MOVIE = 77, 78, 55
ADDON_PROFILE = os.path.join(PROFILE, 'addon_data', 'plugin.video.milionar')


def seed_show(show_id, name='Serial', seasons=((1, 5), (2, 3))):
    meta.put(meta.key_tv(show_id), {
        'id': show_id, 'name': name, 'status': 'Ended', 'first_air_date': '2020-01-01', 'backdrop_path': '/b{}.jpg'.format(show_id),
        'number_of_seasons': len(seasons),
        'seasons': [{'season_number': n, 'episode_count': count} for n, count in seasons]}, 10 ** 9)
    for number, count in seasons:
        meta.put(meta.key_season(show_id, number), {
            'season_number': number,
            'episodes': [{'episode_number': e, 'name': 'S{}E{}'.format(number, e), 'air_date': '2020-0{}-0{}'.format(number, e),
                          'overview': 'Plot {}x{}'.format(number, e)} for e in range(1, count + 1)]}, 10 ** 9)


class Base(unittest.TestCase):
    CHANNELS = [{'id': 'c1', 'name': 'Komedie', 'icon': 'i.png',
                 'media_list': [{'id': SHOW, 'name': 'Serial', 'poster_path': '/p.jpg', 'year': '2020'},
                                {'id': OTHER, 'name': 'Druhy', 'poster_path': '/q.jpg', 'year': '2020'}]}]

    def setUp(self):
        self.root = tempfile.mkdtemp(prefix='milionar-shared-')
        store.set_path(os.path.join(self.root, 'library.db'))
        xbmcgui.Window.props.clear()
        xbmcaddon.Addon.settings.clear()
        xbmcaddon.Addon.settings.update({'lib_resume_min_seconds': '180', 'autoplay_countdown_seconds': '45',
                                         'autoplay_trigger_seconds': '15', 'autoplay_enabled_global': 'true'})
        seed_show(SHOW)
        seed_show(OTHER, 'Druhy')
        self.history_dir = tempfile.mkdtemp(prefix='milionar-history-')
        patcher = patch.object(ChannelHistory, '_get_history_dir', lambda channel_type='tv': self.history_dir)
        patcher.start()
        self.addCleanup(patcher.stop)
        patcher = patch.object(shared, '_profile', lambda: self.root)
        patcher.start()
        self.addCleanup(patcher.stop)
        os.makedirs(os.path.join(self.root, 'mytv_history'), exist_ok=True)
        with open(os.path.join(self.root, 'mytv_channels.json'), 'w', encoding='utf-8') as handle:
            json.dump(self.CHANNELS, handle)

    def share(self, on=True):
        xbmcaddon.Addon.settings['mytv_shared_progress'] = 'true' if on else 'false'
        store.set_flag(shared.FLAG, '1' if on else '0')

    def history(self, data, channel='c1'):
        with open(os.path.join(self.history_dir, '{}.json'.format(channel)), 'w', encoding='utf-8') as handle:
            json.dump(data, handle)

    def watched(self, show=SHOW):
        return sorted(key for key, row in shared._states(show).items() if row['playcount'] > 0)


class SwitchTests(Base):
    def test_on_by_default_but_inactive_until_the_channels_were_merged(self):
        self.assertTrue(shared.enabled('tv'))
        self.assertFalse(shared.active('tv'))                    # no merge yet: the channels keep their files
        self.assertTrue(shared.pending())
        store.set_flag(shared.FLAG, '1')
        self.assertTrue(shared.active('tv'))
        self.assertFalse(shared.pending())

    def test_switched_off(self):
        self.share(True)
        xbmcaddon.Addon.settings['mytv_shared_progress'] = 'false'
        self.assertFalse(shared.active('tv'))
        self.assertTrue(shared.pending())                        # the channels must take over the store's state

    def test_cinema_has_its_own_switch_and_needs_no_merge(self):
        self.assertTrue(shared.active('cinema'))
        xbmcaddon.Addon.settings['mycinema_shared_progress'] = 'false'
        self.assertFalse(shared.active('cinema'))
        self.assertTrue(shared.enabled('tv'))

    def test_series_state_refreshes_the_mytv_rows_only_when_shared(self):
        self.assertTrue(shared.MYTV_ROWS <= refresh.media_rows('tv'))
        self.assertFalse(shared.MYTV_ROWS & refresh.media_rows('movie'))
        xbmcaddon.Addon.settings['mytv_shared_progress'] = 'false'
        self.assertFalse(shared.MYTV_ROWS & refresh.media_rows('tv'))


class PointerTests(Base):
    def test_nothing_watched(self):
        self.assertEqual(shared.pointer(SHOW), (1, 0))
        self.assertIsNone(shared.resume(SHOW))
        self.assertEqual(shared.pointer('not-a-number'), (1, 0))

    def test_after_the_latest_watched_by_order(self):
        store.mark_watched('tv', SHOW, 1, 1)
        store.mark_watched('tv', SHOW, 1, 3)
        self.assertEqual(shared.pointer(SHOW), (1, 3))

    def test_an_episode_in_progress_is_the_next_one(self):
        store.mark_many('tv', SHOW, [(1, 1), (1, 3), (1, 4), (1, 5)], True)
        store.save_resume('tv', SHOW, 600, 1300, 1, 2)                       # an earlier episode left unfinished
        self.assertEqual(shared.pointer(SHOW), (1, 1))
        self.assertEqual(shared.resume(SHOW), {'season': 1, 'episode': 2, 'position': 600.0, 'total': 1300.0})
        store.mark_watched('tv', SHOW, 1, 2)                                 # like Continue: a watched episode is done
        self.assertEqual(shared.pointer(SHOW), (1, 5))

    def test_first_episode_of_a_later_season_in_progress(self):
        store.save_resume('tv', SHOW, 300, 1300, 2, 1)
        self.assertEqual(shared.pointer(SHOW), (1, shared.BEFORE_FIRST))
        self.assertEqual(shared.before(1, 1), (1, 0))

    def test_specials_are_ignored(self):
        store.mark_watched('tv', SHOW, 0, 4)
        self.assertEqual(shared.pointer(SHOW), (1, 0))

    def test_movies(self):
        self.assertFalse(shared.movie_watched(MOVIE))
        self.assertIsNone(shared.movie_resume(MOVIE))
        store.save_resume('movie', MOVIE, 900, 6000)
        self.assertEqual(shared.movie_resume(MOVIE)['position'], 900.0)
        store.mark_watched('movie', MOVIE)
        self.assertTrue(shared.movie_watched(MOVIE))
        self.assertIsNone(shared.movie_resume(MOVIE))


class ChannelHistoryTests(Base):
    def test_separate_world_reads_the_channel_file(self):
        self.share(False)
        self.history({str(SHOW): {'season': 1, 'episode': 2, 'resume_position': 50, 'resume_total': 100,
                                  'resume_s': 1, 'resume_e': 3}})
        store.mark_watched('tv', SHOW, 2, 1)
        self.assertEqual(ChannelHistory.get_series_progress('c1', SHOW), (1, 2))
        self.assertEqual(ChannelHistory.get_resume_point('c1', SHOW)['position'], 50)
        self.assertEqual(ProgressManager.get_progress('c1', SHOW), (1, 2))

    def test_shared_world_reads_the_store(self):
        self.share(True)
        self.history({str(SHOW): {'season': 1, 'episode': 2}})
        store.mark_many('tv', SHOW, [(1, 1), (1, 2), (1, 3)], True)
        store.save_resume('tv', SHOW, 700, 1300, 1, 4)
        self.assertEqual(ChannelHistory.get_series_progress('c1', SHOW), (1, 3))
        self.assertEqual(ChannelHistory.get_series_progress('other-channel', SHOW), (1, 3))    # one progress per series
        self.assertEqual(ChannelHistory.get_resume_point('c1', SHOW),
                         {'season': 1, 'episode': 4, 'position': 700.0, 'total': 1300.0})

    def test_the_channel_monitor_does_not_write_the_store(self):
        """Playback is written by the service tracker; the monitor's own notes stay in the channel file."""
        self.share(True)
        ChannelHistory.update_series_progress('c1', SHOW, 1, 4)
        ChannelHistory.set_resume_point('c1', SHOW, 1, 5, 400, 1300)
        self.assertEqual(shared._states(SHOW), {})
        self.assertEqual(ChannelHistory.load_channel_history('c1')[str(SHOW)]['episode'], 4)

    def test_manual_edit_moves_the_library(self):
        self.share(True)
        store.mark_many('tv', SHOW, [(1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (2, 1)], True)
        store.save_resume('tv', SHOW, 500, 1300, 2, 2)
        ProgressManager.update_progress('c1', SHOW, 1, 2)                    # "continue with S01E03"
        self.assertEqual(self.watched(), [(1, 1), (1, 2)])
        self.assertIsNone(shared.resume(SHOW))
        self.assertEqual(ProgressManager.get_progress('c1', SHOW), (1, 2))

    def test_manual_edit_to_the_start_of_a_season(self):
        self.share(True)
        ProgressManager.update_progress('c1', SHOW, 1, shared.BEFORE_FIRST)  # "continue with S02E01"
        self.assertEqual(self.watched(), [(1, 1), (1, 2), (1, 3), (1, 4), (1, 5)])
        ProgressManager.update_progress('c1', SHOW, 1, 0)                    # back to the very beginning
        self.assertEqual(self.watched(), [])

    def test_manual_edit_in_the_separate_world_leaves_the_store(self):
        self.share(False)
        ProgressManager.update_progress('c1', SHOW, 1, 2)
        self.assertEqual(shared._states(SHOW), {})
        self.assertEqual(ChannelHistory.get_series_progress('c1', SHOW), (1, 2))

    def test_cinema(self):
        ChannelHistory.mark_movie_watched('k1', MOVIE)                       # "it was on in this cinema"
        self.assertFalse(ChannelHistory.is_movie_watched('k1', MOVIE))       # shared: the library decides
        store.save_resume('movie', MOVIE, 900, 6000)
        self.assertEqual(ChannelHistory.get_movie_resume_point('k1', MOVIE)['position'], 900.0)
        store.mark_watched('movie', MOVIE)
        self.assertTrue(ChannelHistory.is_movie_watched('k1', MOVIE))
        xbmcaddon.Addon.settings['mycinema_shared_progress'] = 'false'
        store.mark_unwatched('movie', MOVIE)
        self.assertTrue(ChannelHistory.is_movie_watched('k1', MOVIE))        # separate: the cinema's own note
        self.assertIsNone(ChannelHistory.get_movie_resume_point('k1', MOVIE))

    def test_resume_seek_belongs_to_its_episode(self):
        self.share(True)
        store.save_resume('tv', SHOW, 700, 1300, 1, 4)
        seeks = []

        class Player(xbmc.Player):
            def isPlaying(self):
                return True

            def getTime(self):
                return 1.0

            def seekTime(self, seconds):
                seeks.append(seconds)
        with patch.object(xbmc, 'Player', Player):
            channel_play._seek_to_resume('c1', str(SHOW), '1', '5')          # the queue starts with another episode
            self.assertEqual(seeks, [])
            channel_play._seek_to_resume('c1', str(SHOW), '1', '4')
            self.assertEqual(seeks, [700.0])


class SyncTests(Base):
    def test_switch_on_the_further_progress_wins(self):
        self.history({str(SHOW): {'season': 1, 'episode': 3, 'resume_position': 600, 'resume_total': 1300,
                                  'resume_s': 1, 'resume_e': 4},
                      str(OTHER): {'season': 1, 'episode': 1}})
        store.mark_many('tv', OTHER, [(1, 1), (1, 2), (1, 3), (1, 4)], True)      # the library is further here
        self.assertTrue(shared.sync(network=False))
        self.assertEqual(self.watched(SHOW), [(1, 1), (1, 2), (1, 3)])
        self.assertEqual(shared.resume(SHOW), {'season': 1, 'episode': 4, 'position': 600.0, 'total': 1300.0})
        self.assertEqual(self.watched(OTHER), [(1, 1), (1, 2), (1, 3), (1, 4)])
        self.assertTrue(store.is_in_list('tv', SHOW))                        # played from a channel: in My series
        self.assertTrue(shared.active('tv'))
        self.assertEqual(ChannelHistory.get_series_progress('c1', SHOW), (1, 3))
        self.assertTrue(shared.sync(network=False))                          # nothing left, nothing counted twice
        self.assertEqual(store.get_state('tv', SHOW, 1, 1)['playcount'], 1)

    def test_a_series_never_played_in_a_channel_is_left_alone(self):
        self.history({})
        self.assertTrue(shared.sync(network=False))
        self.assertEqual(shared._states(SHOW), {})
        self.assertFalse(store.is_in_list('tv', SHOW))

    def test_a_short_or_finished_resume_point_is_not_taken(self):
        self.history({str(SHOW): {'season': 1, 'episode': 2, 'resume_position': 20, 'resume_total': 1300,
                                  'resume_s': 1, 'resume_e': 3}})
        self.assertTrue(shared.sync(network=False))
        self.assertIsNone(shared.resume(SHOW))                               # 20 s is under the library's threshold

    def test_missing_metadata_keeps_the_channels_separate_until_it_arrives(self):
        self.history({str(SHOW): {'season': 1, 'episode': 3}})
        meta.delete(meta.key_season(SHOW, 2))
        self.assertFalse(shared.sync(network=False))
        self.assertFalse(shared.active('tv'))
        self.assertEqual(ChannelHistory.get_series_progress('c1', SHOW), (1, 3))     # still the channel file
        seed_show(SHOW)
        self.assertTrue(shared.sync(network=False))
        self.assertEqual(self.watched(SHOW), [(1, 1), (1, 2), (1, 3)])

    def test_switch_off_the_channels_take_over_the_current_state(self):
        self.share(True)
        self.history({str(SHOW): {'season': 1, 'episode': 1}})
        store.mark_many('tv', SHOW, [(1, 1), (1, 2), (1, 3), (1, 4)], True)
        store.save_resume('tv', SHOW, 800, 1300, 1, 5)
        xbmcaddon.Addon.settings['mytv_shared_progress'] = 'false'
        self.assertTrue(shared.sync(network=False))
        self.assertFalse(shared.active('tv'))
        entry = ChannelHistory.load_channel_history('c1')[str(SHOW)]
        self.assertEqual((entry['season'], entry['episode']), (1, 4))
        self.assertEqual((entry['resume_s'], entry['resume_e'], entry['resume_position']), (1, 5, 800.0))
        self.assertEqual(ChannelHistory.get_series_progress('c1', SHOW), (1, 4))
        self.assertEqual(ChannelHistory.get_resume_point('c1', SHOW)['position'], 800.0)
        self.assertNotIn(str(OTHER), ChannelHistory.load_channel_history('c1'))      # no state: its file entry stays out

    def test_off_from_the_first_run_touches_nothing(self):
        xbmcaddon.Addon.settings['mytv_shared_progress'] = 'false'
        self.history({str(SHOW): {'season': 1, 'episode': 2}})
        store.mark_many('tv', SHOW, [(1, 1), (1, 2), (1, 3), (1, 4)], True)
        self.assertTrue(shared.sync(network=False))
        self.assertEqual(ChannelHistory.load_channel_history('c1')[str(SHOW)], {'season': 1, 'episode': 2})
        self.assertFalse(shared.pending())


class ContractTests(Base):
    STREAM = 'https://cdn.example/channel.mkv'

    def engine(self):
        self.clock = [1000.0]
        self.player = FakePlayer()
        return TestEngine(self.player, xbmc.Monitor(), now=lambda: self.clock[0])

    def begin(self, engine, total=1300.0, stream=None):
        self.player.file, self.player.total, self.player.time = stream or self.STREAM, total, 0.0
        engine.handle('started', self.clock[0])

    def at(self, engine, position):
        self.clock[0] += 20
        self.player.time = position
        engine.tick()
        while not self.player.events.empty():
            engine.handle(*self.player.events.get_nowait())

    def test_request_options_reach_the_resolver(self):
        canonical = 'plugin://plugin.video.milionar/?action=mplay&type=episode&tmdb=77&s=1&e=2'
        play.request(canonical, start='resume', origin=play.ORIGIN_CHANNEL, follow=False)
        self.assertEqual(play.consume(canonical), {'src': 'dialog', 'from': 'resume', 'pick': None,
                                                   'origin': 'channel', 'follow': False})
        play.request(canonical)
        self.assertEqual(play.consume(canonical), {'src': 'dialog', 'from': 'start', 'pick': None})

    def test_playlist_item_of_a_channel_is_tracked_without_library_autoplay(self):
        engine = self.engine()
        shared.contract('tv', SHOW, self.STREAM, {'ident': 'x', 'provider': 'webshare', 'name': 'f.mkv'}, 1, 2,
                        title='S1E2', show_title='Serial')
        self.begin(engine)
        self.assertFalse(engine.session.follow)
        self.assertTrue(store.is_in_list('tv', SHOW))                        # played from a channel: joins My series
        self.at(engine, 600)
        self.assertEqual(shared.resume(SHOW)['position'], 600.0)
        self.at(engine, 1290)                                                # inside the countdown: no library dialog
        self.assertEqual((engine.dialogs, engine.played), ([], []))
        engine.handle('ended', self.clock[0])
        self.assertEqual(self.watched(), [(1, 2)])
        self.assertEqual((engine.played, engine.notes), ([], []))            # the channel starts what comes next
        self.assertEqual(store.recent_logs(1)[0]['outcome'], 'watched')

    def test_the_channel_moves_on_at_its_countdown(self):
        engine = self.engine()
        shared.contract('tv', SHOW, self.STREAM, {'ident': 'x'}, 1, 2)
        self.begin(engine)
        self.at(engine, 1260)                                                # 40 s left: the channel's countdown point
        shared.contract('tv', SHOW, self.STREAM + '?2', {'ident': 'y'}, 1, 3)
        self.begin(engine, stream=self.STREAM + '?2')
        self.assertEqual(self.watched(), [(1, 2)])
        self.assertEqual((engine.session.np['s'], engine.session.np['e']), (1, 3))

    def test_a_skipped_item_stays_in_progress(self):
        engine = self.engine()
        shared.contract('tv', SHOW, self.STREAM, {'ident': 'x'}, 1, 2)
        self.begin(engine)
        self.at(engine, 400)
        shared.contract('tv', OTHER, self.STREAM + '?2', {'ident': 'y'}, 1, 1)
        self.begin(engine, stream=self.STREAM + '?2')
        self.assertEqual(self.watched(), [])
        self.assertEqual(shared.resume(SHOW), {'season': 1, 'episode': 2, 'position': 400.0, 'total': 1300.0})

    def test_a_cinema_film_joins_my_movies(self):
        meta.put(meta.key_movie(MOVIE), {'id': MOVIE, 'title': 'Film', 'release_date': '2001-02-03', 'genres': []}, 10 ** 9)
        engine = self.engine()
        shared.contract('movie', MOVIE, self.STREAM, {'ident': 'x'}, title='Film')
        self.begin(engine, total=6000.0)
        self.assertTrue(store.is_in_list('movie', MOVIE))
        self.at(engine, 900)
        engine.handle('stopped', self.clock[0])
        self.assertEqual(shared.movie_resume(MOVIE)['position'], 900.0)

    def test_a_library_play_keeps_its_autoplay(self):
        engine = self.engine()
        play.contract({'type': 'episode', 'tmdb': SHOW, 's': 1, 'e': 2}, self.STREAM, {'ident': 'x'})
        self.begin(engine)
        self.assertTrue(engine.session.follow)
        self.assertFalse(store.is_in_list('tv', SHOW))                       # a plain play adds nothing to the list


class HomeRowTests(Base):
    def setUp(self):
        super().setUp()
        self._read = widgets._read_json
        widgets._read_json = lambda name, default: self.CHANNELS if name == 'mytv_channels.json' else default
        self.addCleanup(setattr, widgets, '_read_json', self._read)
        self.queue = {}
        cache = type('Cache', (), {'get': lambda _self, key, default=None: self.queue.get(key, default)})()
        patcher = patch('wcs.caching.get_cache_manager', lambda: cache)
        patcher.start()
        self.addCleanup(patcher.stop)
        xbmcaddon.Addon.strings.update({32701: 'Právě běží', 32549: '{} min zbývá', 32554: 'Kanál'})
        self.addCleanup(xbmcaddon.Addon.strings.clear)

    def next_row(self):
        return {item.tag.values['TvShowTitle']: item for item in widgets.widget_mytv_next({'click': 'play'})}

    def test_shared_next_episodes_follow_the_library(self):
        self.share(True)
        self.history({str(SHOW): {'season': 2, 'episode': 2}})               # the channel file is not asked
        store.mark_many('tv', SHOW, [(1, 1), (1, 2)], True)
        store.save_resume('tv', SHOW, 650, 1300, 1, 3)
        row = self.next_row()
        item = row['Serial']
        self.assertEqual((item.tag.values['Season'], item.tag.values['Episode']), (1, 3))
        self.assertEqual(item.tag.values['ResumePoint'], (650.0, 1300.0))
        self.assertEqual(item.getProperty('milionar.hero.resumable'), '1')
        self.assertIn('11 min zbývá', item.getProperty('milionar.hero.left'))
        self.assertIn('mytv_channel_id%3Dc1', item.getPath())
        other = row['Druhy']                                                 # not started: its first episode, no bar
        self.assertEqual((other.tag.values['Season'], other.tag.values['Episode']), (1, 1))
        self.assertNotIn('ResumePoint', other.tag.values)
        self.assertEqual(other.getProperty('milionar.hero.resumable'), '')

    def test_shared_finished_series_leaves_the_row(self):
        self.share(True)
        store.mark_many('tv', SHOW, [(1, n) for n in range(1, 6)] + [(2, n) for n in range(1, 4)], True)
        self.assertNotIn('Serial', self.next_row())

    def test_separate_next_episodes_follow_the_channel_and_show_its_resume(self):
        self.share(False)
        self.history({str(SHOW): {'season': 1, 'episode': 3, 'resume_position': 300, 'resume_total': 1200,
                                  'resume_s': 1, 'resume_e': 4}})
        store.mark_many('tv', SHOW, [(1, 1)], True)
        item = self.next_row()['Serial']
        self.assertEqual((item.tag.values['Season'], item.tag.values['Episode']), (1, 4))
        self.assertEqual(item.tag.values['ResumePoint'], (300.0, 1200.0))

    def test_channel_hero_shows_what_is_on_now_from_the_queue(self):
        self.share(True)
        store.mark_many('tv', OTHER, [(1, 1)], True)
        store.save_resume('tv', OTHER, 600, 1200, 1, 2)
        self.queue['program_list_c1'] = [
            {'properties': {'tmdb_id': str(OTHER), 'series_name': 'Druhy', 'season': '1', 'episode': '1', 'ep_code': 'S01E01'}},
            {'properties': {'tmdb_id': str(OTHER), 'series_name': 'Druhy', 'season': '1', 'episode': '2', 'ep_code': 'S01E02',
                            'episode_title': 'Dvojka', 'plot': 'O cem to je.'}},
            {'properties': {'tmdb_id': str(SHOW), 'series_name': 'Serial', 'season': '1', 'episode': '1', 'ep_code': 'S01E01'}}]
        item = widgets.widget_mytv_channels({})[0]
        self.assertEqual(item.getProperty('milionar.hero.title'), 'Komedie')
        # the lines of any hero: the badge with the series where a title has its rating, then the episode and its plot
        self.assertEqual((item.getProperty('milionar.hero.badge'), item.getProperty('milionar.hero.now')), ('PRÁVĚ BĚŽÍ', 'Druhy'))
        self.assertEqual(item.getProperty('milionar.hero.plot'), 'S1 · E2 · Dvojka[CR]O cem to je.')       # E1 is watched
        self.assertEqual(item.getProperty('milionar.hero.rating'), '')
        self.assertEqual(item.getProperty('milionar.hero.left'), 'S1 · E2 · 10 min zbývá')
        self.assertEqual(item.getProperty('milionar.hero.resumable'), '1')
        self.assertEqual(item.tag.values['ResumePoint'], (600.0, 1200.0))
        self.assertTrue(item.getProperty('milionar.hero.fanart').endswith('/b{}.jpg'.format(OTHER)))

    def test_channel_hero_without_a_queue_takes_the_first_series(self):
        self.share(True)
        store.mark_many('tv', SHOW, [(1, 1), (1, 2)], True)
        item = widgets.widget_mytv_channels({})[0]
        self.assertEqual((item.getProperty('milionar.hero.badge'), item.getProperty('milionar.hero.now')), ('PRÁVĚ BĚŽÍ', 'Serial'))
        self.assertEqual(item.getProperty('milionar.hero.plot'), 'S1 · E3 · S1E3[CR]Plot 1x3')
        self.assertEqual(item.getProperty('milionar.hero.left'), '')
        self.assertEqual(item.getProperty('milionar.hero.resumable'), '')

    def test_channel_without_a_program_keeps_its_titles(self):
        self.share(True)
        for show in (SHOW, OTHER):
            store.mark_many('tv', show, [(1, n) for n in range(1, 6)] + [(2, n) for n in range(1, 4)], True)
        item = widgets.widget_mytv_channels({})[0]
        self.assertEqual(item.getProperty('milionar.hero.plot'), 'Serial, Druhy')
        self.assertEqual(item.getProperty('milionar.hero.badge'), '')

    def test_other_heroes_have_no_badge(self):
        self.share(True)
        item = widgets.widget_mytv_next({'click': 'play'})[0]
        self.assertEqual((item.getProperty('milionar.hero.badge'), item.getProperty('milionar.hero.now')), ('', ''))


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