"""Fundamentals router — fundamental data endpoints.""" import json from fastapi import APIRouter, Depends from sqlalchemy.ext.asyncio import AsyncSession from app.dependencies import get_db, require_access from app.schemas.common import APIEnvelope from app.schemas.fundamental import FundamentalResponse from app.services.fundamental_service import get_fundamental router = APIRouter(tags=["fundamentals"]) def _parse_unavailable_fields(raw_json: str) -> dict[str, str]: """Deserialize unavailable_fields_json, defaulting to {} on invalid JSON.""" try: parsed = json.loads(raw_json) except (json.JSONDecodeError, TypeError): return {} if not isinstance(parsed, dict): return {} return {k: v for k, v in parsed.items() if isinstance(k, str) and isinstance(v, str)} @router.get("/fundamentals/{symbol}", response_model=APIEnvelope) async def read_fundamentals( symbol: str, _user=Depends(require_access), db: AsyncSession = Depends(get_db), ) -> APIEnvelope: """Get latest fundamental data for a symbol.""" record = await get_fundamental(db, symbol) if record is None: data = FundamentalResponse(symbol=symbol.strip().upper()) else: data = FundamentalResponse( symbol=symbol.strip().upper(), pe_ratio=record.pe_ratio, revenue_growth=record.revenue_growth, earnings_surprise=record.earnings_surprise, market_cap=record.market_cap, fetched_at=record.fetched_at, unavailable_fields=_parse_unavailable_fields(record.unavailable_fields_json), ) return APIEnvelope(status="success", data=data.model_dump())