from mcp.server.fastmcp import FastMCP
import random
from office_assistant_mcp import playwright_util
from office_assistant_mcp import playwright_message
from office_assistant_mcp.prompt import get_planning_customer_group_prompt, get_planning_message_plan_prompt
from mcp.server.fastmcp.prompts import base
import os
import re
import importlib.metadata

from office_assistant_mcp.log_util import log_error, log_info

def format_exception_message(msg: str, e: Exception) -> str:
    """
    统一处理异常返回信息
    
    Args:
        msg: 异常提示信息
        e: 异常对象
    
    Returns:
        格式化后的异常信息
    """
    error_str = str(e)
    log_error(f"format_exception_message:{msg} exception: {error_str}")
    
    # 浏览器关闭异常
    if "Target page, context or browser has been closed" in error_str:
        log_info("准备清除本地浏览器缓存")
        playwright_util.reset_playwright_cache()
        return f"{msg}: 浏览器已经关闭，需要调用浏览器打开方法重新打开浏览器。"
    
    # # 元素未找到异常
    # if "could not be found" in error_str or "element is not visible" in error_str:
    #     return f"{msg}: 页面元素未找到或不可见，可能页面结构已变化。"
    
    # # 超时异常
    # if "Timeout" in error_str or "exceeded" in error_str:
    #     return f"{msg}: 操作超时，请检查网络连接或重试。"
    
    # 默认返回原始异常信息
    return f"{msg}: {error_str}"

mcp = FastMCP("mcp_demo_server", port=8088)


async def server_log_info(msg: str):
    """发送信息级别的日志消息"""
    await mcp.get_context().session.send_log_message(
        level="info",
        data=msg,
    )


@mcp.resource("config://app")
def get_config() -> str:
    """Static configuration data"""
    return "这是应用的全部配置"

#  定义动态 Resource


@mcp.resource("users://{user_id}/profile")
def get_user_profile(user_id: str) -> str:
    """Dynamic user data"""
    return f"用户全部信息： {user_id}"


# @mcp.tool()
# def ask_weather(city: str) -> dict[str, str]:
#     """返回指定城市的天气"""
#     return {"city": city, "weather": "晴天", "temperature": 25}


@mcp.prompt()
def review_code(code: str) -> str:
    return f"Please review this code:\n\n{code}"


@mcp.tool()
async def login_sso() -> str:
    """如果需要授权登录，则使用本工具进行飞书SSO登录"""
    try:
        await server_log_info("【T】开始飞书SSO登录")
        result = await playwright_util.login_sso()
        await server_log_info(f"【T】登录结果: {result}")
        return result
    except Exception as e:
        await server_log_info(f"【E】飞书SSO登录出错: {str(e)}")
        return format_exception_message("登录过程中出错", e)


@mcp.tool()
async def planning_create_customer_group(user_query: str) -> str:
    """创建客群的第一步，根据用户输入，检查输入信息是否完整，如果完整则规划创建客群的详细步骤    
    Args:
        user_query: 用户输入的创建客群的原样指令
    """
    try:
        await server_log_info(f"【T】开始规划创建客群: {user_query}")
        
        # 构建发送给LLM的提示词
        prompt = get_planning_customer_group_prompt(user_query)
        
        # 调用LLM获取规划结果
        result = await playwright_util.send_llm_request(prompt)
        await server_log_info(f"【T】规划创建客群结果: {result}")
        return result
    except Exception as e:
        await server_log_info(f"【E】规划创建客群时出错: {str(e)}")
        log_error(f"规划创建客群时出错: {str(e)}")
        return "检查参数和创建规划异常，跳过规划直接执行"


@mcp.tool()
async def open_create_customer_group_page() -> str:
    """打开客群页面并点击新建客群按钮"""
    try:
        await server_log_info("【T】开始打开客群页面")
        result = await playwright_util.open_create_customer_group_page()
        return f"客群页面已打开: {result}"
    except Exception as e:
        await server_log_info(f"【E】打开客群页面时出错: {str(e)}")
        return format_exception_message("打开客群页面时出错", e)

