"""Store service — list stores, manage user store account connections.""" import json from cryptography.fernet import Fernet from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload from cartsnitch_api.config import settings def _get_fernet() -> Fernet: return Fernet(settings.fernet_key.encode()) class StoreService: def __init__(self, db: AsyncSession) -> None: self.db = db async def list_stores(self) -> list[dict]: from cartsnitch_api.models import Store result = await self.db.execute(select(Store).order_by(Store.name)) stores = result.scalars().all() return [ { "id": s.id, "name": s.name, "slug": s.slug, "logo_url": s.logo_url, "supported": True, } for s in stores ] async def list_user_stores(self, user_id: str) -> list[dict]: from cartsnitch_api.models import UserStoreAccount result = await self.db.execute( select(UserStoreAccount) .where(UserStoreAccount.user_id == user_id) .options(selectinload(UserStoreAccount.store)) ) accounts = result.scalars().all() return [ { "store": { "id": a.store.id, "name": a.store.name, "slug": a.store.slug, "logo_url": a.store.logo_url, "supported": True, }, "connected": a.status == "active", "last_sync_at": a.last_sync_at, "sync_status": a.status, } for a in accounts ] async def connect_store(self, user_id: str, store_slug: str, credentials: dict | None) -> dict: from cartsnitch_api.models import Store, UserStoreAccount result = await self.db.execute(select(Store).where(Store.slug == store_slug)) store = result.scalar_one_or_none() if not store: raise LookupError(f"Store '{store_slug}' not found") existing = await self.db.execute( select(UserStoreAccount).where( UserStoreAccount.user_id == user_id, UserStoreAccount.store_id == store.id, ) ) if existing.scalar_one_or_none(): raise ValueError("Store account already connected") encrypted_data = None if credentials: fernet = _get_fernet() encrypted_data = { "encrypted": fernet.encrypt(json.dumps(credentials).encode()).decode() } account = UserStoreAccount( user_id=user_id, store_id=store.id, session_data=encrypted_data, status="active", ) self.db.add(account) await self.db.commit() await self.db.refresh(account) return { "store": { "id": store.id, "name": store.name, "slug": store.slug, "logo_url": store.logo_url, "supported": True, }, "connected": True, "last_sync_at": None, "sync_status": "active", } async def disconnect_store(self, user_id: str, store_slug: str) -> None: from cartsnitch_api.models import Store, UserStoreAccount result = await self.db.execute(select(Store).where(Store.slug == store_slug)) store = result.scalar_one_or_none() if not store: raise LookupError(f"Store '{store_slug}' not found") result = await self.db.execute( select(UserStoreAccount).where( UserStoreAccount.user_id == user_id, UserStoreAccount.store_id == store.id, ) ) account = result.scalar_one_or_none() if not account: raise LookupError("Store account not connected") await self.db.delete(account) await self.db.commit()