"""Seed MIDAS database with demo data""" import asyncio import random from datetime import datetime, timedelta from app.database import engine, async_session, Base from app.models.user import User from app.models.bet import Bet from app.models.bankroll import Bankroll from app.models.alert import Alert from app.models.achievement import Achievement, UserAchievement from app.models.lesson import Lesson, UserLesson from app.utils.auth import hash_password ACHIEVEMENTS = [ {"name": "Primeiro Passo", "description": "Registrou sua primeira aposta", "icon": "👣", "category": "beginner", "requirement_type": "bets", "requirement_value": 1, "points": 10}, {"name": "Estudante", "description": "Completou sua primeira lição", "icon": "📚", "category": "education", "requirement_type": "lessons", "requirement_value": 1, "points": 15}, {"name": "Disciplinado", "description": "5 dias sem aposta impulsiva", "icon": "🧘", "category": "discipline", "requirement_type": "streak", "requirement_value": 5, "points": 25}, {"name": "Analista", "description": "Registrou 10 apostas", "icon": "📊", "category": "beginner", "requirement_type": "bets", "requirement_value": 10, "points": 20}, {"name": "Scholar", "description": "Completou 5 lições", "icon": "🎓", "category": "education", "requirement_type": "lessons", "requirement_value": 5, "points": 30}, {"name": "Consistente", "description": "30 dias usando o MIDAS", "icon": "📅", "category": "discipline", "requirement_type": "days", "requirement_value": 30, "points": 50}, {"name": "Mestre da Banca", "description": "Não estourou o limite por 30 dias", "icon": "💰", "category": "bankroll", "requirement_type": "bankroll_days", "requirement_value": 30, "points": 40}, {"name": "Zen", "description": "10 dias seguidos sem aposta impulsiva", "icon": "☯️", "category": "discipline", "requirement_type": "streak", "requirement_value": 10, "points": 35}, {"name": "Veterano", "description": "50 apostas registradas", "icon": "⭐", "category": "beginner", "requirement_type": "bets", "requirement_value": 50, "points": 30}, {"name": "Iluminado", "description": "Completou todas as lições", "icon": "💡", "category": "education", "requirement_type": "lessons", "requirement_value": 8, "points": 50}, ] LESSONS = [ {"title": "O que é Valor Esperado", "content": "Valor Esperado (EV) é o conceito mais importante em apostas. É a média de quanto você ganharia ou perderia por aposta se repetisse a mesma aposta infinitas vezes.\n\n**Fórmula:** EV = (Probabilidade de ganhar × Lucro) - (Probabilidade de perder × Valor apostado)\n\n**Exemplo:** Aposta de R$100 em odds 2.0 com 50% de chance real:\nEV = (0.50 × R$100) - (0.50 × R$100) = R$0\n\nSe a casa oferece odds 1.90 para o mesmo evento:\nEV = (0.50 × R$90) - (0.50 × R$100) = -R$5\n\nIsso significa que, em média, você perde R$5 por aposta. Com o tempo, isso se acumula.", "category": "fundamentos", "difficulty": "iniciante", "duration_min": 8, "order_num": 1}, {"title": "Como a Casa Sempre Ganha", "content": "A margem da casa (vig/juice) é como as casas de apostas garantem lucro.\n\n**Como funciona:** Em um cara ou coroa justo, as odds deveriam ser 2.0 para ambos os lados. Mas a casa oferece 1.90 para cada lado.\n\nSe 100 pessoas apostam R$100 em cara e 100 em coroa:\n- Casa recebe: R$20.000\n- Casa paga: 100 × R$190 = R$19.000\n- Lucro da casa: R$1.000 (5%)\n\n**A margem média das casas:**\n- Futebol: 5-8%\n- Tênis: 6-8%\n- Basquete: 4-6%\n\nNão importa quem ganha — a casa SEMPRE lucra no longo prazo.", "category": "fundamentos", "difficulty": "iniciante", "duration_min": 6, "order_num": 2}, {"title": "Gestão de Banca 101", "content": "Gestão de banca é a skill #1 que separa apostadores disciplinados de apostadores que quebram.\n\n**Regras fundamentais:**\n1. **Defina um orçamento mensal** que NÃO comprometa suas contas\n2. **Máximo 2-5% da banca por aposta** — NUNCA mais que 10%\n3. **Nunca aposte dinheiro do aluguel/comida/contas**\n4. **Separe o dinheiro de apostas** do dinheiro do dia-a-dia\n\n**Exemplo prático:**\n- Banca mensal: R$500\n- Max por aposta (5%): R$25\n- Se perder 50% da banca: PARE e reavalie\n\n**A regra de ouro:** Se você não pode perder esse dinheiro sem afetar sua vida, NÃO aposte.", "category": "gestão", "difficulty": "iniciante", "duration_min": 7, "order_num": 3}, {"title": "Vieses Cognitivos nas Apostas", "content": "Seu cérebro é seu pior inimigo nas apostas. Conheça os vieses:\n\n**1. Falácia do Jogador:** 'Saiu vermelho 5 vezes, agora vai sair preto!' — ERRADO. Cada evento é independente.\n\n**2. Viés de Confirmação:** Você lembra das apostas que ganhou e esquece as que perdeu.\n\n**3. Excesso de Confiança:** Após uma sequência de vitórias, você acha que 'entende' do assunto e aumenta os valores.\n\n**4. Aversão à Perda:** A dor de perder R$100 é 2x mais intensa que a alegria de ganhar R$100.\n\n**5. Efeito Ancoragem:** Se a odd era 3.0 e caiu para 2.5, parece 'ruim' — mas pode ser o valor justo.\n\n**Como se proteger:** Tenha regras fixas ANTES de apostar. Emoção é o inimigo.", "category": "psicologia", "difficulty": "intermediário", "duration_min": 10, "order_num": 4}, {"title": "Quando Parar", "content": "Saber quando parar é mais importante que saber quando apostar.\n\n**Sinais de que você deve parar AGORA:**\n🔴 Apostando para recuperar perdas\n🔴 Aumentando valores depois de perder\n🔴 Apostando após beber ou com raiva\n🔴 Escondendo apostas de família/amigos\n🔴 Pegando dinheiro emprestado para apostar\n🔴 Pensando em apostas o tempo todo\n\n**Regras práticas:**\n- Definiu o limite diário? Atingiu = PAROU\n- Perdeu 3 seguidas? PAROU por hoje\n- Está emocional? NÃO aposte\n- São 23h+? Melhor dormir\n\n**Lembre-se:** As casas de apostas estão abertas 24/7. Sempre haverá 'a próxima oportunidade'. Não precisa ser AGORA.", "category": "disciplina", "difficulty": "iniciante", "duration_min": 6, "order_num": 5}, {"title": "Recuperação é Armadilha", "content": "O 'chasing losses' (tentar recuperar perdas) é o comportamento mais destrutivo nas apostas.\n\n**O ciclo da destruição:**\n1. Perde R$50\n2. Aposta R$100 para recuperar\n3. Perde de novo → agora está -R$150\n4. Aposta R$200 'para empatar'\n5. Perde → -R$350 em um dia\n\n**Por que seu cérebro faz isso:**\n- Aversão à perda: quer 'zerar' o dia\n- Ilusão de controle: 'agora eu sei'\n- Dopamina: a possibilidade de recuperar é excitante\n\n**A verdade cruel:** Cada aposta é INDEPENDENTE. Suas perdas passadas não aumentam suas chances futuras.\n\n**Solução:** Aceite a perda. Feche o app. Vá fazer outra coisa. R$50 perdidos são R$50. Não transforme em R$350.", "category": "psicologia", "difficulty": "intermediário", "duration_min": 8, "order_num": 6}, {"title": "Bankroll Management Avançado", "content": "Estratégias avançadas de gestão de banca:\n\n**1. Método de Unidades:**\n- 1 unidade = 1-2% da banca\n- Aposta normal: 1 unidade\n- Aposta com edge claro: 2 unidades\n- NUNCA mais que 3 unidades\n\n**2. Critério de Kelly:**\nKelly % = (bp - q) / b\n- b = odds decimais - 1\n- p = probabilidade real de ganhar\n- q = 1 - p\n\nExemplo: Odds 2.5, chance real 45%\nKelly = (1.5 × 0.45 - 0.55) / 1.5 = 8.3%\nUse 1/4 Kelly na prática = ~2%\n\n**3. Flat Betting:**\nAposta o mesmo valor SEMPRE. Simples e eficaz.\n\n**4. Regra do Drawdown:**\n- Perdeu 20% da banca? Reduza unidade pela metade\n- Perdeu 50%? PARE e reavalie", "category": "gestão", "difficulty": "avançado", "duration_min": 12, "order_num": 7}, {"title": "Apostas Responsáveis", "content": "Apostar pode ser entretenimento — mas precisa ser com RESPONSABILIDADE.\n\n**Princípios do MIDAS:**\n✅ Aposte apenas dinheiro que pode perder\n✅ Defina limites ANTES de começar\n✅ Registre TODAS as apostas (é pra isso que o MIDAS existe)\n✅ Analise seus padrões regularmente\n✅ Faça pausas regulares\n✅ Converse abertamente sobre apostas\n\n**Recursos de ajuda:**\n📞 CVV: 188 (24h)\n📱 Jogadores Anônimos: www.jogadoresanonimos.org.br\n📋 Teste SOGS: avalie se suas apostas são problemáticas\n\n**O MIDAS existe para te ajudar a ter CONSCIÊNCIA.** Não somos uma plataforma de apostas. Somos sua ferramenta de autoconhecimento financeiro.\n\n**Se as apostas estão causando sofrimento, procure ajuda profissional. Não há vergonha nisso.**", "category": "responsabilidade", "difficulty": "iniciante", "duration_min": 5, "order_num": 8}, ] DEMO_BETS = [ {"sport": "futebol", "event_name": "Flamengo vs Palmeiras", "platform": "Bet365", "amount": 25, "odds": 2.10, "result": "win", "emotion": "😎"}, {"sport": "futebol", "event_name": "Real Madrid vs Barcelona", "platform": "Betano", "amount": 30, "odds": 1.85, "result": "win", "emotion": "😎"}, {"sport": "futebol", "event_name": "Liverpool vs Man City", "platform": "Bet365", "amount": 20, "odds": 3.20, "result": "loss", "emotion": "😰"}, {"sport": "UFC", "event_name": "UFC 310: Pantoja vs Asakura", "platform": "Betano", "amount": 15, "odds": 1.65, "result": "win", "emotion": "🤑"}, {"sport": "basquete", "event_name": "Lakers vs Celtics", "platform": "Bet365", "amount": 25, "odds": 2.40, "result": "loss", "emotion": "😤"}, {"sport": "futebol", "event_name": "Corinthians vs São Paulo", "platform": "Betano", "amount": 20, "odds": 2.00, "result": "win", "emotion": "😎"}, {"sport": "UFC", "event_name": "UFC 311: Makhachev vs Tsarukyan", "platform": "Bet365", "amount": 30, "odds": 1.45, "result": "win", "emotion": "😎"}, {"sport": "futebol", "event_name": "Argentina vs Brasil", "platform": "Betano", "amount": 50, "odds": 2.80, "result": "loss", "emotion": "😤"}, {"sport": "basquete", "event_name": "Warriors vs Bucks", "platform": "Bet365", "amount": 15, "odds": 1.90, "result": "win", "emotion": "😎"}, {"sport": "futebol", "event_name": "PSG vs Bayern", "platform": "Bet365", "amount": 20, "odds": 2.50, "result": "loss", "emotion": "😰"}, {"sport": "futebol", "event_name": "Botafogo vs Fluminense", "platform": "Betano", "amount": 15, "odds": 1.75, "result": "win", "emotion": "🤑"}, {"sport": "UFC", "event_name": "UFC Fight Night: Moreno vs Royval", "platform": "Bet365", "amount": 20, "odds": 2.20, "result": "loss", "emotion": "😰"}, {"sport": "basquete", "event_name": "Nets vs Knicks", "platform": "Betano", "amount": 25, "odds": 1.95, "result": "win", "emotion": "😎"}, {"sport": "futebol", "event_name": "Inter vs Grêmio", "platform": "Bet365", "amount": 20, "odds": 2.05, "result": "win", "emotion": "😎"}, {"sport": "futebol", "event_name": "Chelsea vs Arsenal", "platform": "Betano", "amount": 35, "odds": 3.00, "result": "loss", "emotion": "😤"}, {"sport": "basquete", "event_name": "Heat vs 76ers", "platform": "Bet365", "amount": 20, "odds": 2.15, "result": "pending", "emotion": "😎"}, {"sport": "UFC", "event_name": "UFC 312: Du Plessis vs Strickland", "platform": "Betano", "amount": 25, "odds": 1.80, "result": "pending", "emotion": "🤑"}, {"sport": "futebol", "event_name": "Atlético MG vs Cruzeiro", "platform": "Bet365", "amount": 15, "odds": 2.30, "result": "win", "emotion": "😎"}, {"sport": "futebol", "event_name": "Juventus vs Milan", "platform": "Betano", "amount": 20, "odds": 2.60, "result": "loss", "emotion": "😰"}, {"sport": "basquete", "event_name": "Suns vs Nuggets", "platform": "Bet365", "amount": 30, "odds": 2.00, "result": "pending", "emotion": "😎"}, ] async def seed(): async with engine.begin() as conn: await conn.run_sync(Base.metadata.drop_all) await conn.run_sync(Base.metadata.create_all) async with async_session() as db: # Create demo user user = User( email="demo@midas.com", password_hash=hash_password("Midas@2026"), name="Demo User", plan="premium", streak_days=7, total_points=185, risk_level="yellow" ) db.add(user) await db.flush() # Bankroll bankroll = Bankroll( user_id=user.id, monthly_budget=500, weekly_limit=150, daily_limit=50, bet_max_pct=5, month_spent=245, week_spent=85, day_spent=30 ) db.add(bankroll) # Achievements achievement_objs = [] for a in ACHIEVEMENTS: obj = Achievement(**a) db.add(obj) achievement_objs.append(obj) await db.flush() # Unlock first 5 achievements for demo user for a in achievement_objs[:5]: ua = UserAchievement(user_id=user.id, achievement_id=a.id) db.add(ua) # Lessons lesson_objs = [] for l in LESSONS: obj = Lesson(**l) db.add(obj) lesson_objs.append(obj) await db.flush() # Complete first 3 lessons for demo for l in lesson_objs[:3]: ul = UserLesson(user_id=user.id, lesson_id=l.id) db.add(ul) # Bets (spread over last 30 days) now = datetime.utcnow() for i, b in enumerate(DEMO_BETS): days_ago = 30 - (i * 1.5) created = now - timedelta(days=days_ago, hours=random.randint(8, 22)) profit = 0 if b["result"] == "win": profit = b["amount"] * (b["odds"] - 1) elif b["result"] == "loss": profit = -b["amount"] bet = Bet( user_id=user.id, sport=b["sport"], event_name=b["event_name"], platform=b["platform"], amount=b["amount"], odds=b["odds"], result=b["result"], profit=profit, emotion=b["emotion"], created_at=created ) db.add(bet) # Some alerts alerts = [ Alert(user_id=user.id, type="recovery", severity="red", message="Aposta de recuperação detectada após perda em Liverpool vs Man City"), Alert(user_id=user.id, type="limit", severity="yellow", message="Você já usou 49% do limite mensal"), Alert(user_id=user.id, type="streak", severity="green", message="Parabéns! 7 dias sem aposta impulsiva 🔥"), ] for a in alerts: db.add(a) await db.commit() print("✅ Seed data created successfully!") print(f" User: demo@midas.com / Midas@2026") print(f" {len(DEMO_BETS)} bets, {len(ACHIEVEMENTS)} achievements, {len(LESSONS)} lessons") if __name__ == "__main__": asyncio.run(seed())