import json

import xbmc


TARGET_SKIN = 'skin.aeon.nox.silvo'
TARGET_FONT = 'Arial'


def _rpc(method, params):
    request = {
        'jsonrpc': '2.0',
        'id': 1,
        'method': method,
        'params': params,
    }
    try:
        response = json.loads(xbmc.executeJSONRPC(json.dumps(request)))
    except (TypeError, ValueError):
        return None
    if response.get('error'):
        xbmc.log(
            'The KWTV Wizard: JSON-RPC {0} failed: {1}'.format(
                method, response['error']
            ),
            xbmc.LOGERROR,
        )
        return None
    return response.get('result')


def _get_setting(setting_id):
    result = _rpc('Settings.GetSettingValue', {'setting': setting_id})
    return result.get('value') if isinstance(result, dict) else None


def _set_setting(setting_id, value):
    result = _rpc(
        'Settings.SetSettingValue',
        {'setting': setting_id, 'value': value},
    )
    return result is not None


def _accept_skin_change():
    # Kodi asks whether the newly selected skin should be kept. Accept only
    # while that confirmation dialog is visible, so no unrelated window is hit.
    for _ in range(20):
        if xbmc.getCondVisibility('Window.IsVisible(yesnodialog)'):
            xbmc.executebuiltin('SendClick(11)')
            return
        xbmc.sleep(250)


def enforce_kwtv_look_and_feel():
    """Ensure each Kodi session uses Aeon Nox: SiLVO with its Arial fontset."""
    changed = False
    current_skin = _get_setting('lookandfeel.skin')

    if current_skin != TARGET_SKIN:
        if not xbmc.getCondVisibility('System.HasAddon({0})'.format(TARGET_SKIN)):
            xbmc.log(
                'The KWTV Wizard: cannot select {0}; the skin is not installed '
                'or enabled'.format(TARGET_SKIN),
                xbmc.LOGERROR,
            )
            return False
        if not _set_setting('lookandfeel.skin', TARGET_SKIN):
            return False
        changed = True
        _accept_skin_change()

        # Allow the new skin to finish loading before selecting its fontset.
        for _ in range(20):
            if _get_setting('lookandfeel.skin') == TARGET_SKIN:
                break
            xbmc.sleep(250)

    current_font = _get_setting('lookandfeel.font')
    if not isinstance(current_font, str) or current_font.lower() != TARGET_FONT.lower():
        if _set_setting('lookandfeel.font', TARGET_FONT):
            changed = True

    if changed:
        xbmc.executebuiltin('ReloadSkin()')
    return True
