import json
import time
from datetime import datetime
from functools import wraps

from mower.utils import config
from mower.utils.csleep import MowerExit, csleep
from mower.utils.device.emulator import restart_emulator
from mower.utils.log import logger

from .utils import subprocess_run


def retry_mumumanager(func):
    @wraps(func)
    def retry_wrapper(self, *args, **kwargs):
        for _ in range(4):
            try:
                return func(self, *args, **kwargs)
            except MowerExit:
                raise
            except ValueError as e:
                logger.debug_exception(e)
                if _ < 3:
                    time.sleep(10)
                else:
                    restart_emulator()
            except Exception as e:
                logger.debug_exception(e)

    return retry_wrapper


class MuMuManager:
    manager_path = config.conf.emulator.emulator_folder + "\\MuMuManager.exe"
    index = config.conf.emulator.index

    def load_json(self, data: str) -> dict:
        try:
            return json.loads(data)
        except json.JSONDecodeError as e:
            logger.error(f"JSON 解析失败: {e}")
            return {}

    def get_emulator_info(self):
        cmd = [self.manager_path, "info", "-v", str(self.index)]
        output = subprocess_run(cmd)
        return self.load_json(output)

    @retry_mumumanager
    def get_field_value(self, data, field_name):
        """
        从模拟器信息中提取指定字段的值
        Args:
            field_name (str): 字段名称

        Returns:
            str, int, bool, or None: 字段: 字段值或错误消息
        """
        # 获取模拟器信息
        if not data:
            logger.error("未能获取数据")
            return

        # 提取指定字段的值
        value = data.get(field_name, None)
        if value is None:
            raise ValueError(f"字段 '{field_name}' 不存在")

        return value

    def check_android_process(self) -> bool:
        return self.get_field_value(self.get_emulator_info(), "is_android_started")

    def get_setting_info(self):
        cmd = [self.manager_path, "setting", "-v", str(self.index), "-aw"]
        output = subprocess_run(cmd)
        return self.load_json(output)

    def app_kept_alive(self) -> bool:
        return self.get_field_value(self.get_setting_info(), "app_keptlive")

    def set_app_kept_alive_false(self) -> None:
        cmd = [
            self.manager_path,
            "setting",
            "-v",
            str(self.index),
            "-k",
            "app_keptlive",
            "-val",
            "false",
        ]
        subprocess_run(cmd)

    def launch(self) -> None:
        cmd = [
            self.manager_path,
            "control",
            "-v",
            str(self.index),
            "app",
            "launch",
            "-pkg",
            config.conf.APPNAME,
        ]
        subprocess_run(cmd)

    def exit(self) -> None:
        cmd = [
            self.manager_path,
            "control",
            "-v",
            str(self.index),
            "app",
            "close",
            "-pkg",
            config.conf.APPNAME,
        ]
        subprocess_run(cmd)

    def home(self) -> None:
        cmd = [
            self.manager_path,
            "control",
            "-v",
            str(self.index),
            "tool",
            "func",
            "-n",
            "go_home",
        ]
        subprocess_run(cmd)

    def current_focus(self) -> str:
        cmd = [self.manager_path, "control", "-v", str(self.index), "app", "info", "-i"]
        output = subprocess_run(cmd)
        data = self.load_json(output)
        return self.get_field_value(data, "active")

    def check_current_focus(self) -> bool:
        """check if the application is in the foreground"""
        update = False
        start_time = datetime.now()
        while True:
            try:
                focus = self.current_focus()
                if focus != config.conf.APPNAME:
                    if (datetime.now() - start_time).total_seconds() > 40:
                        self.exit()  # 应用卡死
                        start_time = datetime.now()
                    self.launch()
                    update = True
                    csleep(1)
                    continue
                return update
            except MowerExit:
                raise
            except Exception as e:
                logger.exception(e)
                update = True

    def check_device_screen(self) -> bool:
        data = self.get_setting_info()
        width = int(float(self.get_field_value(data, "resolution_width.custom")))
        height = int(float(self.get_field_value(data, "resolution_height.custom")))
        dpi = int(float(self.get_field_value(data, "resolution_dpi.custom")))
        if (
            config.conf.screencap_strategy.startswith("droidcast")
            and self.app_kept_alive()
        ):
            logger.error("MuMu12的droidcast截图策略下，需要关闭应用后台保活")
            try:
                self.set_app_kept_alive_false()
                logger.info("关闭应用后台保活成功")
                restart_emulator()
            except Exception as e:
                logger.debug_exception(e)
                raise MowerExit

        if width == 1920 and height == 1080 and dpi == 280:
            return True
        logger.error("mower-ng仅支持1920x1080分辨率、280DPI，请修改模拟器设置")
        return False

    def kill_server(self) -> None:
        pass