@mcp.tool()
async def fill_customer_group_info(group_name: str, business_type: str="活动运营") -> str:
    """填写客群基本信息

    Args:
        group_name: 客群名称
        business_type: 业务类型，可选值：社群运营、用户运营、活动运营、商品运营、内容运营、游戏运营
    """
    try:
        await server_log_info(f"【T】开始填写客群信息: {group_name}, {business_type}")
        result = await playwright_util.fill_customer_group_info(group_name, business_type)
        return f"客群信息填写成功: {result}"
    except Exception as e:
        await server_log_info(f"【E】填写客群信息时出错: {str(e)}")
        return format_exception_message("填写客群信息时出错", e)


@mcp.tool()
async def fill_customer_group_user_tag_set_basic_info(
    identity_types: list[str] = None,
    v2_unregistered: str = None
) -> str:
    """新增客群时填写客群用户标签中的基础信息，包括用户身份及是否推客用户。
    
    Args:
        identity_types: 新制度用户身份，可多选，例如 ["P1", "V3"]
                       可选值包括: "P1", "P2", "P3", "P4", "V1", "V2", "V3", "VIP"
                       不区分大小写，如"p1"也会被识别为"P1"
        v2_unregistered: V2以上未注册推客用户，可选值: "是", "否"
    """
    try:
        await server_log_info("【T】开始填写客群用户标签基础信息")
        result = await playwright_util.fill_customer_group_user_tag_set_basic_info(
            identity_types=identity_types,
            v2_unregistered=v2_unregistered
        )
        await server_log_info(f"【T】填写基础信息结果: {result}")
        return result
    except Exception as e:
        await server_log_info(f"【E】填写客群用户标签基础信息时出错: {str(e)}")
        return format_exception_message("填写基础信息时出错", e)


@mcp.tool()
async def fill_customer_add_user_behavior_tag(
    time_range_type: str = "最近",
    time_range_value: str = "7",
    action_type: str = "做过",
    theme: str = "购买", 
    dimension: str = None, 
    dimension_condition: str = None,
    dimension_value: str = None,
    metric: str = None,
    metric_condition: str = None,
    metric_value: str = None,
    metric_value_end: str = None
) -> str:
    """添加用户行为标签

    Args:
        time_range_type: 时间范围类型："最近"或"任意时间"
        time_range_value: 时间范围值，天数，如："7"
        action_type: 行为类型："做过"或"没做过"
        theme: 主题："购买"或"搜索"等
        dimension: 维度选项。当theme="购买"时可用：
            - 类目相关：["后台一级类目", "后台二级类目", "后台三级类目", "后台四级类目"]
              (条件均为=或!=，值为字符串，支持下拉列表多选)
            - 商品相关：["商品品牌", "商品名称", "商品id"] 
              (条件均为=或!=，品牌需从下拉列表选择，其他为字符串)
            - 其他："统计日期"
        dimension_condition: 维度条件：通常为=或!=，部分情况支持"包含"等
        dimension_value: 维度值：根据dimension类型提供相应字符串
        metric: 指标名称。当theme="购买"时可用：
            ["购买金额", "购买件数", "购买净金额", "购买订单数"]
            (所有指标条件均支持=, >=, <=, <, >，值均为数字)
        metric_condition: 指标条件：=, >=, <=, <, >, 介于
        metric_value: 指标值：数字类型，当metric_condition="介于"时为范围开始值
        metric_value_end: 指标范围结束值：仅当metric_condition="介于"时使用
    """
    try:
        await server_log_info(f"【T】开始添加{theme}用户行为标签")
        result = await playwright_util.add_user_behavior_common_tags(
            time_range_type=time_range_type,
            time_range_value=time_range_value,
            action_type=action_type,
            theme=theme,
            dimension=dimension,
            dimension_condition=dimension_condition,
            dimension_value=dimension_value,
            metric=metric,
            metric_condition=metric_condition,
            metric_value=metric_value,
            metric_value_end=metric_value_end
        )
        await server_log_info(f"【T】添加用户行为标签结果: {result}")
        return result
    except Exception as e:
        await server_log_info(f"【E】添加用户行为标签时出错: {str(e)}")
        return format_exception_message("添加用户行为标签时出错", e)


