"""GTA 在线/故事 模式切换模块"""

import argparse
import sys
import time

from tclogger import TCLogger, logstr
from acto import SoftRetrier
from typing import Union

from ..menus.navigates import MenuNavigator
from ..menus.locates import ExitLocatorRunner, is_score_too_low
from ..visions.screens import ScreenCapturer


logger = TCLogger(name="NetmodeSwitcher", use_prefix=True, use_prefix_ms=True)


class NetmodeSwitcher:
    """GTA 界面/在线/故事模式切换器"""

    def __init__(self):
        """初始化模式切换器"""
        self.navigator = MenuNavigator()
        self.capturer = ScreenCapturer()
        # 使用 navigator 中的 interactor，避免创建新的手柄（会不生效）
        self.interactor = self.navigator.interactor
        # 使用 navigator 中的 locator
        self.locator = self.navigator.locator_runner.locator
        self.exit_runner = ExitLocatorRunner()

    def get_netmode(self) -> Union[str, bool]:
        """获取当前模式

        :return: 当前模式名称，"界面模式"/"在线模式"/"故事模式"，如果无法识别则返回 None
        """
        # 确保菜单打开
        self.navigator.ensure_menu_opened()
        # 截取屏幕
        frame_np = self.capturer.capture_frame(verbose=False).to_np()
        # 匹配模式
        result = self.locator.match_mode(frame_np)
        # 判断匹配结果
        if not is_score_too_low(result):
            mode_name = result.name
            logger.mesg(f"当前模式: [{mode_name}]")
            # # 对于界面模式，关闭菜单，以进行后续切换
            # if mode_name == "界面模式":
            #     self.navigator.ensure_menu_closed()
            #     logger.mesg("已关闭设置菜单，回到开始页")
            return mode_name
        else:
            logger.warn("无法识别当前模式")
            return False

    def get_netmode_with_retry(self):
        retrier = SoftRetrier(max_retries=10, retry_interval=5)
        mode = retrier.run(self.get_netmode)
        return mode

    def exit_and_confirm(self, max_retries: int = 10) -> bool:
        """定位退出提示并确认

        :param max_retries: 最大重试次数
        :return: 是否成功完成定位-确认流程
        """
        logger.note("定位退出提示并确认...")

        retry = 0
        while retry < max_retries:
            retry += 1
            # 等待退出提示出现
            self.interactor.wait_until_ready(500)
            # 截取屏幕
            frame_np = self.capturer.capture_frame(verbose=False).to_np()
            # 定位退出提示
            exit_result = self.exit_runner.locate(frame_np, verbose=True)
            # 判断是否匹配到退出提示
            if not is_score_too_low(exit_result):
                logger.mesg(f"已看到退出提示: {exit_result.name}")
                # 确认退出
                self.interactor.confirm()
                logger.okay("已确认退出提示")
                return True
            else:
                retry_str = f"[{retry} / {max_retries}]"
                logger.warn(f"{retry_str} 未能看到退出提示，重试中...")
                # 再按一次 confirm，可能需要多次确认才能触发退出提示
                self.interactor.confirm()
        logger.fail("未能看到退出提示")
        return False

    def _switch_mode(
        self, dst_names: list[str], mode_desc: str, max_retries: int = 5
    ) -> bool:
        """通用模式切换方法

        :param dst_names: 目标菜单路径
        :param mode_desc: 模式切换描述（用于日志）
        :param max_retries: 最大重试次数
        :return: 是否成功切换模式
        """
        logger.note("=" * 50)
        logger.note(mode_desc)
        logger.note("=" * 50)

        retry = 0
        while retry < max_retries:
            retry += 1
            if retry > 1:
                retry_str = f"[{retry}/{max_retries}] "
            else:
                retry_str = ""
            logger.note(f"{retry_str}尝试导航到: {dst_names}")
            # 导航到目标菜单项
            current_names = self.navigator.go_to(dst_names)
            # 检查是否导航到目标位置
            if current_names == dst_names:
                logger.okay(f"成功导航到: {current_names}")
                # 确认选择
                self.interactor.confirm()
                logger.mesg("已确认选择，等待退出提示...")
                # 定位退出提示并确认
                if self.exit_and_confirm():
                    # logger.okay("已完成切换")
                    return True
                # 如果定位退出提示失败，继续重试整个流程
            else:
                logger.warn(f"未导航到目标位置，当前位置: {current_names}，重试...")
                # 关闭菜单并重新打开
                self.navigator.ensure_menu_closed()
                self.navigator.ensure_menu_opened()

        logger.fail("模式切换失败")
        return False

    def _log_okay_mode(self, mode_name: str) -> None:
        """记录当前模式

        :param mode_name: 当前模式名称
        """
        logger.note(f"当前已是{logstr.okay(mode_name)}，无需切换")

    def switch_story_to_online(self, max_retries: int = 5) -> bool:
        """故事模式切换到在线模式

        :param max_retries: 最大重试次数
        :return: 是否成功切换模式
        """
        # 检查当前模式
        mode = self.get_netmode_with_retry()
        if mode == "在线模式":
            self._log_okay_mode(mode)
            return True

        dst_names = ["在线", "进入GTA在线模式", "凭邀请加入的战局"]
        return self._switch_mode(dst_names, "故事模式 -> 在线模式", max_retries)

    def switch_online_to_story(self, max_retries: int = 5) -> bool:
        """在线模式切换到故事模式

        :param max_retries: 最大重试次数
        :return: 是否成功切换模式
        """
        # 检查当前模式
        mode = self.get_netmode_with_retry()
        if mode == "故事模式":
            self._log_okay_mode(mode)
            return True

        dst_names = ["在线", "退至故事模式"]
        return self._switch_mode(dst_names, "在线模式 -> 故事模式", max_retries)

    def switch_to_new_invite_lobby(self, max_retries: int = 5) -> bool:
        """切换到新的邀请战局

        根据当前模式自动选择对应的菜单路径：
        - 故事模式: 在线 -> 进入GTA在线模式 -> 凭邀请加入的战局
        - 在线模式: 在线 -> 寻找新战局 -> 仅限邀请的战局

        :param max_retries: 最大重试次数
        :return: 是否成功切换到新的邀请战局
        """
        # 获取当前模式
        mode = self.get_netmode_with_retry()

        # 根据模式设置目标路径和描述
        if mode == "故事模式":
            dst_names = ["在线", "进入GTA在线模式", "凭邀请加入的战局"]
            mode_desc = "切换到新的邀请战局（从故事模式）"
        else:  # mode == "在线模式"
            dst_names = ["在线", "寻找新战局", "仅限邀请的战局"]
            mode_desc = "切换到新的邀请战局（从在线模式）"

        # 执行切换
        return self._switch_mode(dst_names, mode_desc, max_retries)

    def sync_to_remote(self):
        """同步存档到远程服务器"""
        logger.note(f"同步存档到远程服务器...")
        self.interactor.close_window()
        time.sleep(10)  # 等待右下角转完圈，出现选项
        self.interactor.cancel(3)
        logger.okay(f"已完成同步，请留意左下角提示: {logstr.mesg('[保存成功]')}")


