import json from fastapi import APIRouter, Depends, Query from sqlalchemy import text from .db import get_db from .layout_routes import DEFAULTS # PUBLIC storefront API — the customer-facing shop reads its theme/layout + catalog here. # No auth (theme + in-stock catalog aren't secret); driven by what the builder saves. router = APIRouter(prefix="/shop", tags=["shop"]) @router.get("/config") async def shop_config(db=Depends(get_db)): row = (await db.execute(text("SELECT config FROM store_config WHERE store_id=1"))).first() cfg = row[0] if row else None if isinstance(cfg, str): cfg = json.loads(cfg) return cfg or DEFAULTS @router.get("/catalog") async def shop_catalog(q: str = Query(""), page: int = Query(1, ge=1), db=Depends(get_db)): per = 24 where = ["i.in_stock", "i.store_id = 1"] params = {"per": per, "off": (page - 1) * per} if q: where.append("(coalesce(i.title, dc.title) ILIKE :q OR dc.artist ILIKE :q)") params["q"] = f"%{q}%" w = " AND ".join(where) items = [dict(r) for r in (await db.execute(text(f""" SELECT i.sku, coalesce(i.title, dc.title) AS title, dc.artist, dc.thumb, i.price::float AS price, i.condition, i.kind FROM inventory i LEFT JOIN disc_cache dc ON dc.release_id = i.release_id WHERE {w} ORDER BY i.updated_at DESC NULLS LAST LIMIT :per OFFSET :off"""), params)).mappings()] cparams = {k: v for k, v in params.items() if k not in ("per", "off")} total = (await db.execute(text( f"SELECT count(*) FROM inventory i LEFT JOIN disc_cache dc ON dc.release_id=i.release_id WHERE {w}" ), cparams)).scalar() return {"items": items, "page": page, "per": per, "total": total}