"""items 域 MySQL 实现：SQLAlchemy 2.0 async。"""

from datetime import datetime

from sqlalchemy import String, Text, func, select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import Mapped, mapped_column

from src.database import Base
from src.items.schemas import ItemCreate, ItemOut, ItemUpdate


class Item(Base):
    __tablename__ = "items"

    id: Mapped[int] = mapped_column(primary_key=True, autoincrement=True)
    name: Mapped[str] = mapped_column(String(128), index=True)
    description: Mapped[str | None] = mapped_column(Text, nullable=True)
    created_at: Mapped[datetime] = mapped_column(server_default=func.now())

    def to_out(self) -> ItemOut:
        return ItemOut(
            id=str(self.id),
            name=self.name,
            description=self.description,
            created_at=self.created_at,
        )


class MySQLItemRepo:
    """仓储模式：所有 SQL 集中在此，router 不直接碰 ORM。"""

    def __init__(self, session: AsyncSession):
        self.session = session

    async def create(self, data: ItemCreate) -> ItemOut:
        item = Item(name=data.name, description=data.description)
        self.session.add(item)
        await self.session.commit()
        await self.session.refresh(item)
        return item.to_out()

    async def get(self, item_id: str) -> ItemOut | None:
        item = await self.session.get(Item, int(item_id))
        return item.to_out() if item else None

    async def list(self, skip: int = 0, limit: int = 20) -> tuple[int, list[ItemOut]]:
        total = await self.session.scalar(select(func.count(Item.id)))
        rows = await self.session.scalars(select(Item).offset(skip).limit(limit))
        return total or 0, [r.to_out() for r in rows]

    async def update(self, item_id: str, data: ItemUpdate) -> ItemOut | None:
        item = await self.session.get(Item, int(item_id))
        if not item:
            return None
        for field, value in data.model_dump(exclude_unset=True).items():
            setattr(item, field, value)
        await self.session.commit()
        await self.session.refresh(item)
        return item.to_out()

    async def delete(self, item_id: str) -> bool:
        item = await self.session.get(Item, int(item_id))
        if not item:
            return False
        await self.session.delete(item)
        await self.session.commit()
        return True