def parse_args() -> argparse.Namespace:
    """
    解析命令行参数。

    :return: 解析后的参数
    """
    parser = argparse.ArgumentParser(
        description="GTA 在线/故事模式切换工具",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
示例:
  python -m gtaz.workers.mode_switch -g    # 获取当前模式
  python -m gtaz.workers.mode_switch -o    # 故事模式 -> 在线模式
  python -m gtaz.workers.mode_switch -s    # 在线模式 -> 故事模式
  python -m gtaz.workers.mode_switch -i    # 新的邀请战局
  python -m gtaz.workers.mode_switch -y    # 同步存档到远程服务器
        """,
    )

    parser.add_argument(
        "-g",
        "--get",
        action="store_true",
        help="获取当前模式",
    )
    parser.add_argument(
        "-o",
        "--online",
        action="store_true",
        help="故事模式 -> 在线模式",
    )
    parser.add_argument(
        "-s",
        "--story",
        action="store_true",
        help="在线模式 -> 故事模式",
    )
    parser.add_argument(
        "-i",
        "--invite",
        action="store_true",
        help="新的邀请战局",
    )
    parser.add_argument(
        "-y",
        "--sync",
        action="store_true",
        help="同步存档到远程服务器",
    )
    return parser.parse_args()


def main():
    """主函数，处理命令行参数"""
    if len(sys.argv) == 1:
        # 没有参数时显示帮助
        sys.argv.append("-h")
    args = parse_args()

    switcher = NetmodeSwitcher()

    if args.get:
        switcher.get_netmode_with_retry()

    if args.online:
        switcher.switch_story_to_online()

    if args.story:
        switcher.switch_online_to_story()

    if args.invite:
        switcher.switch_to_new_invite_lobby()

    if args.sync:
        switcher.sync_to_remote()


if __name__ == "__main__":
    main()

    # 显示帮助信息
    # python -m gtaz.workers.mode_switch

    # 获取当前模式
    # python -m gtaz.workers.mode_switch -g

    # 故事模式 -> 在线模式
    # python -m gtaz.workers.mode_switch -o

    # 在线模式 -> 故事模式
    # python -m gtaz.workers.mode_switch -s

    # 新的邀请战局
    # python -m gtaz.workers.mode_switch -i

    # 同步存档到远程服务器
    # python -m gtaz.workers.mode_switch -y
