import asyncio
import sys
from uuid import uuid4
from fastmcp import FastMCP
from playwright.async_api import async_playwright

# 如果 fastmcp 版本较新找不到 Image，用 mcp.types 的原生类是最稳的
from mcp.types import ImageContent, EmbeddedResource
import os

mcp = FastMCP("TaobaoSpecHunter")

PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__))
# 在项目根目录下创建 tmp 文件夹
TMP_DIR = os.path.join(PROJECT_ROOT, "tmp")


if not os.path.exists(TMP_DIR):
    os.makedirs(TMP_DIR)

# 全局变量保存 playwright 对象，防止函数结束时被回收
_playwright_instance = None
_browser_instance = None

async def get_existing_page():
    """
    异步连接已有的 Chrome 浏览器
    """
    global _playwright_instance, _browser_instance

    # 启动异步 Playwright
    if not _playwright_instance:
        _playwright_instance = await async_playwright().start()

    try:
        # 注意：这里必须加 await
        # 尝试连接已打开的浏览器 (CDP)
        browser = await _playwright_instance.chromium.connect_over_cdp("http://127.0.0.1:9222")
        _browser_instance = browser  # 保持引用

        context = browser.contexts[0]
        page = context.pages[0] if context.pages else await context.new_page()
        return page
    except Exception as e:
        raise Exception(f"连接浏览器失败: {e}\n请确保已在命令行运行: chrome --remote-debugging-port=9222")


async def force_lazy_load(page, max_scrolls=5):
    """异步滚动加载"""
    print("正在预加载图片...")
    for i in range(max_scrolls):
        # 异步滚动
        await page.mouse.wheel(0, 1000)
        await asyncio.sleep(0.2)  # 必须用 asyncio.sleep

    await page.mouse.wheel(0, -2000)
    await asyncio.sleep(1)


# ---------------------------------------------------------
# 工具 1: 负责“搜索关键字” + ”显示价格区间框“,搜索完成后，悬停于区间按钮，会有下拉框出现，再去填价格
# ---------------------------------------------------------
@mcp.tool()
async def search_and_filter(keyword: str, min_price: int = None, max_price: int = None) -> str:
    """
    在淘宝搜索商品。
    如果指定了 min_price 和 max_price，会通过“后台静默悬停”技术自动填写价格区间。
    整个过程不需要鼠标介入，支持后台运行。

    Args:
        keyword: 搜索关键词 (如 "RTX 4090")
        min_price: (可选) 最低价格，整数
        max_price: (可选) 最高价格，整数
    """
    try:
        page = await get_existing_page()
        print(f"[Action] 正在搜索: {keyword}...", file=sys.stderr)

        # 1. 访问搜索页
        # 加上 sort=sale-desc 按销量排序通常数据更好，可根据需要调整
        await page.goto(f"https://s.taobao.com/search?q={keyword}&sort=sale-desc")
        await page.wait_for_load_state('domcontentloaded')

        # 简单等待页面渲染
        await asyncio.sleep(3)

        # 如果没有价格需求，直接返回
        if min_price is None or max_price is None:
            return f"搜索 '{keyword}' 完成 (无价格筛选)。"

        # 2. 开始执行静默筛选 (无鼠标干扰版)
        print(f"[Action] 正在后台应用价格筛选: {min_price}-{max_price}...", file=sys.stderr)

        # 定位“区间”按钮
        # 使用 :has-text 更加稳健
        tab_selector = 'div.next-tabs-tab-inner:has-text("区间")'
        try:
            await page.wait_for_selector(tab_selector, timeout=4000)
        except:
            return "搜索成功，但未找到'区间'按钮，无法筛选价格。"

        tab_btn = page.locator(tab_selector).first

        # --- 【关键技术】直接分发事件，无需鼠标移动 ---
        # 模拟 React/Vue 组件需要的悬停事件
        await tab_btn.dispatch_event('mouseenter')
        await tab_btn.dispatch_event('mouseover')
        # --------------------------------------------

        # 给一点点时间让 JS 渲染下拉框
        await asyncio.sleep(1.0)

        # 3. 填写价格
        input_selector = 'input.textInput--QBre6Fdc'
        # 等待输入框出现
        try:
            await page.wait_for_selector(input_selector, state='visible', timeout=3000)
        except:
            return "触发了悬停，但价格输入框未弹出(可能是反爬或网络卡顿)。"

        price_inputs = page.locator(input_selector)

        if await price_inputs.count() >= 2:
            # 填入最低价
            await price_inputs.nth(0).fill(str(min_price))
            await asyncio.sleep(0.2)
            # 填入最高价
            await price_inputs.nth(1).fill(str(max_price))
            await asyncio.sleep(0.5)

            # 4. 点击确认
            # 使用 force=True，即使被遮挡也能点击
            confirm_btn = page.locator('div.confirmButton--gHXjLus4').first
            if await confirm_btn.count() > 0:
                await confirm_btn.click(force=True)

                # 等待列表刷新
                await asyncio.sleep(2)
                return f"搜索 '{keyword}' 完成，已成功筛选价格 {min_price}-{max_price}。"
            else:
                return "输入了价格，但未找到确认按钮。"
        else:
            return "价格输入框数量不对，无法填写。"

    except Exception as e:
        return f"执行出错: {str(e)}"


