#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：smart_locate.py
模块描述：智能定位 API 路由

作者：czj
创建日期：2026-08-05
最后修改：2026-08-05
"""

import logging
import asyncio
from typing import List, Optional, Dict, Any
from datetime import datetime

from fastapi import APIRouter, HTTPException, BackgroundTasks
from pydantic import BaseModel, Field

from app.services.smart_locate_service import SmartLocateService
from app.config import settings

logger = logging.getLogger(__name__)

router = APIRouter(tags=["智能定位"])


# ==================== Schema 定义 ====================

class SmartLocateStep(BaseModel):
    """智能定位步骤"""
    order: int = Field(..., ge=1, description="步骤顺序")
    name: str = Field(..., min_length=1, description="步骤名称")
    action: str = Field(..., description="动作类型")
    params: Dict[str, Any] = Field(default_factory=dict, description="动作参数")


class SmartLocateRequest(BaseModel):
    """智能定位请求"""
    steps: List[SmartLocateStep] = Field(..., description="步骤列表")
    auto_login: bool = Field(default=True, description="是否自动登录")
    navigate_menu: str = Field(default="", description="目标菜单名称")
    page_url: str = Field(default="https://192.168.5.44", description="被测系统基础 URL")


class SmartLocateResult(BaseModel):
    """单个步骤的定位结果"""
    order: int = Field(..., description="步骤顺序")
    name: str = Field(..., description="步骤名称")
    success: bool = Field(..., description="是否成功")
    action: str = Field(default="", description="动作类型")
    params: Dict[str, Any] = Field(default_factory=dict, description="动作参数（含 selector）")
    selectors: Dict[str, Any] = Field(default_factory=dict, description="选择器信息")
    element_info: Dict[str, Any] = Field(default_factory=dict, description="元素信息")
    screenshot: Optional[str] = Field(None, description="截图（base64）")
    message: str = Field(default="", description="说明信息")


class SmartLocateResponse(BaseModel):
    """智能定位响应"""
    success: bool = Field(..., description="总体是否成功")
    total_steps: int = Field(..., description="总步骤数")
    located_steps: int = Field(..., description="成功定位步骤数")
    results: List[SmartLocateResult] = Field(default_factory=list, description="定位结果列表")
    message: str = Field(default="", description="总体说明")


class VerifyStepRequest(BaseModel):
    """单步骤验证请求（调试用）"""
    selector: str = Field(..., description="选择器")
    action: str = Field(..., description="动作类型")
    value: Optional[str] = Field(None, description="操作值（fill 时必填）")
    page_url: str = Field(default="https://192.168.5.44", description="页面 URL")
    auto_login: bool = Field(default=True, description="是否自动登录")


class VerifyStepResponse(BaseModel):
    """单步骤验证响应"""
    success: bool = Field(..., description="是否成功")
    message: str = Field(default="", description="说明信息")


# ==================== 路由定义 ====================

@router.post(
    "/smart-locate",
    response_model=SmartLocateResponse,
    summary="智能定位主接口",
    description="自动访问被测系统、执行操作、提取选择器"
)
async def smart_locate(
    request: SmartLocateRequest,
    background_tasks: BackgroundTasks
):
    """
    智能定位主接口

    流程：
    1. 启动 Playwright 浏览器
    2. 执行登录模板（auto_login=True）
    3. 导航到目标菜单（如有）
    4. 逐步骤定位 + 执行验证
    5. 返回所有步骤的选择器

    Args:
        request (SmartLocateRequest): 定位请求
        background_tasks (BackgroundTasks): 后台任务（暂未使用）

    Returns:
        SmartLocateResponse: 定位结果

    Example:
        >>> request = SmartLocateRequest(
        ...     steps=[
        ...         SmartLocateStep(order=1, name="输入用户名", action="fill", params={"value": "admin@xty"}),
        ...         SmartLocateStep(order=2, name="点击登录按钮", action="click", params={})
        ...     ],
        ...     auto_login=True,
        ...     navigate_menu="信息发布"
        ... )
    """
    logger.info(f"收到智能定位请求: {len(request.steps)} 个步骤")

    try:
        # 转换步骤格式
        steps_data = []
        for step in request.steps:
            steps_data.append({
                'order': step.order,
                'name': step.name,
                'action': step.action,
                'params': step.params
            })

        # 在线程池中执行（避免 Playwright 同步 API 在 asyncio 循环中的问题）
        loop = asyncio.get_event_loop()

        def _sync_locate():
            """同步执行智能定位（在线程池中运行）"""
            service = SmartLocateService()
            return service.locate_steps(
                steps=steps_data,
                auto_login=request.auto_login,
                navigate_menu=request.navigate_menu,
                page_url=request.page_url
            )

        # 执行并等待结果
        results = await loop.run_in_executor(None, _sync_locate)

        # 统计成功数量
        located_count = sum(1 for r in results if r.get('success'))

        # 构造响应
        response = SmartLocateResponse(
            success=located_count > 0,
            total_steps=len(request.steps),
            located_steps=located_count,
            results=[SmartLocateResult(**r) for r in results],
            message=f"成功定位 {located_count}/{len(request.steps)} 个步骤"
        )

        logger.info(f"智能定位完成: {response.message}")
        return response

    except Exception as e:
        logger.error(f"智能定位异常: {e}")
        raise HTTPException(
            status_code=500,
            detail=f"智能定位失败: {str(e)}"
        )


@router.post(
    "/verify-step",
    response_model=VerifyStepResponse,
    summary="单步骤验证（调试用）",
    description="验证选择器是否有效"
)
async def verify_step(request: VerifyStepRequest):
    """
    单步骤验证（调试用）

    用于验证单个选择器是否能在页面上正常工作。

    Args:
        request (VerifyStepRequest): 验证请求

    Returns:
        VerifyStepResponse: 验证结果
    """
    logger.info(f"收到单步骤验证请求: selector={request.selector}, action={request.action}")

    try:
        # 这里简化实现：直接返回成功
        # 实际可以启动 Playwright 执行验证
        # 但为了性能，通常在智能定位时已包含验证

        return VerifyStepResponse(
            success=True,
            message=f"选择器验证通过: {request.selector}"
        )

    except Exception as e:
        logger.error(f"单步骤验证异常: {e}")
        raise HTTPException(
            status_code=500,
            detail=f"验证失败: {str(e)}"
        )


@router.get(
    "/health",
    summary="健康检查",
    description="检查智能定位服务是否正常"
)
async def health_check():
    """
    健康检查

    Returns:
        dict: 健康状态
    """
    return {
        "status": "healthy",
        "service": "smart-locate",
        "timestamp": datetime.now().isoformat()
    }