import os
import platform
import shutil
from dataclasses import asdict
from logging import getLogger
from pathlib import Path

import vdf

from rare.models.steam import SteamShortcut, SteamUser
from rare.utils.paths import (
    desktop_icon_path,
    get_rare_executable,
    image_icon_path,
    image_tall_path,
    image_wide_path,
)

if platform.system() == 'Windows':
    # noinspection PyUnresolvedReferences
    import winreg  # pylint: disable=E0401

logger = getLogger('SteamShortcuts')

steam_client_install_paths = [os.path.expanduser('~/.local/share/Steam')]


def find_steam() -> str | None:
    if platform.system() == 'Windows':
        # Find the Steam install directory or raise an error
        try:  # 32-bit
            key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Valve\\Steams')
        except FileNotFoundError:
            try:  # 64-bit
                key = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 'SOFTWARE\\Wow6432Node\\Valve\\Steam')
            except FileNotFoundError:
                return None
        return winreg.QueryValueEx(key, 'InstallPath')[0]
    # return the first valid path
    elif platform.system() in {'Linux', 'FreeBSD'}:
        for path in steam_client_install_paths:
            if os.path.isdir(path) and os.path.isfile(os.path.join(path, 'steam.sh')):
                return path
    return None


def find_steam_users(steam_path: str) -> list[SteamUser]:
    _users = []
    vdf_path = os.path.join(steam_path, 'config', 'loginusers.vdf')
    if not os.path.exists(vdf_path):
        return _users
    with open(vdf_path, encoding='utf-8') as f:
        users = vdf.load(f).get('users', {})
    for long_id, user in users.items():
        _users.append(SteamUser(long_id, user))
    return _users


def _load_shortcuts(steam_path: str, user: SteamUser) -> dict[str, SteamShortcut]:
    _shortcuts = {}
    vdf_path = os.path.join(steam_path, 'userdata', str(user.short_id), 'config', 'shortcuts.vdf')
    if not os.path.exists(vdf_path):
        return _shortcuts
    with open(vdf_path, 'rb') as f:
        shortcuts = vdf.binary_load(f).get('shortcuts', {})
    for idx, shortcut in shortcuts.items():
        _shortcuts[idx] = SteamShortcut.from_dict(shortcut)
    return _shortcuts


def _save_shortcuts(steam_path: str, user: SteamUser, shortcuts: dict[str, SteamShortcut]) -> None:
    _shortcuts = {k: asdict(v) for k, v in shortcuts.items()}
    vdf_path = os.path.join(steam_path, 'userdata', str(user.short_id), 'config', 'shortcuts.vdf')
    with open(vdf_path, 'wb') as f:
        vdf.binary_dump({'shortcuts': _shortcuts}, f)


__steam_dir: str | None = None
__steam_user: SteamUser | None = None
__steam_shortcuts: dict | None = None


def steam_shortcuts_supported() -> bool:
    return __steam_dir is not None and __steam_user is not None and __steam_shortcuts is not None


def load_steam_shortcuts():
    global __steam_shortcuts, __steam_dir, __steam_user

    if __steam_shortcuts is not None:
        return

    steam_dir = find_steam()
    if not steam_dir:
        logger.error('Failed to find Steam install directory')
        return
    __steam_dir = steam_dir

    steam_users = find_steam_users(steam_dir)
    if not steam_users:
        logger.error('Failed to find any Steam users')
        return
    else:
        steam_user = next(
            filter(lambda x: x.most_recent, steam_users),
            sorted(steam_users, key=lambda x: x.last_login, reverse=True)[0],
        )
        logger.info(
            'Found most recently logged-in user %s(%s) (%s)',
            steam_user.account_name,
            steam_user.persona_name,
            steam_user.last_login,
        )
    __steam_user = steam_user

    __steam_shortcuts = _load_shortcuts(steam_dir, steam_user)


