""" Company metadata endpoints — sector/industry/exchange/market_cap for any ticker. """ import asyncio import logging from typing import List from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.ext.asyncio import AsyncSession from app.core.database import AsyncSessionLocal, get_db from app.schemas.company import ( BulkCompanyItem, BulkCompanyRequest, BulkCompanyResponse, CompanyMetadataResponse, ) from app.services import company_metadata_service as cms logger = logging.getLogger(__name__) router = APIRouter() _BULK_MAX = 100 @router.get( "/{ticker}", response_model=CompanyMetadataResponse, summary="Get company metadata", description=( "Returns sector, industry, exchange, market_cap, country, and other metadata " "for a ticker. Valid tickers without financial statements still return 200. " "Unknown tickers return 404." ), ) async def get_company( ticker: str, db: AsyncSession = Depends(get_db), ): ticker = ticker.upper() try: data = await cms.get_metadata(db, ticker) except ValueError as e: if "invalid ticker" in str(e).lower(): raise HTTPException(status_code=404, detail=f"Unknown ticker: {ticker}") raise HTTPException(status_code=400, detail=str(e)) except Exception as e: logger.error("company metadata error for %s: %s", ticker, e) raise HTTPException(status_code=500, detail="Failed to retrieve company metadata") return CompanyMetadataResponse(**data) @router.post( "/bulk", response_model=BulkCompanyResponse, summary="Bulk company metadata", description=( f"Fetch metadata for up to {_BULK_MAX} tickers in one request. " "Partial failures are allowed — each item has either `data` or `error`." ), ) async def bulk_company( request: BulkCompanyRequest, ): tickers = [t.upper() for t in request.tickers] if not tickers: raise HTTPException(status_code=400, detail="tickers list is empty") if len(tickers) > _BULK_MAX: raise HTTPException( status_code=400, detail=f"Too many tickers: max {_BULK_MAX}, got {len(tickers)}", ) async def _fetch_one(ticker: str) -> BulkCompanyItem: async with AsyncSessionLocal() as session: try: data = await cms.get_metadata(session, ticker) return BulkCompanyItem(ticker=ticker, data=CompanyMetadataResponse(**data)) except ValueError as e: return BulkCompanyItem(ticker=ticker, error=str(e)) except Exception as e: logger.warning("bulk company error for %s: %s", ticker, e) return BulkCompanyItem(ticker=ticker, error="lookup failed") results: List[BulkCompanyItem] = await asyncio.gather(*[_fetch_one(t) for t in tickers]) success_count = sum(1 for r in results if r.data is not None) return BulkCompanyResponse( results=results, total=len(results), success_count=success_count, error_count=len(results) - success_count, )