"""Targeted live-Kodi checks for Vinyl. Returns counts only, never account credentials."""
from urllib.parse import parse_qs, urlsplit

from wcs.vinyl import actions, client, widgets


def start_playback(mode, row='vinyl_curator', index=0):
    import json
    import xbmc
    import xbmcgui
    from urllib.parse import urlencode
    if mode == 'play_from':
        path = widgets.build({'row': row, 'limit': '10', 'sort': 'title', 'click': mode})[index][0]
        params = {k: v[0] for k, v in parse_qs(urlsplit(path).query).items()}
    else:
        source, kind, _label = widgets.ROWS[row]
        params = widgets.query(client.cached(source)[index], kind, row, mode)
        path = widgets.BASE + '?' + urlencode(params)
    songs = actions._songs(params)
    state = {'mode': mode, 'ids': [str(s['id']) for s in songs],
             'before': xbmc.PlayList(xbmc.PLAYLIST_MUSIC).size()}
    xbmcgui.Window(10000).setProperty('milionar.vinyl.probe', json.dumps(state))
    xbmc.executebuiltin('RunPlugin({})'.format(path))
    return {'mode': mode, 'expected': len(songs)}


def check_playback():
    import json
    import xbmc
    import xbmcgui
    state = json.loads(xbmcgui.Window(10000).getProperty('milionar.vinyl.probe'))
    playlist = xbmc.PlayList(xbmc.PLAYLIST_MUSIC)
    actual = [urlsplit(playlist[i].getPath().split('|')[0]).path.rsplit('/', 1)[-1]
              for i in range(playlist.size())]
    expected = state['ids']
    if state['mode'] == 'queue':
        assert playlist.size() == state['before'] + len(expected)
        assert actual[-len(expected):] == expected
    elif state['mode'] == 'shuffle':
        assert sorted(actual) == sorted(expected)
        if len(expected) > 1:
            assert actual != expected
    else:
        assert actual == expected
    assert xbmc.Player().isPlayingAudio()
    assert xbmc.Player().getTime() > 0
    assert xbmc.Player().getPlayingFile().startswith(client.BASE)
    return {'mode': state['mode'], 'playlist_size': playlist.size(), 'audio_playing': True,
            'seconds': round(xbmc.Player().getTime(), 1), 'proxy': True}


def verify():
    result = {}
    for row, (source, kind, _label) in widgets.ROWS.items():
        cached = client.cached(source)
        counts = []
        for limit in (10, 20, 30, 50):
            built = widgets.build({'row': row, 'limit': str(limit), 'sort': 'source'})
            assert len(built) == min(len(cached), limit), (row, limit)
            counts.append(len(built))
        ordered = widgets.build({'row': row, 'limit': '50', 'sort': 'title'})
        labels = [li.getLabel().casefold() for _, li, _ in ordered]
        assert labels == sorted(labels), row
        if cached:
            songs = actions._songs(widgets.query(cached[0], kind, row, 'play'))
            assert songs, row
            cover = client.cover(cached[0], kind)
            assert cover.startswith(client.BASE) or kind == 'genre', row
        result[row] = {'available': len(cached), 'counts': counts}
    # "Play from" follows the displayed order, even when alphabetically sorted or shuffled.
    row = 'vinyl_favorite_songs'
    built = widgets.build({'row': row, 'limit': '10', 'sort': 'title', 'click': 'play_from'})
    if len(built) >= 3:
        params = {k: v[0] for k, v in parse_qs(urlsplit(built[2][0]).query).items()}
        songs = actions._songs(params)
        expected = [parse_qs(urlsplit(path).query)['id'][0] for path, _, _ in built[2:]]
        assert [str(s['id']) for s in songs] == expected
    playlists = client.request('playlists')['playlists']
    assert {p['id'] for p in client.cached('playlists')} == {p['id'] for p in playlists if p.get('is_owner')}
    assert {p['id'] for p in client.cached('favorite_playlists')} == {p['id'] for p in playlists if p.get('is_favorite')}
    return result


def verify_media_and_cache():
    import hashlib
    import requests
    from pathlib import Path
    result = {}
    for row, (source, kind, _label) in widgets.ROWS.items():
        entries = client.cached(source)
        if not entries:
            continue
        cover = client.cover(entries[0], kind)
        if cover.startswith(client.BASE):
            with requests.get(cover.split('|')[0], headers={'Authorization': 'Bearer anonymous'},
                              stream=True, timeout=(5, 20)) as response:
                assert response.ok and response.headers.get('Content-Type', '').startswith('image/'), row
        songs = actions._songs(widgets.query(entries[0], kind, row, 'play'))
        with requests.get(client.media('stream/{}'.format(songs[0]['id'])).split('|')[0],
                          headers={'Authorization': 'Bearer anonymous', 'Range': 'bytes=0-63'},
                          stream=True, timeout=(5, 20)) as response:
            assert response.status_code == 206, row
            assert next(response.iter_content(64)), row
        result[row] = True
    path = Path(client.cache_path('curator'))
    before = hashlib.sha256(path.read_bytes()).hexdigest()
    original = client.sources
    try:
        def unavailable():
            raise RuntimeError('test unavailable')
        client.sources = unavailable
        from wcs.skin import refresher
        assert refresher.refresh(client.addon(), 'vinyl') is False
    finally:
        client.sources = original
    assert hashlib.sha256(path.read_bytes()).hexdigest() == before
    result['last_good_cache_preserved'] = True
    return result
