from abc import ABC, abstractmethod
import subprocess
import os
from PyQt5.QtWidgets import QMessageBox

class BaseLauncher(ABC):
    def __init__(self, game_info, config):
        self.game_info = game_info
        self.config = config

    @abstractmethod
    def launch(self, parent_widget, **kwargs):
        pass


class JavaLauncher(BaseLauncher):
    def launch(self, parent_widget, instance=None, account=None, splitscreen=False, splitscreen_account=None):
        if not instance or not account:
            QMessageBox.warning(parent_widget, "Missing Info", "Instance or account not provided.")
            return

        exec_path = self.config.get("exec_path")
        launcher_type = self.config.get("type", "native")

        base_args = ["flatpak", "run", exec_path, "-l", instance, "-a", account] if launcher_type == "flatpak" else [exec_path, "-l", instance, "-a", account]

        if splitscreen:
            if account == splitscreen_account:
                QMessageBox.warning(parent_widget, "Error", "Cannot use the same account for splitscreen.")
                return
            instance2 = instance + " 2"
            args2 = ["flatpak", "run", exec_path, "-l", instance2, "-a", splitscreen_account] if launcher_type == "flatpak" else [exec_path, "-l", instance2, "-a", splitscreen_account]
            subprocess.Popen(base_args)
            subprocess.Popen(args2)
        else:
            subprocess.Popen(base_args)


class BedrockLauncher(BaseLauncher):
    def launch(self, parent_widget, profile=None):
        exec_path = self.config.get("exec_path")
        launcher_type = self.config.get("type", "native")
        args = ["flatpak", "run", exec_path, "-p", profile] if launcher_type == "flatpak" else [exec_path, "-p", profile]
        subprocess.Popen(args)


class FlatpakLauncher(BaseLauncher):
    def launch(self, parent_widget, **kwargs):
        exec_path = self.config.get("exec_path")
        if not exec_path:
            QMessageBox.warning(parent_widget, "Error", "Executable path not provided.")
            return

        args = ["flatpak", "run", exec_path]
        extra_args = kwargs.get("extra_args", [])
        if extra_args:
            args.extend(extra_args)

        try:
            subprocess.Popen(args)
        except Exception as e:
            QMessageBox.critical(parent_widget, "Launch Error", str(e))


class NativeLauncher(BaseLauncher):
    def launch(self, parent_widget, **kwargs):
        exec_path = self.config.get("exec_path")
        if not exec_path:
            QMessageBox.warning(parent_widget, "Error", "Executable path not provided.")
            return

        args = [exec_path]
        extra_args = kwargs.get("extra_args", [])
        if extra_args:
            args.extend(extra_args)

        try:
            subprocess.Popen(args)
        except Exception as e:
            QMessageBox.critical(parent_widget, "Launch Error", str(e))


class SteamLauncher(BaseLauncher):
    def launch(self, parent_widget, steam_id=None):
        if not steam_id:
            QMessageBox.warning(parent_widget, "Error", "Steam ID not provided.")
            return
        subprocess.Popen(["xdg-open", f"steam://run/{steam_id}"])


class LutrisLauncher(BaseLauncher):
    def launch(self, parent_widget, lutris_id=None):
        if not lutris_id:
            QMessageBox.warning(parent_widget, "Error", "Lutris game ID not provided.")
            return
        subprocess.Popen(["xdg-open", f"lutris:rungameid/{lutris_id}"])


class WebLauncher(BaseLauncher):
    def launch(self, parent_widget, url=None):
        if not url:
            QMessageBox.warning(parent_widget, "Error", "URL not provided.")
            return
        subprocess.Popen(["xdg-open", url])


class Xbox360Launcher(BaseLauncher):
    def launch(self, parent_widget, exec_path=None, rom_path=None):
        parent = os.path.dirname(os.path.realpath(exec_path))
        proton = os.path.expanduser("~/.steam/steam/steamapps/common/Proton - Experimental/proton")
        compat = os.path.expanduser("~/.mcmel")
        env = os.environ.copy()
        env.update({
            "STEAM_COMPAT_DATA_PATH": compat,
            "STEAM_COMPAT_CLIENT_INSTALL_PATH": compat,
            "PROTON_LOG": "1"
        })
        subprocess.Popen([proton, "run", exec_path, rom_path], cwd=parent, env=env)
