"""API routes for Amar (MOCK) vein - Mock Amar API for testing.""" import asyncio import random from fastapi import APIRouter, HTTPException, Query from fastapi.responses import JSONResponse from typing import Optional, List, Dict, Any from pydantic import BaseModel # Import datagen from ward/tools import sys from pathlib import Path ward_tools_path = Path(__file__).parent.parent.parent.parent.parent / "ward" / "tools" sys.path.insert(0, str(ward_tools_path)) from datagen.amar import AmarDataGenerator from ..core.config import settings router = APIRouter() # In-memory storage for mock data (reset on restart) MOCK_DB = { "petowners": {}, "pets": {}, "carts": {}, "service_requests": {}, } # Request/Response Models class CreatePetOwnerRequest(BaseModel): address: str email: Optional[str] = None phone: Optional[str] = None class CreatePetRequest(BaseModel): owner_id: int name: str species: str # DOG, CAT age: Optional[int] = None age_unit: str = "years" # years, months class CreateCartRequest(BaseModel): owner_id: int class AddCartItemRequest(BaseModel): service_id: int pet_id: int quantity: int = 1 async def _mock_delay(): """Add realistic delay if enabled.""" if settings.enable_random_delays: delay_ms = random.randint(settings.min_delay_ms, settings.max_delay_ms) await asyncio.sleep(delay_ms / 1000) def _maybe_error(): """Randomly raise an error based on error_rate.""" if random.random() < settings.error_rate: raise HTTPException(500, "Mock error: Simulated failure") @router.get("/health") async def health(): """Health check endpoint.""" return { "status": "ok", "vein": "Amar\n(MOCK)", "message": "Mock Amar API for testing", "_mock": True, } @router.post("/api/v1/pet-owners/") async def create_petowner(request: CreatePetOwnerRequest): """Create a guest petowner (VET-536).""" await _mock_delay() _maybe_error() owner = AmarDataGenerator.petowner( address=request.address, is_guest=True, email=request.email, phone=request.phone, ) # Store in mock DB MOCK_DB["petowners"][owner["id"]] = owner owner["_mock"] = True return owner @router.get("/api/v1/pet-owners/{owner_id}") async def get_petowner(owner_id: int): """Get petowner by ID.""" await _mock_delay() _maybe_error() owner = MOCK_DB["petowners"].get(owner_id) if not owner: raise HTTPException(404, f"PetOwner {owner_id} not found") return owner @router.post("/api/v1/pets/") async def create_pet(request: CreatePetRequest): """Create a pet (VET-537).""" await _mock_delay() _maybe_error() # Verify owner exists if request.owner_id not in MOCK_DB["petowners"]: raise HTTPException(404, f"Owner {request.owner_id} not found") pet = AmarDataGenerator.pet( owner_id=request.owner_id, name=request.name, species=request.species, age_value=request.age, age_unit=request.age_unit, ) # Store in mock DB MOCK_DB["pets"][pet["id"]] = pet pet["_mock"] = True return pet @router.get("/api/v1/pets/{pet_id}") async def get_pet(pet_id: int): """Get pet by ID.""" await _mock_delay() _maybe_error() pet = MOCK_DB["pets"].get(pet_id) if not pet: raise HTTPException(404, f"Pet {pet_id} not found") return pet @router.post("/api/v1/cart/") async def create_cart(request: CreateCartRequest): """Create a cart (VET-538).""" await _mock_delay() _maybe_error() # Verify owner exists if request.owner_id not in MOCK_DB["petowners"]: raise HTTPException(404, f"Owner {request.owner_id} not found") cart = AmarDataGenerator.cart(owner_id=request.owner_id) # Store in mock DB MOCK_DB["carts"][cart["id"]] = cart cart["_mock"] = True return cart @router.post("/api/v1/cart/{cart_id}/items/") async def add_cart_item(cart_id: int, request: AddCartItemRequest): """Add item to cart and recalculate summary.""" await _mock_delay() _maybe_error() cart = MOCK_DB["carts"].get(cart_id) if not cart: raise HTTPException(404, f"Cart {cart_id} not found") # Get service price services = AmarDataGenerator.SERVICES service = next((s for s in services if s["id"] == request.service_id), None) if not service: raise HTTPException(404, f"Service {request.service_id} not found") # Add item item = { "service_id": request.service_id, "service_name": service["name"], "pet_id": request.pet_id, "quantity": request.quantity, "price": service["price"], } cart["items"].append(item) # Recalculate summary cart = AmarDataGenerator.calculate_cart_summary(cart, cart["items"]) MOCK_DB["carts"][cart_id] = cart cart["_mock"] = True return cart @router.get("/api/v1/cart/{cart_id}") async def get_cart(cart_id: int): """Get cart by ID.""" await _mock_delay() _maybe_error() cart = MOCK_DB["carts"].get(cart_id) if not cart: raise HTTPException(404, f"Cart {cart_id} not found") return cart @router.get("/api/v1/services/") async def list_services( species: Optional[str] = Query(None), neighborhood_id: Optional[int] = Query(None), ): """List available services filtered by species and neighborhood (VET-540).""" await _mock_delay() _maybe_error() services = AmarDataGenerator.filter_services( species=species, neighborhood_id=neighborhood_id, ) for service in services: service["_mock"] = True return services @router.get("/api/v1/categories/") async def list_categories( species: Optional[str] = Query(None), neighborhood_id: Optional[int] = Query(None), ): """List categories with available services (VET-539).""" await _mock_delay() _maybe_error() categories = AmarDataGenerator.filter_categories( species=species, neighborhood_id=neighborhood_id, ) for category in categories: category["_mock"] = True return categories @router.post("/solicitudes/service-requests/") async def create_service_request(cart_id: int, requested_date: Optional[str] = None): """Create a service request.""" await _mock_delay() _maybe_error() cart = MOCK_DB["carts"].get(cart_id) if not cart: raise HTTPException(404, f"Cart {cart_id} not found") request = AmarDataGenerator.service_request( cart_id=cart_id, requested_date=requested_date, ) MOCK_DB["service_requests"][request["id"]] = request request["_mock"] = True return request @router.get("/mock/reset") async def reset_mock_db(): """Reset the mock database (useful for testing).""" MOCK_DB["petowners"].clear() MOCK_DB["pets"].clear() MOCK_DB["carts"].clear() MOCK_DB["service_requests"].clear() return { "message": "Mock database reset", "_mock": True, } @router.get("/mock/stats") async def mock_stats(): """Get mock database statistics.""" return { "petowners": len(MOCK_DB["petowners"]), "pets": len(MOCK_DB["pets"]), "carts": len(MOCK_DB["carts"]), "service_requests": len(MOCK_DB["service_requests"]), "_mock": True, }