# -*- encoding: utf-8 -*-

# Heavily influenced by https://github.com/erri120/GameFinder

import os
import threading
import time
from collections.abc import Sequence
from pathlib import Path
from urllib import parse

import psutil


class OriginWatcher:
    """
    This is a class to control killing Origin when needed. This is used in
    order to hook and unhook Origin to get around the Origin DRM. Support
    for launching Origin is not included as it's intended for the game's
    DRM to launch Origin as needed.
    """

    def __init__(self, executables: Sequence[str] = []):
        self.executables = list(map(lambda s: s.lower(), executables))

    def spawn_origin_watcher(self) -> bool:
        self.kill_origin()
        self.worker_alive = True
        self.worker = threading.Thread(target=self._workerFunc)
        self.worker.start()
        return True

    def stop_origin_watcher(self) -> None:
        self.worker_alive = False
        self.worker.join(10.0)

    def kill_origin(self) -> None:
        """
        Kills the Origin application
        """
        for proc in psutil.process_iter():
            if proc.name().lower() == "origin.exe":
                proc.kill()

    def _workerFunc(self) -> None:
        gameAliveCount = 300  # Large number to allow Origin and the game to launch
        while self.worker_alive:
            gameAlive = False
            # See if the game is still alive
            for proc in psutil.process_iter():
                if proc.name().lower() in self.executables:
                    gameAlive = True
                    break
            if gameAlive:
                # Game is alive, sleep and keep monitoring at faster pace
                gameAliveCount = 5
            else:
                gameAliveCount -= 1
                if gameAliveCount <= 0:
                    self.kill_origin()
                    self.worker_alive = False
            time.sleep(1)


def find_games() -> dict[str, Path]:
    """
    Find the list of Origin games installed.

    Returns:
        A mapping from Origin manifest IDs to install locations for available
        Origin games.
    """
    games: dict[str, Path] = {}

    program_data_path = os.path.expandvars("%PROGRAMDATA%")
    local_content_path = Path(program_data_path).joinpath("Origin", "LocalContent")
    for manifest in local_content_path.glob("**/*.mfst"):
        # Skip any manifest file with '@steam'
        if "@steam" in manifest.name.lower():
            continue

        # Read the file and look for &id= and &dipinstallpath=
        with open(manifest, "r") as f:
            manifest_query = f.read()
        url = parse.urlparse(manifest_query)
        query = parse.parse_qs(url.query)
        if "id" not in query:
            # If id is not present, we have no clue what to do.
            continue
        if "dipinstallpath" not in query:
            # We could query the Origin server for the install location but... no?
            continue

        for id_ in query["id"]:
            for path_ in query["dipinstallpath"]:
                games[id_] = Path(path_)

    return games


if __name__ == "__main__":
    games = find_games()
    for k, v in games.items():
        print("Found game with id {} at {}.".format(k, v))
