"""
    Drissionpage-mcp中纯Cv领域的相关功能，为Vl模型赋能
"""
from typing import Any, Tuple

from fastmcp import FastMCP
from typing import Annotated, Dict, List
from tools.tools import dp_mcp_message_pack, compress_html
from DrissionPage.errors import NoRectError
import os

ele_outer_html_max_len = 500


def register_get_ele_info_by_bboxes(mcp: FastMCP, browser_manager):
    @mcp.tool(name="get_ele_info_by_bboxes",
              description="根据传入的bboxes字典返回，对应的元素信息列表")
    async def get_ele_info_by_bboxes(
            browser_port: Annotated[int, "浏览器端口"],
            tab_id: Annotated[str, "tab页id"],
            element_bboxes_list: Annotated[Dict[
                str, list], "元素bboxes字典，字典格式为：{'element_name':[x1, y1, x2, y2]}，左上 (x1,y1) → 右下 (x2,y2)，其中每个x和y都是(0,1)之间的float值"]
    ) -> dict[str, Any]:
        _browser = browser_manager.get_browser(browser_port)
        target_tab = _browser.get_tab(tab_id)
        viewport_size_with_scrollbar = target_tab.rect.viewport_size_with_scrollbar
        result_dict = dict()
        for element_name, bboxes in element_bboxes_list.items():
            x_center = (bboxes[0] + bboxes[2]) / 2 * viewport_size_with_scrollbar[0]
            y_center = (bboxes[1] + bboxes[3]) / 2 * viewport_size_with_scrollbar[1]
            target_ele = target_tab.run_js(f'return document.elementFromPoint({x_center}, {y_center})')
            temp_dict = {
                "bboxes圈定的中心": (x_center, y_center),
                "当前窗口大小": viewport_size_with_scrollbar,
                "bboxes": bboxes,
            }
            if target_ele is not None:
                target_ele = target_tab.ele(target_ele)
                try:
                    has_rect = target_ele.states.has_rect
                    is_covered = target_ele.states.is_covered
                    rect_x_center = (has_rect[0][0] + has_rect[1][0]) / 2
                    rect_y_center = (has_rect[1][1] + has_rect[2][1]) / 2
                    rect_center = (rect_x_center, rect_y_center)
                    rect_size = target_ele.rect.size
                except NoRectError:
                    has_rect = False
                    is_covered = "元素没有大小和位置信息"
                    rect_center = "元素没有大小和位置信息"
                    rect_size = "元素没有大小和位置信息"
                temp_dict["是否定位到元素"] = True
                compressed_html, rate = compress_html(target_ele.html)
                if len(compressed_html) > ele_outer_html_max_len:
                    file_name = f"{tab_id}_{x_center}_{y_center}_segment.html"
                    abs_path = os.path.join(browser_manager.get_cache_path(), file_name)
                    with open(abs_path, "w", encoding="utf-8") as f:
                        f.write(compressed_html)
                    compressed_html = f"元素的outerHTML过大，已将元素的outerHTML保存至：{abs_path}"
                temp_dict["元素信息"] = {
                    "元素tag": target_ele.tag,
                    "元素在页面中 css selector 的绝对路径": target_ele.css_path,
                    "元素是否拥有大小和位置信息": has_rect,
                    "元素rect确定的中心": rect_center,
                    "元素rect的大小": rect_size,
                    "元素是否可被模拟点击": target_ele.states.is_clickable,
                    "元素是否可见": target_ele.states.is_displayed,
                    "元素是否可用": target_ele.states.is_enabled,
                    "元素是否被其它元素覆盖": is_covered,
                    "元素的outerHTML": compressed_html,
                }
            else:
                temp_dict["是否定位到元素"] = False
                temp_dict["元素信息"] = {}
            result_dict[element_name] = temp_dict
        message = f"对于【browser_port={browser_port}】【tab_id={tab_id}】成功选中{len(result_dict)}个元素。"
        return dp_mcp_message_pack(
            message=message,
            browser_port=browser_port,
            tab_id=tab_id,
            element_info=result_dict,
        )


def register_click_action_by_xy(mcp: FastMCP, browser_manager):
    @mcp.tool(name="click_action_by_xy",
              description="根据传入的坐标，进行点击，返回是否点击成功。")
    async def get_ele_info_by_bboxes(
            browser_port: Annotated[int, "浏览器端口"],
            tab_id: Annotated[str, "tab页id"],
            coordinates: Annotated[Tuple, "要点击的坐标，这个坐标不可以是bboxes"],
            relocate_element: Annotated[
                bool, "是否要在这个工具内使用coordinates参数重新定位元素，这可能导致点击的元素与预期的不一致"] = False,
    ) -> dict[str, Any]:
        _browser = browser_manager.get_browser(browser_port)
        target_tab = _browser.get_tab(tab_id)
        if relocate_element:
            target_ele = target_tab.run_js(f'return document.elementFromPoint({coordinates[0]}, {coordinates[1]})')
            if target_ele is None:
                message = f"使用【coordinates={coordinates}】未能重新定位到元素"
                return dp_mcp_message_pack(
                    message=message,
                    browser_port=browser_port,
                    tab_id=tab_id,
                )
            target_element = target_tab.ele(target_ele)
            element_clickable = target_element.states.is_clickable
            has_rect = False
            is_covered = True
            rect_center = None
            try:
                has_rect = target_element.states.has_rect
                is_covered = target_element.states.is_covered
                if has_rect:
                    rect_x_center = (has_rect[0][0] + has_rect[1][0]) / 2
                    rect_y_center = (has_rect[1][1] + has_rect[2][1]) / 2
                    rect_center = (rect_x_center, rect_y_center)
                click_success = not is_covered
                if not is_covered:
                    click_success = target_element.click()
                    click_success = click_success is not False
            except NoRectError:
                has_rect = False
                click_success = False
            except Exception as e:
                click_success = False
            rect_center_message = ""
            if rect_center:
                rect_center_message = f"，实际rect_center={rect_center}"
            if element_clickable:
                message = f"tab页:【{tab_id}】点击【coordinates={coordinates}{rect_center_message}】的元素 {'成功' if click_success else '失败'} 了"
            else:
                message = f"tab页:【{tab_id}】中【coordinates={coordinates}{rect_center_message}】的元素不可被点击"
            if has_rect:
                message += "，元素没有大小和位置信息"
            if has_rect and is_covered:
                message += "，元素被遮挡了"
            return dp_mcp_message_pack(
                message=message,
                browser_port=browser_port,
                tab_id=tab_id,
                css_selector=target_element.css_path,
                element_clickable=element_clickable,
                click_success=click_success,
                extra_message="点击成功，页面可能有更新，请重新获取页面html，并重新分析页面Selector" if element_clickable and click_success else ""
            )
        try:
            target_tab.actions.move_to(coordinates)
            click_success = target_tab.actions.click()
            click_success = click_success is not False
        except Exception as e:
            click_success = False
        message=f"tab页:【{tab_id}】中【coordinates={coordinates}】位置点击 {'成功' if click_success else '失败'} 了"
        return dp_mcp_message_pack(
            message=message,
            browser_port=browser_port,
            tab_id=tab_id,
            click_success=click_success,

        )
