from typing import Optional, List, Dict, Any from datetime import datetime import hashlib import re import httpx from fastapi import HTTPException from app.core.settings import settings from app.services.fakerapi_client import FakerApiClient def normalize_cpf(value: str) -> str: return re.sub(r"\D", "", value or "") def _parse_float(value: Any, default: float = 0.0) -> float: if value is None: return default if isinstance(value, (int, float)): return float(value) text = str(value).replace("R$", "").replace(" ", "") text = text.replace(".", "").replace(",", ".") if "," in text else text try: return float(text) except Exception: return default def _stable_int(seed_text: str) -> int: digest = hashlib.sha256(seed_text.encode("utf-8")).hexdigest() return int(digest[:16], 16) def _cpf_from_any(value: Any) -> str: as_int = _stable_int(str(value)) % (10**11) return str(as_int).zfill(11) async def _fetch_faker_products(count: int) -> List[Dict[str, Any]]: client = FakerApiClient() try: return await client.fetch_resource("products", quantity=count) except httpx.HTTPStatusError as exc: status_code = exc.response.status_code if exc.response is not None else 502 request_url = str(exc.request.url) if exc.request is not None else "desconhecida" raise HTTPException( status_code=502, detail=f"FakerAPI retornou HTTP {status_code} em '{request_url}'.", ) except httpx.RequestError as exc: raise HTTPException( status_code=502, detail=( "Falha de rede ao acessar FakerAPI (products). " f"{exc.__class__.__name__}: {exc}. " "Verifique egress/NAT do Cloud Run e resolucao DNS." ), ) except Exception: raise HTTPException( status_code=502, detail="Falha de integracao com FakerAPI ao consultar products.", ) async def _fetch_faker_persons(count: int) -> List[Dict[str, Any]]: client = FakerApiClient() try: return await client.fetch_resource("persons", quantity=count) except httpx.HTTPStatusError as exc: status_code = exc.response.status_code if exc.response is not None else 502 request_url = str(exc.request.url) if exc.request is not None else "desconhecida" raise HTTPException( status_code=502, detail=f"FakerAPI retornou HTTP {status_code} em '{request_url}'.", ) except httpx.RequestError as exc: raise HTTPException( status_code=502, detail=( "Falha de rede ao acessar FakerAPI (persons). " f"{exc.__class__.__name__}: {exc}. " "Verifique egress/NAT do Cloud Run e resolucao DNS." ), ) except Exception: raise HTTPException( status_code=502, detail="Falha de integracao com FakerAPI ao consultar persons.", ) async def consultar_estoque(preco_max: float, categoria: Optional[str] = None) -> List[Dict[str, Any]]: raw = await _fetch_faker_products(settings.fakerapi_products_quantity) registros: List[Dict[str, Any]] = [] for item in raw: categories = item.get("categories") if isinstance(categories, list) and categories: category_value = str(categories[0]) else: category_value = str(item.get("category") or "geral") registro = { "id": item.get("id"), "modelo": item.get("name") or item.get("title") or "Veiculo", "categoria": category_value.lower(), "preco": _parse_float(item.get("price"), 0.0), } registros.append(registro) categoria_norm = categoria.lower() if categoria else None return [ r for r in registros if _parse_float(r.get("preco"), 0.0) <= preco_max and (categoria_norm is None or str(r.get("categoria", "")).lower() == categoria_norm) ] async def validar_cliente_venda(cpf: str, valor_veiculo: float) -> Dict[str, Any]: cpf_norm = normalize_cpf(cpf) raw = await _fetch_faker_persons(settings.fakerapi_persons_quantity) registros: List[Dict[str, Any]] = [] for item in raw: person_id = item.get("id") or item.get("email") or item.get("firstname") generated_cpf = _cpf_from_any(person_id) entropy = _stable_int(f"{generated_cpf}:{settings.fakerapi_seed}") limite = float(30000 + (entropy % 150000)) score = int(300 + (entropy % 550)) possui_restricao = (entropy % 7 == 0) nome = f"{item.get('firstname', '')} {item.get('lastname', '')}".strip() or "Cliente" registros.append( { "cpf": generated_cpf, "nome": nome, "score": score, "limite_credito": limite, "possui_restricao": possui_restricao, } ) cliente = next((r for r in registros if normalize_cpf(r.get("cpf", "")) == cpf_norm), None) if not cliente: entropy = _stable_int(f"{cpf_norm}:{settings.fakerapi_seed}") cliente = { "cpf": cpf_norm, "nome": "Cliente Faker", "score": int(300 + (entropy % 550)), "limite_credito": float(30000 + (entropy % 150000)), "possui_restricao": (entropy % 7 == 0), } limite = _parse_float(cliente.get("limite_credito", 0), 0.0) restricao = bool(cliente.get("possui_restricao", False)) aprovado = (not restricao) and (valor_veiculo <= limite) return { "aprovado": aprovado, "cpf": cpf_norm, "nome": cliente.get("nome"), "score": cliente.get("score"), "limite_credito": limite, "possui_restricao": restricao, "valor_veiculo": valor_veiculo, } async def avaliar_veiculo_troca(modelo: str, ano: int, km: int) -> Dict[str, Any]: ano_atual = datetime.now().year idade = max(0, ano_atual - ano) base = 80000.0 valor = base * (0.85 ** idade) - (km * 0.03) valor = max(5000.0, valor) return { "modelo": modelo, "ano": ano, "km": km, "valor_estimado_troca": round(valor, 2), } async def agendar_revisao(placa: str, data_hora: str) -> Dict[str, Any]: raise HTTPException( status_code=503, detail="FakerAPI nao suporta escrita/persistencia. Endpoint disponivel apenas para leitura de dados ficticios.", ) async def cancelar_pedido(numero_pedido: str, motivo: str) -> Dict[str, Any]: raise HTTPException( status_code=503, detail="FakerAPI nao suporta cancelamento persistente de pedidos. Endpoint indisponivel neste modo.", )