from __future__ import annotations

import time
from datetime import datetime, timedelta
from importlib import import_module
from typing import Any, Callable

from mower.utils import config
from mower.utils import typealias as tp
from mower.utils.log import logger, save_screenshot

method_map = {
    "adb": "mower.utils.device.method.adb.ADB",
    "droidcast": "mower.utils.device.method.droidcast.DroidCast",
    "droidcast_raw": "mower.utils.device.method.droidcast.DroidCast_raw",
    "scrcpy": "mower.utils.device.method.scrcpy.Scrcpy",
    "mumuipc": "mower.utils.device.method.mumu_ipc.MuMu12IPC",
    "diy": "mower.utils.device.method.adb.DIY",
    "mumumanager": "mower.utils.device.method.mumumanager.MuMuManager",
    "adb_multiuser": "mower.utils.device.method.adb.ADBMultiUser",
}


def import_method(full_name: str):
    index = full_name.rfind(".")
    module_name = full_name[:index]
    class_name = full_name[index + 1 :]
    module = import_module(module_name)
    return getattr(module, class_name)


class Device:
    solver_name = "设备"
    services = {}

    def get_service(self, method: str):
        if method not in self.services:
            self.services[method] = import_method(method_map[method])()
        return self.services[method]

    @property
    def screenshot(self):
        return self.get_service(config.conf.screencap_strategy)

    @property
    def control(self):
        return self.get_service(config.conf.control_strategy)

    @property
    def app_control(self):
        return self.get_service(config.conf.app_control_strategy)

    def launch(self) -> None:
        """launch the application"""
        logger.info("明日方舟，启动！")
        self.app_control.launch()

    def exit(self) -> None:
        """exit the application"""
        logger.info("退出游戏")
        self.app_control.exit()

    def home(self) -> None:
        """back to home"""
        logger.info("返回模拟器主页")
        self.app_control.home()

    def send_keyevent(self, keycode: int) -> None:
        """send a key event"""
        logger.debug(keycode)
        self.control.send_keyevent(keycode)

    def screencap(self) -> bytes:
        start_time = datetime.now()
        if config.conf.screencap_strategy != "scrcpy":
            min_time = config.screenshot_time + timedelta(
                milliseconds=config.conf.screenshot_interval
            )
            delta = (min_time - start_time).total_seconds()
            if delta > 0:
                time.sleep(delta)
                start_time = min_time

        img = self.screenshot.capture_display()

        stop_time = datetime.now()
        config.screenshot_time = stop_time
        interval = (stop_time - start_time).total_seconds() * 1000
        if config.screenshot_avg is None:
            config.screenshot_avg = interval
        else:
            config.screenshot_avg = config.screenshot_avg * 0.9 + interval * 0.1
        if config.screenshot_count >= 100:
            config.screenshot_count = 0
            logger.info(
                f"截图用时{interval:.0f}ms 平均用时{config.screenshot_avg:.0f}ms"
            )
        else:
            config.screenshot_count += 1

        save_screenshot(img)
        return img

    def tap(self, point: tuple[int, int]) -> None:
        """tap"""
        logger.debug(point)
        self.control.tap(point[0], point[1])

    def back(self):
        logger.debug("back")
        self.control.back()

    def swipe(
        self, start: tuple[int, int], end: tuple[int, int], duration: int = 100
    ) -> None:
        """swipe"""
        logger.debug(f"{start=} {end=} {duration=}")
        self.control.swipe(start[0], start[1], end[0], end[1], duration / 1000)

    def swipe_ext(
        self,
        points: list[tp.Coordinate],
        durations: list[int],
        update: bool = False,
        interval: float = 0,
        func: Callable[[tp.Image], Any] = lambda _: None,
    ):
        """复杂的滑动

        Args:
            points (list[tp.Coordinate]): 坐标列表
            durations (list[int]): 每两个坐标之间拖动的时长
            update (bool, optional): 抬手前截图. Defaults to False.
            interval (float, optional): 抬手后等待回弹动画的时间. Defaults to 0.
            func (Callable[[tp.Image], Any], optional): 处理抬手前截图的函数. Defaults to lambda _: None.

        Returns:
            Any: func的返回值
        """
        logger.debug(f"{points=} {durations=} {update=} {interval=} {func=}")
        return self.control.swipe_ext(points, durations, update, interval, func)

    def check_current_focus(self) -> bool:
        """check if the application is in the foreground"""
        return self.app_control.check_current_focus()

    def check_device_screen(self) -> bool:
        """检查分辨率和DPI

        Returns:
            设置是否正确
        """
        return self.app_control.check_device_screen()
