from datetime import datetime import hashlib import re from typing import Any, Dict, List, Optional from fastapi import HTTPException from app.db.mock_database import SessionMockLocal from app.db.mock_models import Customer, Order, ReviewSchedule, Vehicle def normalize_cpf(value: str) -> str: """Normaliza CPF removendo qualquer caractere nao numerico.""" return re.sub(r"\D", "", value or "") def _parse_float(value: Any, default: float = 0.0) -> float: """Converte entradas numericas/textuais para float com fallback padrao.""" 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: """Gera inteiro deterministico a partir de um texto usando hash SHA-256.""" digest = hashlib.sha256(seed_text.encode("utf-8")).hexdigest() return int(digest[:16], 16) async def consultar_estoque( preco_max: Optional[float] = None, categoria: Optional[str] = None, ordenar_preco: Optional[str] = None, limite: Optional[int] = None, ) -> List[Dict[str, Any]]: """Consulta veiculos no estoque com filtros opcionais e ordenacao por preco.""" db = SessionMockLocal() try: query = db.query(Vehicle) if preco_max is not None: query = query.filter(Vehicle.preco <= preco_max) if categoria: query = query.filter(Vehicle.categoria == categoria.lower()) if ordenar_preco in ("asc", "desc"): query = query.order_by(Vehicle.preco.asc() if ordenar_preco == "asc" else Vehicle.preco.desc()) if limite is not None: try: limite = max(1, int(limite)) query = query.limit(limite) except (TypeError, ValueError): pass rows = query.all() return [ { "id": row.id, "modelo": row.modelo, "categoria": row.categoria, "preco": _parse_float(row.preco), } for row in rows ] finally: db.close() async def validar_cliente_venda(cpf: str, valor_veiculo: float) -> Dict[str, Any]: """Avalia aprovacao de compra com base em score, limite e restricao do cliente.""" cpf_norm = normalize_cpf(cpf) db = SessionMockLocal() try: cliente = db.query(Customer).filter(Customer.cpf == cpf_norm).first() if cliente: score = int(cliente.score) limite = _parse_float(cliente.limite_credito, 0.0) restricao = bool(cliente.possui_restricao) nome = cliente.nome else: entropy = _stable_int(cpf_norm) score = int(300 + (entropy % 550)) limite = float(30000 + (entropy % 150000)) restricao = entropy % 7 == 0 nome = "Cliente Simulado" aprovado = (not restricao) and (valor_veiculo <= limite) return { "aprovado": aprovado, "cpf": cpf_norm, "nome": nome, "score": score, "limite_credito": limite, "possui_restricao": restricao, "valor_veiculo": valor_veiculo, } finally: db.close() async def avaliar_veiculo_troca(modelo: str, ano: int, km: int) -> Dict[str, Any]: """Calcula valor estimado de troca usando depreciacao por ano e quilometragem.""" 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]: """Cria ou reaproveita agendamento de revisao a partir de placa e data/hora.""" try: dt = datetime.fromisoformat(data_hora.replace("Z", "+00:00")) except ValueError: raise HTTPException( status_code=400, detail="data_hora invalida. Use formato ISO 8601, por exemplo: 2026-03-10T09:00:00-03:00", ) entropy = hashlib.md5(f"{placa}:{data_hora}".encode("utf-8")).hexdigest()[:8].upper() protocolo = f"REV-{dt.strftime('%Y%m%d')}-{entropy}" db = SessionMockLocal() try: existente = db.query(ReviewSchedule).filter(ReviewSchedule.protocolo == protocolo).first() if existente: return { "protocolo": existente.protocolo, "placa": existente.placa, "data_hora": existente.data_hora.isoformat(), "status": existente.status, } agendamento = ReviewSchedule( protocolo=protocolo, placa=placa.upper(), data_hora=dt, status="agendado", ) db.add(agendamento) db.commit() db.refresh(agendamento) return { "protocolo": agendamento.protocolo, "placa": agendamento.placa, "data_hora": agendamento.data_hora.isoformat(), "status": agendamento.status, } finally: db.close() async def cancelar_pedido(numero_pedido: str, motivo: str) -> Dict[str, Any]: """Cancela pedido existente e registra motivo e data de cancelamento.""" db = SessionMockLocal() try: pedido = db.query(Order).filter(Order.numero_pedido == numero_pedido).first() if not pedido: raise HTTPException(status_code=404, detail="Pedido nao encontrado na base ficticia.") if pedido.status.lower() == "cancelado": return { "numero_pedido": pedido.numero_pedido, "status": pedido.status, "motivo": pedido.motivo_cancelamento, "data_cancelamento": pedido.data_cancelamento.isoformat() if pedido.data_cancelamento else None, } pedido.status = "Cancelado" pedido.motivo_cancelamento = motivo pedido.data_cancelamento = datetime.utcnow() db.commit() db.refresh(pedido) return { "numero_pedido": pedido.numero_pedido, "status": pedido.status, "motivo": pedido.motivo_cancelamento, "data_cancelamento": pedido.data_cancelamento.isoformat() if pedido.data_cancelamento else None, } finally: db.close()