#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
模块名称：api_preset_service.py
模块描述：API 接口预设服务层，提供 CRUD 业务逻辑

作者：czj
创建日期：2026-08-13
"""

import logging
from typing import Any, Dict, List, Optional, Tuple

from fastapi import HTTPException
from sqlalchemy import select, func, desc
from sqlalchemy.ext.asyncio import AsyncSession

from app.models.api_preset import ApiPreset
from app.utils.id_generator import generate_id

logger = logging.getLogger(__name__)


class ApiPresetService:
    """
    API 接口预设服务

    提供接口预设的增删改查业务逻辑。
    """

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

        Args:
            db: 数据库会话
        """
        self.db = db

    async def get_preset(self, preset_id: str) -> Optional[ApiPreset]:
        """
        获取预设详情

        Args:
            preset_id: 预设ID

        Returns:
            ApiPreset: 预设对象，不存在返回 None
        """
        return await self.db.get(ApiPreset, preset_id)

    async def list_presets(
        self,
        page: int = 1,
        page_size: int = 20,
        keyword: Optional[str] = None,
    ) -> Tuple[List[ApiPreset], int]:
        """
        获取预设列表（分页）

        Args:
            page: 页码
            page_size: 每页数量
            keyword: 按名称/URL 关键词搜索

        Returns:
            tuple: (预设列表, 总数)
        """
        query = select(ApiPreset)
        count_query = select(func.count()).select_from(ApiPreset)

        if keyword:
            like_pattern = f"%{keyword}%"
            query = query.where(
                (ApiPreset.name.like(like_pattern)) | (ApiPreset.target_url.like(like_pattern))
            )
            count_query = count_query.where(
                (ApiPreset.name.like(like_pattern)) | (ApiPreset.target_url.like(like_pattern))
            )

        total = (await self.db.execute(count_query)).scalar() or 0

        query = (
            query.order_by(desc(ApiPreset.updated_at))
            .offset((page - 1) * page_size)
            .limit(page_size)
        )
        result = await self.db.execute(query)
        items = list(result.scalars().all())

        return items, total

    async def create_preset(self, data: Dict[str, Any]) -> ApiPreset:
        """
        创建接口预设

        Args:
            data: 预设数据

        Returns:
            ApiPreset: 创建的预设对象

        Raises:
            HTTPException: 名称已存在时抛出 409
        """
        # 检查名称唯一性
        name = data.get("name", "").strip()
        if name:
            existing = await self.db.execute(
                select(ApiPreset).where(ApiPreset.name == name)
            )
            if existing.scalar_one_or_none():
                raise HTTPException(
                    status_code=409,
                    detail=f"预设名称已存在: {name}"
                )

        capture_rules = data.pop("capture_rules", None)
        preset = ApiPreset(
            id=generate_id("preset"),
            **data,
        )
        if capture_rules is not None:
            preset.capture_rules = capture_rules

        self.db.add(preset)
        await self.db.commit()
        await self.db.refresh(preset)
        logger.info(f"创建接口预设: {preset.id} - {preset.name}")
        return preset

    async def update_preset(
        self, preset_id: str, data: Dict[str, Any]
    ) -> Optional[ApiPreset]:
        """
        更新接口预设

        Args:
            preset_id: 预设ID
            data: 更新数据

        Returns:
            ApiPreset: 更新后的预设，不存在返回 None

        Raises:
            HTTPException: 名称冲突时抛出 409
        """
        preset = await self.get_preset(preset_id)
        if not preset:
            return None

        # 检查名称唯一性（排除自身）
        name = data.get("name")
        if name and name != preset.name:
            existing = await self.db.execute(
                select(ApiPreset).where(
                    ApiPreset.name == name,
                    ApiPreset.id != preset_id,
                )
            )
            if existing.scalar_one_or_none():
                raise HTTPException(
                    status_code=409,
                    detail=f"预设名称已存在: {name}"
                )

        capture_rules = data.pop("capture_rules", None)
        for key, value in data.items():
            if value is not None and hasattr(preset, key):
                setattr(preset, key, value)
        if capture_rules is not None:
            preset.capture_rules = capture_rules

        await self.db.commit()
        await self.db.refresh(preset)
        return preset

    async def delete_preset(self, preset_id: str) -> bool:
        """
        删除接口预设

        Args:
            preset_id: 预设ID

        Returns:
            bool: 是否成功删除
        """
        preset = await self.get_preset(preset_id)
        if not preset:
            return False

        await self.db.delete(preset)
        await self.db.commit()
        logger.info(f"删除接口预设: {preset_id} - {preset.name}")
        return True