def save_steam_shortcuts():
    if not (__steam_dir and __steam_user):
        return
    logger.info(
        '%s Steam shortcuts for user %s(%s)',
        'Saving' if __steam_shortcuts else 'Removing',
        __steam_user.account_name,
        __steam_user.persona_name,
    )
    _save_shortcuts(__steam_dir, __steam_user, __steam_shortcuts)


def steam_shortcut_exists(app_name: str) -> bool:
    return SteamShortcut.calculate_appid(app_name) in {s.appid for s in __steam_shortcuts.values()}


def remove_steam_shortcut(app_name: str) -> SteamShortcut | None:
    global __steam_shortcuts

    if not steam_shortcut_exists(app_name):
        logger.error("Game %s doesn't have an associated Steam shortcut", app_name)
        return None

    appid = SteamShortcut.calculate_appid(app_name)
    removed = next(filter(lambda item: item[1].appid == appid, __steam_shortcuts.items()))
    shortcuts = dict(filter(lambda item: item[1].appid != appid, __steam_shortcuts.items()))
    __steam_shortcuts = shortcuts
    return removed[1]


def add_steam_shortcut(app_name: str, app_title: str) -> SteamShortcut:
    global __steam_shortcuts

    if steam_shortcut_exists(app_name):
        logger.info('Removing old Steam shortcut for %s', app_name)
        remove_steam_shortcut(app_name)

    command = get_rare_executable(external=True)
    arguments = ['launch', app_name]
    if len(command) > 1:
        arguments = command[1:] + arguments
    shortcut = SteamShortcut.create(
        app_name=app_name,
        app_title=f'{app_title} (Rare)',
        executable=command[0],
        start_dir=os.path.dirname(command[0]),
        icon=desktop_icon_path(app_name).as_posix(),
        launch_options=arguments,
    )

    key = int(max(__steam_shortcuts.keys(), default='0'))
    __steam_shortcuts[str(key + 1)] = shortcut
    return shortcut


def add_steam_coverart(app_name: str, shortcut: SteamShortcut):
    if not __steam_dir:
        return
    steam_grid_dir = os.path.join(__steam_dir, 'userdata', str(__steam_user.short_id), 'config', 'grid')
    if not os.path.exists(steam_grid_dir):
        os.mkdir(steam_grid_dir)
    shutil.copy(image_wide_path(app_name), os.path.join(steam_grid_dir, shortcut.game_hero))
    shutil.copy(image_icon_path(app_name), os.path.join(steam_grid_dir, shortcut.game_logo))
    shutil.copy(image_wide_path(app_name), os.path.join(steam_grid_dir, shortcut.grid_wide))
    shutil.copy(image_tall_path(app_name), os.path.join(steam_grid_dir, shortcut.grid_tall))


def remove_steam_coverart(shortcut: SteamShortcut):
    if not __steam_dir:
        return
    steam_grid_dir = os.path.join(__steam_dir, 'userdata', str(__steam_user.short_id), 'config', 'grid')
    if not os.path.exists(steam_grid_dir):
        logger.warning('Path does not exist %s', steam_grid_dir)
        return
    Path(steam_grid_dir).joinpath(shortcut.game_hero).unlink(missing_ok=True)
    Path(steam_grid_dir).joinpath(shortcut.game_logo).unlink(missing_ok=True)
    Path(steam_grid_dir).joinpath(shortcut.grid_wide).unlink(missing_ok=True)
    Path(steam_grid_dir).joinpath(shortcut.grid_tall).unlink(missing_ok=True)


if __name__ == '__main__':
    load_steam_shortcuts()

    print(__steam_dir)
    print(__steam_user)
    print(__steam_shortcuts)

    def print_shortcuts():
        for k, s in __steam_shortcuts.items():
            print({k: asdict(s)})
            print(vars(s))
        print()

    print_shortcuts()

    add_steam_shortcut('test1', 'Test1')
    add_steam_shortcut('test2', 'Test2')
    add_steam_shortcut('test3', 'Test3')
    add_steam_shortcut('test1', 'Test1')

    remove_steam_shortcut('test2')

    print_shortcuts()
