import math
import random
import re
import time
from typing import Tuple, List

import tidevice
import wda
from wda import Client
from Utils.AiUtils import AiUtils
from Utils.LogManager import LogManager


# 页面控制工具类
class ControlUtils(object):

    # 获取设备上的app列表
    @classmethod
    def getDeviceAppList(self, udid):
        device = tidevice.Device(udid)
        # 获取已安装的应用列表
        apps = []
        for app in device.installation.iter_installed():
            apps.append({
                "name": app.get("CFBundleDisplayName", "Unknown"),
                "bundleId": app.get("CFBundleIdentifier", "Unknown"),
                "version": app.get("CFBundleShortVersionString", "Unknown"),
                "path": app.get("Path", "Unknown")
            })

        # 筛选非系统级应用（过滤掉以 com.apple 开头的系统应用）
        noSystemApps = [app for app in apps if not app["bundleId"].startswith("com.apple")]
        return noSystemApps

    # 打开Tik Tok
    @classmethod
    def openTikTok(cls, session: Client, udid):
        apps = cls.getDeviceAppList(udid)
        tk = ""
        for app in apps:
            if app.get("name", "") == "TikTok":
                tk = app.get("bundleId", "")

        currentApp = session.app_current()
        if currentApp != tk:
            session.app_start(tk)

    # 关闭Tik Tok
    @classmethod
    def closeTikTok(cls, session: Client, udid):
        apps = cls.getDeviceAppList(udid)
        tk = ""
        for app in apps:
            if app.get("name", "") == "TikTok":
                tk = app.get("bundleId", "")
        session.app_stop(tk)

    # 返回
    @classmethod
    def clickBack(cls, session: Client):
        try:
            back = session.xpath(
                "//*[@label='返回']"
                " | "
                "//*[@label='返回上一屏幕']"
                " | "
                "//XCUIElementTypeButton[@visible='true' and @name='TTKProfileNavBarBaseItemComponent' and @label='IconChevronLeftOffsetLTR']"
            )

            if back.exists:
                back.click()
                return True
            elif session.xpath("//*[@name='nav_bar_start_back']").exists:
                back = session.xpath("//*[@name='nav_bar_start_back']")
                if back.exists:
                    back.click()
                return True
            elif session.xpath(
                    "//Window[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]").exists:
                back = session.xpath(
                    "//Window[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]")

                if back.exists:
                    back.click()
                    return True
            else:
                return False
        except Exception as e:
            print(e)
            return False

    # 点赞
    @classmethod
    def clickLike(cls, session: Client, udid):
        scale = session.scale
        x, y = AiUtils.findImageInScreen("add", udid)
        print(x, y)
        if x > -1:
            LogManager.info("点赞了", udid)
            session.click(x // scale, y // scale + 50)
            return True
        else:
            LogManager.info("没有找到目标", udid)
            return False

    # 点击搜索
    @classmethod
    def clickSearch(cls, session: Client):
        obj = session.xpath("//*[@name='搜索']")
        try:
            if obj.exists:
                obj.click()
                return True
        except Exception as e:
            print(e)
            return False

    # 点击收件箱按钮
    @classmethod
    def clickMsgBox(cls, session: Client):
        box = session.xpath("//XCUIElementTypeButton[name='a11y_vo_inbox']")
        if box.exists:
            box.click()
            return True
        else:
            return False

    # 获取主播详情页的第一个视频
    @classmethod
    def clickFirstVideoFromDetailPage(cls, session: Client):
        # videoCell = session.xpath(
        #     '//Window/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[1]/Other[2]/Other[1]/ScrollView[1]/Other[1]/CollectionView[1]/Cell[2]')

        videoCell = session.xpath(
            '(//XCUIElementTypeCollectionView//XCUIElementTypeCell[.//XCUIElementTypeImage[@name="profile_video"]])[1]')


        tab = session.xpath(
            '//XCUIElementTypeButton[@name="TTKProfileTabVideoButton_0" or contains(@label,"作品") or contains(@name,"作品")]'
        ).get(timeout=5)        # 某些版本 tab.value 可能就是数量；或者 tab.label 类似 “作品 7”
        m = re.search(r"\d+", tab.label)

        num = 0

        if m:
            # 判断当前的作品的数量
            num = int(m.group())
            print("作品数量为：", num)

        if videoCell.exists:
            videoCell.click()
            # 点击视频
            print("找到主页的第一个视频")
            return True, num
        else:
            print("没有找到主页的第一个视频")
            return False, num



    @classmethod
    def clickFollow(cls, session, aid):
        # 1) 含“关注/已关注/Follow/Following”的首个 cell
        cell_xpath = (
            '(//XCUIElementTypeCollectionView[@name="TTKSearchCollectionComponent"]'
            '//XCUIElementTypeCell[.//XCUIElementTypeButton[@name="关注" or @name="Follow" or @name="已关注" or @name="Following"]])[1]'
        )
        cell = session.xpath(cell_xpath).get(timeout=5)

        # 2) 先试“用户信息 Button”（label/name 里包含 aid）
        profile_btn_xpath = (
            f'{cell_xpath}//XCUIElementTypeButton[contains(@label, "{aid}") or contains(@name, "{aid}")]'
        )

        try:
            profile_btn = session.xpath(profile_btn_xpath).get(timeout=3)
            profile_btn.click()
        except wda.WDAElementNotFoundError:
            # 3) 兜底：用“关注”按钮做锚点，向左偏移点击头像/用户名区域
            follow_btn_xpath = (
                f'{cell_xpath}//XCUIElementTypeButton[@name="关注" or @name="Follow" or @name="已关注" or @name="Following"]'
            )
            follow_btn = session.xpath(follow_btn_xpath).get(timeout=5)
            rect = follow_btn.bounds
            left_x = max(1, rect.x - 20)
            center_y = rect.y + rect.height // 2
            session.tap(left_x, center_y)
    @classmethod
    def userClickProfile(cls, session, aid):
        try:
            user_btn = session.xpath("(//XCUIElementTypeButton[@name='用户' and @visible='true'])[1]")
            if user_btn:
                user_btn.click()
                time.sleep(3)
                follow_btn = session.xpath(
                    "(//XCUIElementTypeTable//XCUIElementTypeButton[@name='关注' or @name='已关注'])[1]"
                ).get(timeout=5)
                if follow_btn:
                    x, y, w, h = follow_btn.bounds
                    # 垂直方向中心 + 随机 3~8 像素偏移
                    cy = int(y + h / 2 + random.randint(-8, 8))
                    # 横向往左偏移 80~120 像素之间的随机值
                    cx = int(x - random.randint(80, 120))
                    # 点击
                    session.tap(cx, cy)
                    return True

            return False
        except Exception as e:
            print(e)
            return False

    @classmethod
    def random_micro_swipe(
            cls,
            center_x: int,
            center_y: int,
            session,
            points: int = 6,
            duration_ms: int = 15,
    ) -> None:
        """
        在 (center_x, center_y) 附近做 20px 左右的不规则微滑动。
        使用 facebook-wda 的 session.swipe(x1, y1, x2, y2, duration) 接口。
        """
        # 1. 随机方向
        angle = random.uniform(0, 2 * math.pi)
        length = random.uniform(18, 22)  # 20px 左右
        end_x = center_x + length * math.cos(angle)
        end_y = center_y + length * math.sin(angle)

        # 2. 限制在 20px 圆内（防止超出）
        def clamp_to_circle(x, y, cx, cy, r):
            dx = x - cx
            dy = y - cy
            if dx * dx + dy * dy > r * r:
                scale = r / math.hypot(dx, dy)
                x = cx + dx * scale
                y = cy + dy * scale
            return int(round(x)), int(round(y))

        end_x, end_y = clamp_to_circle(end_x, end_y, center_x, center_y, 20)

        # 3. 加入轻微噪声，制造“不规则”曲线
        noise = 3  # 最大偏移像素
        mid_count = points - 2
        mid_points: List[Tuple[int, int]] = []
        for i in range(1, mid_count + 1):
            t = i / (mid_count + 1)
            # 线性插值 + 垂直方向噪声
            x = center_x * (1 - t) + end_x * t
            y = center_y * (1 - t) + end_y * t
            perp_angle = angle + math.pi / 2  # 垂直方向
            offset = random.uniform(-noise, noise)
            x += offset * math.cos(perp_angle)
            y += offset * math.sin(perp_angle)
            x, y = clamp_to_circle(x, y, center_x, center_y, 20)
            mid_points.append((int(round(x)), int(round(y))))

        # 4. 构造完整轨迹
        trajectory: List[Tuple[int, int]] = (
                [(center_x, center_y)] + mid_points + [(end_x, end_y)]
        )

        # 5. 使用 facebook-wda 的 swipe 接口（逐段 swipe）
        #    由于总时长太短，我们一次性 swipe 到终点，但用多点轨迹模拟
        #    facebook-wda 支持 swipe(x1, y1, x2, y2, duration)
        #    我们直接用起点 -> 终点，duration 用总时长
        print("开始微滑动")
        session.swipe(center_x, center_y, end_x, end_y, duration_ms / 1000)
        print("随机微滑动：", trajectory)




