#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：login_template_service.py
模块描述：登录模板业务服务，负责模板的增删改查和默认模板管理

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

import logging
from typing import Optional, List

from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, delete
from sqlalchemy.orm import selectinload

from app.models.login_template import LoginTemplate
from app.schemas.login_template import (
    LoginTemplateCreate,
    LoginTemplateUpdate,
    TemplateStepDefinition,
)
from app.config import settings
from app.utils.id_generator import generate_id

logger = logging.getLogger(__name__)


class LoginTemplateService:
    """
    登录模板服务类

    负责登录模板的业务逻辑处理，包括增删改查、默认模板管理。

    Attributes:
        db (AsyncSession): 数据库会话对象

    Example:
        >>> service = LoginTemplateService(db)
        >>> template = await service.create(LoginTemplateCreate(
        ...     name="统一管理平台登录模板",
        ...     template_type="login",
        ...     steps=[{"order": 1, "action": "navigate", "params": {"url": "https://192.168.5.44"}}]
        ... ))
    """

    def __init__(self, db: AsyncSession):
        """
        初始化模板服务

        Args:
            db (AsyncSession): 数据库会话对象

        Raises:
            ValueError: 当 db 为 None 时抛出
        """
        if db is None:
            raise ValueError("数据库会话不能为空")
        self.db = db

    async def create(self, template_data: LoginTemplateCreate) -> LoginTemplate:
        """
        创建登录模板

        Args:
            template_data (LoginTemplateCreate): 模板创建数据

        Returns:
            LoginTemplate: 创建的模板对象
        """
        # 生成唯一 ID
        template_id = generate_id("template")

        # 转换步骤为 dict
        steps_data = []
        for step in template_data.steps:
            steps_data.append({
                "order": step.order,
                "name": step.name,
                "action": step.action,
                "params": step.params,
                "expected": step.expected,
            })

        # 创建模板对象
        template = LoginTemplate(
            id=template_id,
            name=template_data.name,
            description=template_data.description,
            template_type=template_data.template_type,
            target_system=template_data.target_system,
            base_url=template_data.base_url,
            steps=steps_data,
            is_default=template_data.is_default,
        )

        # 如果设置为默认模板，先清除其他同类型默认模板
        if template_data.is_default:
            await self._clear_default_flag(template_data.template_type)

        self.db.add(template)
        await self.db.flush()
        await self.db.refresh(template)

        logger.info(f"创建登录模板成功: {template.id} - {template.name}")
        return template

    async def get_by_id(self, template_id: str) -> Optional[LoginTemplate]:
        """
        根据 ID 获取模板

        Args:
            template_id (str): 模板ID

        Returns:
            Optional[LoginTemplate]: 模板对象，不存在则返回 None
        """
        result = await self.db.execute(
            select(LoginTemplate).where(LoginTemplate.id == template_id)
        )
        return result.scalar_one_or_none()

    async def get_list(
        self,
        template_type: Optional[str] = None,
        status: Optional[str] = None,
        skip: int = 0,
        limit: int = 100,
    ) -> tuple[List[LoginTemplate], int]:
        """
        获取模板列表（支持筛选和分页）

        Args:
            template_type (Optional[str]): 模板类型筛选
            status (Optional[str]): 状态筛选
            skip (int): 跳过数量
            limit (int): 返回数量

        Returns:
            tuple: (模板列表, 总数)
        """
        # 构建查询条件
        conditions = []
        if template_type:
            conditions.append(LoginTemplate.template_type == template_type)
        if status:
            conditions.append(LoginTemplate.status == status)

        # 查询总数
        count_query = select(func.count()).select_from(LoginTemplate)
        if conditions:
            count_query = count_query.where(*conditions)
        total_result = await self.db.execute(count_query)
        total = total_result.scalar()

        # 查询列表
        query = select(LoginTemplate).order_by(LoginTemplate.created_at.desc())
        if conditions:
            query = query.where(*conditions)
        query = query.offset(skip).limit(limit)

        result = await self.db.execute(query)
        templates = list(result.scalars().all())

        return templates, total

    async def update(
        self,
        template_id: str,
        template_data: LoginTemplateUpdate
    ) -> Optional[LoginTemplate]:
        """
        更新模板

        Args:
            template_id (str): 模板ID
            template_data (LoginTemplateUpdate): 更新数据

        Returns:
            Optional[LoginTemplate]: 更新后的模板对象

        Raises:
            HTTPException: 模板不存在时抛出 404
        """
        template = await self.get_by_id(template_id)
        if not template:
            return None

        # 更新字段
        update_data = template_data.model_dump(exclude_unset=True)

        # 如果更新步骤，需要转换格式
        if "steps" in update_data and update_data["steps"] is not None:
            steps_data = []
            for step in update_data["steps"]:
                steps_data.append({
                    "order": step.order,
                    "name": step.name,
                    "action": step.action,
                    "params": step.params,
                    "expected": step.expected,
                })
            update_data["steps"] = steps_data

        # 如果设置为默认模板，先清除其他同类型默认模板
        if update_data.get("is_default"):
            await self._clear_default_flag(template.template_type)

        for key, value in update_data.items():
            setattr(template, key, value)

        await self.db.flush()
        await self.db.refresh(template)

        logger.info(f"更新登录模板成功: {template.id}")
        return template

    async def delete(self, template_id: str) -> bool:
        """
        删除模板

        Args:
            template_id (str): 模板ID

        Returns:
            bool: 删除成功返回 True，不存在返回 False
        """
        template = await self.get_by_id(template_id)
        if not template:
            return False

        await self.db.delete(template)
        await self.db.flush()

        logger.info(f"删除登录模板成功: {template_id}")
        return True

    async def get_default_template(self, template_type: str = "login") -> Optional[LoginTemplate]:
        """
        获取默认模板

        Args:
            template_type (str): 模板类型

        Returns:
            Optional[LoginTemplate]: 默认模板对象
        """
        result = await self.db.execute(
            select(LoginTemplate).where(
                LoginTemplate.template_type == template_type,
                LoginTemplate.is_default == True,
                LoginTemplate.status == "active"
            )
        )
        return result.scalar_one_or_none()

    async def set_default_template(self, template_id: str) -> Optional[LoginTemplate]:
        """
        设置默认模板

        Args:
            template_id (str): 模板ID

        Returns:
            Optional[LoginTemplate]: 更新后的模板对象
        """
        template = await self.get_by_id(template_id)
        if not template:
            return None

        # 清除同类型其他默认模板
        await self._clear_default_flag(template.template_type)

        # 设置当前模板为默认
        template.is_default = True
        await self.db.flush()
        await self.db.refresh(template)

        logger.info(f"设置默认模板成功: {template_id}")
        return template

    async def _clear_default_flag(self, template_type: str) -> None:
        """
        清除同类型模板的默认标志

        Args:
            template_type (str): 模板类型
        """
        await self.db.execute(
            LoginTemplate.__table__.update()
            .where(LoginTemplate.template_type == template_type)
            .values(is_default=False)
        )

    @staticmethod
    def get_default_login_steps() -> List[dict]:
        """
        获取默认登录模板步骤（8 步登录 + 3 步功能中心导航）

        验证码固定使用 csba。

        Returns:
            List[dict]: 登录步骤列表
        """
        return [
            # 登录流程（8 步）
            {
                "order": 1,
                "name": "访问登录页面",
                "action": "navigate",
                "params": {"url": settings.TARGET_URL},
                "expected": ""
            },
            {
                "order": 2,
                "name": "等待登录表单加载",
                "action": "wait",
                "params": {"selector": "input[placeholder*=\"手机号\"]", "timeout": 10000},
                "expected": ""
            },
            {
                "order": 3,
                "name": "输入用户名",
                "action": "fill",
                "params": {"selector": "input[placeholder*=\"手机号\"]", "value": "admin@xty"},
                "expected": ""
            },
            {
                "order": 4,
                "name": "输入密码",
                "action": "fill",
                "params": {"selector": "input[type=\"password\"]", "value": "Ubains@13579"},
                "expected": ""
            },
            {
                "order": 5,
                "name": "输入验证码",
                "action": "fill",
                "params": {"selector": "input[placeholder*=\"图\"]", "value": "csba"},
                "expected": ""
            },
            {
                "order": 6,
                "name": "勾选协议复选框",
                "action": "click",
                "params": {"selector": ".el-checkbox"},
                "expected": ""
            },
            {
                "order": 7,
                "name": "点击登录按钮",
                "action": "click",
                "params": {"selector": "button:has-text(\"登录\")"},
                "expected": ""
            },
            {
                "order": 8,
                "name": "等待登录跳转完成",
                "action": "wait",
                "params": {"selector": "[class*='nav'], .container, .el-main", "timeout": 15000},
                "expected": ""
            },
        ]

    @staticmethod
    def get_default_navigation_steps(menu_name: str = "信息发布") -> List[dict]:
        """
        获取默认功能中心导航模板步骤（3 步）

        Args:
            menu_name (str): 目标菜单名称

        Returns:
            List[dict]: 导航步骤列表
        """
        return [
            {
                "order": 9,
                "name": "点击功能中心图标",
                "action": "click",
                "params": {"selector": "//*[@id=\"Home\"]/div[1]/div[1]"},
                "expected": ""
            },
            {
                "order": 10,
                "name": "等待功能抽屉打开",
                "action": "wait",
                "params": {"selector": ".el-drawer", "timeout": 5000},
                "expected": ""
            },
            {
                "order": 11,
                "name": f"点击{menu_name}菜单",
                "action": "click",
                "params": {"selector": f".el-drawer >> text=\"{menu_name}\""},
                "expected": ""
            },
        ]

    async def ensure_default_templates(self) -> None:
        """
        确保默认模板存在

        如果不存在默认模板，则创建。
        """
        # 检查是否存在登录模板
        login_template = await self.get_default_template("login")
        if not login_template:
            # 创建默认登录模板
            login_steps = self.get_default_login_steps()
            await self.create(LoginTemplateCreate(
                name="统一管理平台登录模板",
                description="预置登录模板（含协议勾选），验证码固定 csba",
                template_type="login",
                target_system="统一管理平台",
                base_url=settings.TARGET_URL,
                steps=[TemplateStepDefinition(**step) for step in login_steps],
                is_default=True,
            ))
            logger.info("创建默认登录模板成功")

        # 检查是否存在导航模板
        navigation_template = await self.get_default_template("navigation")
        if not navigation_template:
            # 创建默认导航模板（示例：信息发布）
            navigation_steps = self.get_default_navigation_steps("信息发布")
            await self.create(LoginTemplateCreate(
                name="功能中心导航模板",
                description="预置功能中心导航模板，可指定目标菜单",
                template_type="navigation",
                target_system="统一管理平台",
                base_url=settings.TARGET_URL,
                steps=[TemplateStepDefinition(**step) for step in navigation_steps],
                is_default=True,
            ))
            logger.info("创建默认导航模板成功")