"""
用户 CRUD 操作
==============

用户认证相关的数据访问。
"""

from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession

from app.crud.base import CRUDBase
from app.models.user import User


class UserCRUD(CRUDBase[User]):
    """用户数据访问对象"""

    def __init__(self) -> None:
        super().__init__(User)

    async def get_by_mobile(self, db: AsyncSession, *, mobile: str) -> User | None:
        """根据手机号获取用户"""
        result = await db.execute(select(User).where(User.mobile == mobile))
        return result.scalar_one_or_none()

    async def get_or_create_by_mobile(
        self, db: AsyncSession, *, mobile: str, nickname: str | None = None, source: str = "unknown"
    ) -> User:
        """
        根据手机号获取或创建用户

        Returns:
            已存在或新创建的用户
        """
        user = await self.get_by_mobile(db, mobile=mobile)

        if user is None:
            # 创建新用户
            user = await self.create(
                db,
                obj_in={
                    "mobile": mobile,
                    "nickname": nickname or f"用户_{mobile[-4:]}",
                    "source": source,
                },
            )

        return user

    async def update_login_info(
        self, db: AsyncSession, *, user_id: str, ip: str | None = None
    ) -> User | None:
        """
        更新用户最后登录信息
        """
        from datetime import UTC, datetime

        user = await self.get(db, id=user_id)
        if user is None:
            return None

        user.last_login_at = datetime.now(UTC)
        if ip:
            user.last_login_ip = ip

        await db.commit()
        await db.refresh(user)
        return user

    async def update_extra(
        self, db: AsyncSession, *, user_id: str, extra: dict
    ) -> bool:
        """
        原子更新用户 extra 字段（JSONB）

        使用 SQLAlchemy 的 update 语句避免读-改-写的竞态条件。
        """
        from sqlalchemy import update

        stmt = (
            update(User)
            .where(User.id == user_id)
            .values(extra=extra)
        )
        result = await db.execute(stmt)
        await db.commit()
        return result.rowcount > 0


# 导出实例
user = UserCRUD()