# ---------------------------------------------------------
# 工具 3: 负责“获取当前页面的前 N 个商品链接”
# ---------------------------------------------------------
@mcp.tool()
async def get_top_product_links(limit: int = 3) -> list[str]:
    """
    第二步：获取当前浏览器页面中显示的商品链接,获取limit个，用户未填写则默认为3。
    请在执行完 search_and_filter 后调用此工具。
    """
    try:
        page = await get_existing_page()
        print(f"[Action] 正在抓取前 {limit} 个商品...", file=sys.stderr)

        # 确保有商品显示
        try:
            await page.wait_for_selector('a[href*="item.htm"]', timeout=5000)
        except:
            return ["当前页面未发现商品链接，请检查是否需要登录或验证码"]

        locators = page.locator('a[href*="item.htm"]')
        count = await locators.count()

        valid_links = []
        seen_ids = set()
        import re

        for i in range(count):
            if len(valid_links) >= limit:
                break

            href = await locators.nth(i).get_attribute("href")
            if not href: continue

            if href.startswith("//"):
                href = "https:" + href

            # ID 去重逻辑
            id_match = re.search(r'[?&]id=(\d+)', href)
            if id_match:
                item_id = id_match.group(1)
                if item_id in seen_ids:
                    continue
                seen_ids.add(item_id)
                valid_links.append(href)
            else:
                if href not in valid_links:
                    valid_links.append(href)

        if not valid_links:
            return ["未找到链接"]

        print(f"[Success] 成功抓取 {len(valid_links)} 个链接", file=sys.stderr)
        return valid_links

    except Exception as e:
        return [f"抓取链接出错: {str(e)}"]


@mcp.tool()
async def capture_specs_area(url: str):
    """
    智能抓取配置单 (异步版) - 直接截图版,请在执行完 get_top_product_links后执行此工具
    """
    page = await get_existing_page()
    print(f"正在分析配置: {url}")

    try:
        # 导航到页面
        await page.goto(url)

        # 直接截图 (await screenshot)
        screenshot_bytes = await page.screenshot(full_page=False)

        # 保存到文件
        path = os.path.join(TMP_DIR, f"specs_{uuid4().hex}.png")
        with open(path, "wb") as f:
            f.write(screenshot_bytes)

        return {
            "type": "image",
            "path": path
        }

    except Exception as e:
        return {
            "type": "error",
            "error": f"截图失败: {str(e)}"
        }



def main() -> None:
    print("Hello from Mizutsune-taobaosearch-mcp-server!")
    mcp.run(transport="stdio")

