from __future__ import annotations from datetime import datetime from sqlalchemy.ext.asyncio import AsyncSession from app.core.exceptions import ConflictException, NotFoundException from app.models.mariadb.device import Device from app.repositories.device_repo import DeviceRepository from app.schemas.device import DeviceCreate, DeviceRead, DeviceUpdate class DeviceService: def __init__(self, session: AsyncSession): self.device_repo = DeviceRepository(session) async def get_device(self, device_id: int) -> DeviceRead: device = await self.device_repo.get_by_id(device_id) if not device or device.is_deleted: raise NotFoundException("Device not found") return DeviceRead.model_validate(device) async def get_device_by_uid(self, device_uid: str) -> DeviceRead: device = await self.device_repo.get_by_uid(device_uid) if not device: raise NotFoundException("Device not found") return DeviceRead.model_validate(device) async def list_devices(self, skip: int = 0, limit: int = 20) -> list[DeviceRead]: devices = await self.device_repo.get_all( skip=skip, limit=limit, filters={"is_deleted": False} ) return [DeviceRead.model_validate(d) for d in devices] async def count_devices(self) -> int: return await self.device_repo.count(filters={"is_deleted": False}) async def create_device(self, data: DeviceCreate) -> DeviceRead: existing = await self.device_repo.get_by_uid(data.device_uid) if existing: raise ConflictException("Device UID already registered") device = Device(**data.model_dump()) device = await self.device_repo.create(device) return DeviceRead.model_validate(device) async def update_device(self, device_id: int, data: DeviceUpdate) -> DeviceRead: device = await self.device_repo.get_by_id(device_id) if not device or device.is_deleted: raise NotFoundException("Device not found") update_data = data.model_dump(exclude_none=True) device = await self.device_repo.update(device, update_data) return DeviceRead.model_validate(device) async def delete_device(self, device_id: int) -> None: device = await self.device_repo.get_by_id(device_id) if not device or device.is_deleted: raise NotFoundException("Device not found") await self.device_repo.update( device, {"is_deleted": True, "deleted_at": datetime.utcnow()} ) async def update_device_status(self, device_uid: str, status: str) -> DeviceRead: device = await self.device_repo.get_by_uid(device_uid) if not device: raise NotFoundException("Device not found") device = await self.device_repo.update( device, {"status": status, "last_seen_at": datetime.utcnow()} ) return DeviceRead.model_validate(device)