@mcp.tool()
async def planning_create_message_plan(user_query: str) -> str:
    """创建短信计划的第一步，根据用户输入，检查输入信息是否完整，如果完整则规划创建短信计划的详细步骤    
    Args:
        user_query: 用户输入的创建短信计划的原样指令
    """
    try:
        await server_log_info(f"【T】开始规划创建短信计划: {user_query}")
        
        # 构建发送给LLM的提示词
        prompt = get_planning_message_plan_prompt(user_query)
        
        # 调用LLM获取规划结果
        result = await playwright_util.send_llm_request(prompt)
        await server_log_info(f"【T】规划创建短信计划结果: {result}")
        return result
    except Exception as e:
        await server_log_info(f"【E】规划创建短信计划时出错: {str(e)}")
        log_error(f"规划创建短信计划时出错: {str(e)}")
        return "检查参数和创建规划异常，跳过规划直接执行"


@mcp.tool()
async def open_create_message_plan_page() -> str:
    """打开创建短信计划页面，以便创建短信计划"""
    try:
        await server_log_info("【T】开始打开短信计划页面")
        result = await playwright_message.open_create_message_plan_page()
        await server_log_info(f"【T】打开短信计划页面结果: {result}")
        return result
    except Exception as e:
        await server_log_info(f"【E】打开短信计划页面时出错: {str(e)}")
        return format_exception_message("打开短信计划页面时出错", e)


@mcp.tool()
async def fill_message_group_id(group_id: str) -> str:
    """创建短信计划，填写指定的客群id
    
    Args:
        group_id: 客群ID，格式为数字字符串
    """
    try:
        await server_log_info(f"【T】开始搜索并选择客群: {group_id}")
        result = await playwright_message.fill_message_group_id(group_id)
        await server_log_info(f"【T】选择客群结果: {result}")
        return result
    except Exception as e:
        await server_log_info(f"【E】搜索并选择客群时出错: {str(e)}")
        return format_exception_message("搜索并选择客群时出错", e)


@mcp.tool()
async def fill_message_plan_info(plan_name: str, send_date: str, send_time: str) -> str:
    """填写短信计划的标题、发送日期和时间
    
    Args:
        plan_name: 计划名称，格式为字符串，例如："0412高质量用户圣牧纯牛奶"
        send_date: 发送日期，格式为"YYYY-MM-DD"，例如："2025-04-12"
        send_time: 发送时间，格式为"HH:MM:SS"，例如："18:00:00"
    """
    try:
        await server_log_info(f"【T】开始填写短信计划基本信息: {plan_name}, {send_date} {send_time}")
        result = await playwright_message.fill_message_plan_info(plan_name, send_date, send_time)
        await server_log_info(f"【T】填写短信计划基本信息结果: {result}")
        return result
    except Exception as e:
        await server_log_info(f"【E】填写短信计划基本信息时出错: {str(e)}")
        return format_exception_message("填写短信计划基本信息时出错", e)


@mcp.tool()
async def fill_message_content(content: str, product_id: str) -> str:
    """设置发送短信的文本内容，通过商品id生成并插入商品链接
    
    Args:
        content: 短信内容，格式为字符串
        product_id: 商品ID，格式为数字字符串
    """
    try:
        await server_log_info(f"【T】开始设置短信内容和商品链接: 内容长度:{len(content)}, 商品ID:{product_id}")
        result = await playwright_message.fill_message_content(content, product_id)
        await server_log_info(f"【T】设置短信内容和商品链接结果: {result}")
        
        department_result = await playwright_message.set_department_info()
        await server_log_info(f"【T】设置默认费用归属部门结果: {department_result}")
        
        return result + "\n" + department_result
    except Exception as e:
        await server_log_info(f"【E】设置短信内容和商品链接时出错: {str(e)}")
        return format_exception_message("设置短信内容和商品链接时出错", e)


@mcp.tool()
async def get_current_time() -> str:
    """获取当前时间字符串，格式为YYYY-MM-DD HH:MM:SS"""
    try:
        from datetime import datetime
        current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
        return f"当前时间: {current_time}"
    except Exception as e:
        await server_log_info(f"【E】获取当前时间时出错: {str(e)}")
        return format_exception_message("获取当前时间时出错", e)


@mcp.tool()
async def get_current_version() -> str:
    """获取当前工具的版本号"""
    try:
        version = importlib.metadata.version("office_assistant_mcp")
        await server_log_info(f"【T】获取版本号成功: {version}")
        return f"当前版本号: {version}"
    except Exception as e:
        await server_log_info(f"【E】获取版本号时出错: {str(e)}")
        return format_exception_message("获取版本号时出错", e)


def main():
    """MCP服务入口函数"""
    log_info(f"服务启动")
    mcp.run(transport='stdio')


if __name__ == "__main__":
    main()
