import os
import time

import psutil

from module.config.config import NikkeConfig
from module.config.language import set_language
from module.config.server import set_server
from module.device.win.game_control import WinClient, Window
from module.device.win.login import Login
from module.exception import AccountError, RequestHumanTakeover
from module.logger import logger

GAME_TITLE = {
    'intl': 'NIKKE',
    'hmt': '勝利女神：妮姬',
}
GAME_PROCESS = {
    'intl': 'nikke.exe',
    'hmt': 'nikke.exe',
}
LAUNCHER_TITLE = {
    'intl': 'NIKKE',
    'hmt': 'NIKKE',
}
LAUNCHER_PROCESS = {
    'intl': 'nikke_launcher.exe',
    'hmt': 'nikke_launcher_hmt.exe',
}


class AppControl(WinClient, Login):
    config: NikkeConfig

    def __init__(self, config):
        """
        Args:
            config (NikkeConfig, str): Name of the user config under ./config
        """
        logger.hr('Device', level=1)
        if isinstance(config, str):
            self.config = NikkeConfig(config, task=None)
        else:
            self.config = config
        super().__init__(config)

        # 启动器信息
        if not self.config.PCClientInfo_LauncherPath:
            logger.error('必须填写启动器路径')
            raise RequestHumanTakeover
        launcher_path = os.path.normpath(self.config.PCClientInfo_LauncherPath)
        launcher_process = (
            self.config.PCClientInfo_LauncherProcessName or LAUNCHER_PROCESS[self.config.PCClientInfo_Client]
        )
        launcher_window_title = (
            self.config.PCClientInfo_LauncherTitleName or LAUNCHER_TITLE[self.config.PCClientInfo_Client]
        )
        launcher_window_class = 'TWINCONTROL'

        # 游戏信息
        # game_path = os.path.normpath(self.config.PCClientInfo_GamePath)
        game_process = self.config.PCClientInfo_GameProcessName or GAME_PROCESS[self.config.PCClientInfo_Client]
        game_window_title = self.config.PCClientInfo_GameTitleName or GAME_TITLE[self.config.PCClientInfo_Client]
        game_window_class = 'UnityWndClass'

        # 创建 Window 对象
        self.launcher = Window(
            name='Launcher',
            title=launcher_window_title,
            class_name=launcher_window_class,
            process=launcher_process,
            path=launcher_path,
        )
        launcher_dir = os.path.dirname(launcher_path)
        self.game = Window(
            name='Game',
            title=game_window_title,
            class_name=game_window_class,
            process=game_process,
            path=self.config.PCClientInfo_GamePath
            or os.path.normpath(os.path.join(launcher_dir, '..', 'NIKKE', 'game', game_process)),
        )

        # 回填配置
        self.config.PCClientInfo_LauncherProcessName = launcher_process
        self.config.PCClientInfo_LauncherTitleName = launcher_window_title
        self.config.PCClientInfo_GameProcessName = game_process
        self.config.PCClientInfo_GameTitleName = game_window_title
        self.config.PCClientInfo_GamePath = self.game.path

        self.interval_timer = {}

        # self.script_path = (
        #     os.path.normpath(script_path)
        #     if script_path and isinstance(script_path, (str, bytes, os.PathLike))
        #     else None
        # )

        # 设置屏幕方向
        if self.config.PCClient_ScreenRotate:
            self.screen_rotate(1)
            time.sleep(3)

        # 启动流程
        self.app_start()
        logger.attr('Process', self.current_window.process)

        # Package
        self.package = self.config.PCClientInfo_Client
        set_server(self.package)
        logger.attr('Client', self.package)
        self.language = self.config.PCClientInfo_Language
        set_language(self.language)
        logger.attr('Language', self.language)

    def app_is_running(self) -> bool:
        return self.switch_to_program()

    def get_process_path(name):
        # 通过进程名获取运行路径
        for proc in psutil.process_iter(attrs=['pid', 'name']):
            if name in proc.info['name']:
                process = psutil.Process(proc.info['pid'])
                return process.exe()
        return None

    def app_start(self):
        logger.info('Game starting')
        MAX_RETRY = 3

        def wait_until(condition, timeout, period=1):
            """等待直到条件满足或超时"""
            end_time = time.time() + timeout
            while time.time() < end_time:
                if condition():
                    return True
                time.sleep(period)
            return False

        # 检查屏幕分辨率
        self.check_screen_resolution(720, 1280)
        self.launcher_running = False
        self.current_window = self.game
        # 关闭自动HDR
        if self.config.PCClient_CloseAutoHdr:
            self.change_auto_hdr('disable')
        else:
            self.change_auto_hdr('unset')
        for retry in range(MAX_RETRY):
            try:
                # 检查是否已进入游戏
                if self.switch_to_program():
                    logger.info('游戏已在运行，检查分辨率')
                    self.ensure_resolution(720, 1280, self.config.PCClient_GameWindowPosition)
                    self.check_resolution(720, 1280)
                    break

                # 启动启动器
                self.current_window = self.launcher
                if not self.switch_to_program() and not self.start_program():
                    logger.error('启动器启动失败')
                    raise RequestHumanTakeover
                # 切换到启动器前台
                if not wait_until(lambda: self.switch_to_program(), 30):
                    logger.error('切换到启动器超时')
                    raise RequestHumanTakeover
                # 设置启动器分辨率
                # self.ensure_resolution(PROGRAM_LAUNCHER, 900, 600)
                # self.check_resolution(PROGRAM_LAUNCHER, 900, 600)
                # time.sleep(5)

                # 登录
                self.login()
                # 切换到游戏前台
                if not wait_until(lambda: self.switch_to_program(), 60):
                    logger.error('切换到游戏超时')
                    raise RequestHumanTakeover
                # 设置游戏分辨率
                self.ensure_resolution(720, 1280, self.config.PCClient_GameWindowPosition)
                self.check_resolution(720, 1280)

                break
            except AccountError:
                # 直接退出
                raise AccountError
            except Exception as e:
                logger.error(f'启动错误：{e}，尝试重试 {retry + 1}/{MAX_RETRY}')
                self.current_window = self.game
                self.stop_program()
                # 启动器打开失败
                if not self.launcher_running:
                    self.current_window = self.launcher
                    self.stop_program()
                time.sleep(5)
                if retry == MAX_RETRY - 1:
                    raise

        logger.info('Game started')

        # if not wait_until(lambda: screen.get_current_screen(), 360):
        #     raise TimeoutError("获取当前界面超时")

    def app_stop(self, program='Game'):
        try:
            # 关闭游戏或者启动器
            if program == 'Launcher':
                self.current_window = self.launcher
            else:
                self.current_window = self.game

            logger.info(f'{program} stop: {self.current_window.path}')
            if self.stop_program():
                logger.info(f'{program} stop success')
            else:
                logger.warning(f'{program} path config error')
                raise RequestHumanTakeover
        except Exception as e:
            logger.exception(e)
            raise RequestHumanTakeover
