|
import React, { useState, useEffect, useMemo, useCallback } from 'react'; |
|
import { Play, CheckCircle, AlertTriangle, Calculator, DollarSign, TrendingUp, Database, Target, Award } from 'lucide-react'; |
|
import { LotomaniaAlgorithm } from '../utils/lotomaniaAlgorithm'; |
|
import { useLotomaniaAPI } from '../hooks/useLotomaniaAPI'; |
|
import { LotomaniaGame, LotomaniaResult } from '../types'; |
|
|
|
interface GameAnalysisResult { |
|
game: LotomaniaGame; |
|
numbers: number[]; |
|
matches: number; |
|
points: number; |
|
isWinning: boolean; |
|
prizeValue: number; |
|
prizeDescription: string; |
|
} |
|
|
|
interface FinancialSummary { |
|
totalCost: number; |
|
totalPrizes: number; |
|
netResult: number; |
|
profitMargin: number; |
|
winningGames: number; |
|
pointsDistribution: Record<number, number>; |
|
prizeDistribution: Record<number, { count: number; totalValue: number }>; |
|
} |
|
|
|
export const CompleteSystemAnalysis: React.FC = () => { |
|
const [algorithm] = useState(() => new LotomaniaAlgorithm()); |
|
const [allGames, setAllGames] = useState<LotomaniaGame[]>([]); |
|
const [isAnalyzing, setIsAnalyzing] = useState(false); |
|
const [analysisResults, setAnalysisResults] = useState<GameAnalysisResult[]>([]); |
|
const [financialSummary, setFinancialSummary] = useState<FinancialSummary | null>(null); |
|
const [selectedConcurso, setSelectedConcurso] = useState<number | ''>(''); |
|
|
|
const { latestResult, fetchLatestResult, analyzeGameResult } = useLotomaniaAPI(); |
|
|
|
|
|
useEffect(() => { |
|
console.log('🚀 Iniciando geração completa de jogos...'); |
|
const startTime = performance.now(); |
|
|
|
const games = algorithm.generateAllGames(); |
|
const endTime = performance.now(); |
|
|
|
console.log(`✅ Jogos gerados em ${(endTime - startTime).toFixed(2)}ms`); |
|
console.log(`📊 Total de jogos: ${games.length}`); |
|
|
|
const verticalGames = algorithm.getVerticalGames(); |
|
const horizontalGames = algorithm.getHorizontalGames(); |
|
|
|
console.log(`🔹 Jogos Verticais: ${verticalGames.length}`); |
|
console.log(`🔸 Jogos Horizontais: ${horizontalGames.length}`); |
|
|
|
setAllGames(games); |
|
}, [algorithm]); |
|
|
|
|
|
const gameStats = useMemo(() => { |
|
if (allGames.length === 0) return null; |
|
|
|
const verticalGames = allGames.filter(g => g.type === 'vertical'); |
|
const horizontalGames = allGames.filter(g => g.type === 'horizontal'); |
|
|
|
const stats = algorithm.getGameStatistics(); |
|
|
|
return { |
|
...stats, |
|
verticalCount: verticalGames.length, |
|
horizontalCount: horizontalGames.length, |
|
isCorrect: verticalGames.length === 252 && horizontalGames.length === 252, |
|
expectedTotal: 504, |
|
actualTotal: allGames.length |
|
}; |
|
}, [allGames, algorithm]); |
|
|
|
|
|
const performCompleteAnalysis = useCallback(async () => { |
|
if (!latestResult || allGames.length === 0) { |
|
console.error('❌ Dados insuficientes para análise'); |
|
return; |
|
} |
|
|
|
setIsAnalyzing(true); |
|
console.log('🔄 Iniciando análise completa de todos os jogos...'); |
|
console.log(`📊 Analisando ${allGames.length} jogos contra concurso ${latestResult.concurso}`); |
|
|
|
const startTime = performance.now(); |
|
const results: GameAnalysisResult[] = []; |
|
|
|
for (let i = 0; i < allGames.length; i++) { |
|
const game = allGames[i]; |
|
const gameNumbers = algorithm.getNumbersFromGame(game); |
|
const analysis = analyzeGameResult(gameNumbers, latestResult); |
|
|
|
|
|
let prizeValue = 0; |
|
let prizeDescription = 'Sem prêmio'; |
|
|
|
if (analysis.points >= 15 || analysis.points === 0) { |
|
const premio = latestResult.premiacoes?.find(p => p.acertos === analysis.points); |
|
if (premio) { |
|
prizeValue = premio.valorPremio; |
|
prizeDescription = premio.descricao; |
|
} |
|
} |
|
|
|
results.push({ |
|
game, |
|
numbers: gameNumbers, |
|
matches: analysis.matches, |
|
points: analysis.points, |
|
isWinning: analysis.isWinning, |
|
prizeValue, |
|
prizeDescription |
|
}); |
|
|
|
|
|
if ((i + 1) % 100 === 0) { |
|
console.log(`📈 Analisados ${i + 1}/${allGames.length} jogos...`); |
|
} |
|
} |
|
|
|
const endTime = performance.now(); |
|
console.log(`✅ Análise completa em ${(endTime - startTime).toFixed(2)}ms`); |
|
|
|
setAnalysisResults(results); |
|
|
|
|
|
const GAME_COST = 3.00; |
|
const totalCost = allGames.length * GAME_COST; |
|
const totalPrizes = results.reduce((sum, r) => sum + r.prizeValue, 0); |
|
const netResult = totalPrizes - totalCost; |
|
const profitMargin = totalCost > 0 ? (netResult / totalCost) * 100 : 0; |
|
const winningGames = results.filter(r => r.isWinning).length; |
|
|
|
|
|
const pointsDistribution: Record<number, number> = {}; |
|
const prizeDistribution: Record<number, { count: number; totalValue: number }> = {}; |
|
|
|
results.forEach(r => { |
|
pointsDistribution[r.points] = (pointsDistribution[r.points] || 0) + 1; |
|
|
|
if (r.isWinning) { |
|
if (!prizeDistribution[r.points]) { |
|
prizeDistribution[r.points] = { count: 0, totalValue: 0 }; |
|
} |
|
prizeDistribution[r.points].count++; |
|
prizeDistribution[r.points].totalValue += r.prizeValue; |
|
} |
|
}); |
|
|
|
const financial: FinancialSummary = { |
|
totalCost, |
|
totalPrizes, |
|
netResult, |
|
profitMargin, |
|
winningGames, |
|
pointsDistribution, |
|
prizeDistribution |
|
}; |
|
|
|
setFinancialSummary(financial); |
|
|
|
|
|
console.log('💰 ===== ANÁLISE FINANCEIRA COMPLETA ====='); |
|
console.log(`💸 Custo Total: R$ ${totalCost.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}`); |
|
console.log(`🏆 Prêmios Totais: R$ ${totalPrizes.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}`); |
|
console.log(`📊 Resultado Líquido: R$ ${netResult.toLocaleString('pt-BR', { minimumFractionDigits: 2 })}`); |
|
console.log(`📈 Margem: ${profitMargin.toFixed(2)}%`); |
|
console.log(`🎯 Jogos Premiados: ${winningGames}/${allGames.length} (${((winningGames/allGames.length)*100).toFixed(2)}%)`); |
|
|
|
setIsAnalyzing(false); |
|
}, [latestResult, allGames, algorithm, analyzeGameResult]); |
|
|
|
|
|
useEffect(() => { |
|
if (latestResult && allGames.length > 0 && analysisResults.length === 0) { |
|
performCompleteAnalysis(); |
|
} |
|
}, [latestResult, allGames, analysisResults.length, performCompleteAnalysis]); |
|
|
|
|
|
useEffect(() => { |
|
fetchLatestResult(); |
|
}, [fetchLatestResult]); |
|
|
|
return ( |
|
<div className="space-y-6"> |
|
{/* Header */} |
|
<div className="bg-gradient-to-r from-blue-600 to-purple-600 text-white p-6 rounded-lg"> |
|
<h2 className="text-2xl font-bold flex items-center gap-2"> |
|
<Database className="w-6 h-6" /> |
|
Análise Completa do Sistema Lotomania |
|
</h2> |
|
<p className="text-blue-100 mt-2"> |
|
Verificação completa da lógica, geração de jogos e análise financeira detalhada |
|
</p> |
|
</div> |
|
|
|
{/* Verificação do Algoritmo */} |
|
<div className="bg-white rounded-lg shadow-lg p-6"> |
|
<h3 className="text-xl font-semibold mb-4 flex items-center gap-2"> |
|
<Target className="w-5 h-5 text-blue-600" /> |
|
Verificação do Algoritmo |
|
</h3> |
|
|
|
{gameStats ? ( |
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4"> |
|
<div className={`p-4 rounded-lg border-l-4 ${ |
|
gameStats.isCorrect ? 'border-green-500 bg-green-50' : 'border-red-500 bg-red-50' |
|
}`}> |
|
<div className="flex items-center gap-2"> |
|
{gameStats.isCorrect ? ( |
|
<CheckCircle className="w-5 h-5 text-green-600" /> |
|
) : ( |
|
<AlertTriangle className="w-5 h-5 text-red-600" /> |
|
)} |
|
<span className="font-semibold">Status</span> |
|
</div> |
|
<p className={`text-sm ${gameStats.isCorrect ? 'text-green-700' : 'text-red-700'}`}> |
|
{gameStats.isCorrect ? 'Algoritmo Correto ✅' : 'Algoritmo com Problemas ❌'} |
|
</p> |
|
</div> |
|
|
|
<div className="p-4 rounded-lg border-l-4 border-blue-500 bg-blue-50"> |
|
<div className="flex items-center gap-2"> |
|
<Calculator className="w-5 h-5 text-blue-600" /> |
|
<span className="font-semibold">Total de Jogos</span> |
|
</div> |
|
<p className="text-2xl font-bold text-blue-800"> |
|
{gameStats.actualTotal} |
|
</p> |
|
<p className="text-sm text-blue-600"> |
|
Esperado: {gameStats.expectedTotal} |
|
</p> |
|
</div> |
|
|
|
<div className="p-4 rounded-lg border-l-4 border-purple-500 bg-purple-50"> |
|
<div className="flex items-center gap-2"> |
|
<span className="w-5 h-5 bg-purple-600 rounded"></span> |
|
<span className="font-semibold">Jogos Verticais</span> |
|
</div> |
|
<p className="text-2xl font-bold text-purple-800"> |
|
{gameStats.verticalCount} |
|
</p> |
|
<p className="text-sm text-purple-600"> |
|
Esperado: 252 |
|
</p> |
|
</div> |
|
|
|
<div className="p-4 rounded-lg border-l-4 border-orange-500 bg-orange-50"> |
|
<div className="flex items-center gap-2"> |
|
<span className="w-5 h-5 bg-orange-600 rounded"></span> |
|
<span className="font-semibold">Jogos Horizontais</span> |
|
</div> |
|
<p className="text-2xl font-bold text-orange-800"> |
|
{gameStats.horizontalCount} |
|
</p> |
|
<p className="text-sm text-orange-600"> |
|
Esperado: 252 |
|
</p> |
|
</div> |
|
</div> |
|
) : ( |
|
<div className="animate-pulse space-y-4"> |
|
<div className="h-4 bg-gray-200 rounded w-1/4"></div> |
|
<div className="h-20 bg-gray-200 rounded"></div> |
|
</div> |
|
)} |
|
</div> |
|
|
|
{/* Informações do Resultado da Lotomania */} |
|
{latestResult && ( |
|
<div className="bg-white rounded-lg shadow-lg p-6"> |
|
<h3 className="text-xl font-semibold mb-4 flex items-center gap-2"> |
|
<Award className="w-5 h-5 text-green-600" /> |
|
Resultado Oficial da Lotomania |
|
</h3> |
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6"> |
|
<div className="p-4 bg-green-50 rounded-lg"> |
|
<span className="text-sm text-green-600">Concurso</span> |
|
<p className="text-2xl font-bold text-green-800">{latestResult.concurso}</p> |
|
</div> |
|
|
|
<div className="p-4 bg-blue-50 rounded-lg"> |
|
<span className="text-sm text-blue-600">Data</span> |
|
<p className="text-lg font-semibold text-blue-800">{latestResult.data}</p> |
|
</div> |
|
|
|
<div className="p-4 bg-yellow-50 rounded-lg"> |
|
<span className="text-sm text-yellow-600">Valor Arrecadado</span> |
|
<p className="text-lg font-semibold text-yellow-800"> |
|
R$ {(latestResult.valorArrecadado || 0).toLocaleString('pt-BR')} |
|
</p> |
|
</div> |
|
|
|
<div className={`p-4 rounded-lg ${latestResult.acumulado ? 'bg-red-50' : 'bg-green-50'}`}> |
|
<span className={`text-sm ${latestResult.acumulado ? 'text-red-600' : 'text-green-600'}`}> |
|
Status |
|
</span> |
|
<p className={`text-lg font-semibold ${latestResult.acumulado ? 'text-red-800' : 'text-green-800'}`}> |
|
{latestResult.acumulado ? 'Acumulou' : 'Teve Ganhador'} |
|
</p> |
|
</div> |
|
</div> |
|
|
|
{/* Números Sorteados */} |
|
<div className="mb-4"> |
|
<h4 className="font-semibold mb-2">Números Sorteados:</h4> |
|
<div className="grid grid-cols-10 gap-2"> |
|
{latestResult.numeros.map((numero, index) => ( |
|
<div |
|
key={index} |
|
className="bg-blue-600 text-white rounded-lg p-2 text-center font-bold" |
|
> |
|
{numero === 0 ? '00' : numero.toString().padStart(2, '0')} |
|
</div> |
|
))} |
|
</div> |
|
</div> |
|
</div> |
|
)} |
|
|
|
{/* Controles de Análise */} |
|
<div className="bg-white rounded-lg shadow-lg p-6"> |
|
<h3 className="text-xl font-semibold mb-4 flex items-center gap-2"> |
|
<Play className="w-5 h-5 text-blue-600" /> |
|
Análise Completa |
|
</h3> |
|
|
|
<div className="flex flex-col md:flex-row gap-4 items-center"> |
|
<button |
|
onClick={performCompleteAnalysis} |
|
disabled={isAnalyzing || !latestResult || allGames.length === 0} |
|
className={`flex items-center gap-2 px-6 py-3 rounded-lg font-semibold transition-all ${ |
|
isAnalyzing || !latestResult || allGames.length === 0 |
|
? 'bg-gray-400 cursor-not-allowed' |
|
: 'bg-blue-600 hover:bg-blue-700 text-white shadow-lg hover:shadow-xl' |
|
}`} |
|
> |
|
{isAnalyzing ? ( |
|
<> |
|
<div className="animate-spin rounded-full h-5 w-5 border-b-2 border-white"></div> |
|
Analisando todos os {allGames.length} jogos... |
|
</> |
|
) : ( |
|
<> |
|
<Play className="w-5 h-5" /> |
|
Analisar Todos os {allGames.length} Jogos |
|
</> |
|
)} |
|
</button> |
|
|
|
{analysisResults.length > 0 && ( |
|
<div className="text-sm text-gray-600"> |
|
✅ Análise completa realizada com {analysisResults.length} jogos |
|
</div> |
|
)} |
|
</div> |
|
</div> |
|
|
|
{} |
|
{financialSummary && ( |
|
<div className="bg-white rounded-lg shadow-lg p-6"> |
|
<h3 className="text-xl font-semibold mb-4 flex items-center gap-2"> |
|
<DollarSign className="w-5 h-5 text-green-600" /> |
|
Análise Financeira Completa |
|
</h3> |
|
|
|
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4 mb-6"> |
|
<div className="p-4 bg-red-50 rounded-lg border-l-4 border-red-500"> |
|
<span className="text-sm text-red-600">Custo Total</span> |
|
<p className="text-2xl font-bold text-red-800"> |
|
R$ {financialSummary.totalCost.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} |
|
</p> |
|
<p className="text-sm text-red-600"> |
|
{allGames.length} jogos × R$ 3,00 |
|
</p> |
|
</div> |
|
|
|
<div className="p-4 bg-green-50 rounded-lg border-l-4 border-green-500"> |
|
<span className="text-sm text-green-600">Prêmios Totais</span> |
|
<p className="text-2xl font-bold text-green-800"> |
|
R$ {financialSummary.totalPrizes.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} |
|
</p> |
|
<p className="text-sm text-green-600"> |
|
{financialSummary.winningGames} jogos premiados |
|
</p> |
|
</div> |
|
|
|
<div className={`p-4 rounded-lg border-l-4 ${ |
|
financialSummary.netResult >= 0 ? 'border-blue-500 bg-blue-50' : 'border-orange-500 bg-orange-50' |
|
}`}> |
|
<span className={`text-sm ${ |
|
financialSummary.netResult >= 0 ? 'text-blue-600' : 'text-orange-600' |
|
}`}> |
|
Resultado Líquido |
|
</span> |
|
<p className={`text-2xl font-bold ${ |
|
financialSummary.netResult >= 0 ? 'text-blue-800' : 'text-orange-800' |
|
}`}> |
|
{financialSummary.netResult >= 0 ? '+' : ''}R$ {financialSummary.netResult.toLocaleString('pt-BR', { minimumFractionDigits: 2 })} |
|
</p> |
|
<p className={`text-sm ${ |
|
financialSummary.netResult >= 0 ? 'text-blue-600' : 'text-orange-600' |
|
}`}> |
|
{financialSummary.profitMargin >= 0 ? 'Lucro' : 'Prejuízo'}: {Math.abs(financialSummary.profitMargin).toFixed(2)}% |
|
</p> |
|
</div> |
|
|
|
<div className="p-4 bg-purple-50 rounded-lg border-l-4 border-purple-500"> |
|
<span className="text-sm text-purple-600">Taxa de Acerto</span> |
|
<p className="text-2xl font-bold text-purple-800"> |
|
{((financialSummary.winningGames / allGames.length) * 100).toFixed(2)}% |
|
</p> |
|
<p className="text-sm text-purple-600"> |
|
{financialSummary.winningGames} de {allGames.length} jogos |
|
</p> |
|
</div> |
|
</div> |
|
|
|
{/* Distribuição de Pontos */} |
|
<div className="mt-6"> |
|
<h4 className="font-semibold mb-3">Distribuição de Pontos:</h4> |
|
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-8 gap-3"> |
|
{Object.entries(financialSummary.pointsDistribution) |
|
.sort(([a], [b]) => parseInt(b) - parseInt(a)) |
|
.map(([points, count]) => { |
|
const prize = financialSummary.prizeDistribution[parseInt(points)]; |
|
const isWinning = prize && prize.count > 0; |
|
|
|
return ( |
|
<div |
|
key={points} |
|
className={`p-3 rounded-lg text-center ${ |
|
isWinning ? 'bg-green-100 border border-green-300' : 'bg-gray-100' |
|
}`} |
|
> |
|
<div className={`font-bold text-lg ${ |
|
isWinning ? 'text-green-800' : 'text-gray-700' |
|
}`}> |
|
{points} pts |
|
</div> |
|
<div className={`text-sm ${ |
|
isWinning ? 'text-green-600' : 'text-gray-600' |
|
}`}> |
|
{count} jogos |
|
</div> |
|
{isWinning && ( |
|
<div className="text-xs text-green-600 font-semibold"> |
|
R$ {prize.totalValue.toLocaleString('pt-BR', { maximumFractionDigits: 0 })} |
|
</div> |
|
)} |
|
</div> |
|
); |
|
})} |
|
</div> |
|
</div> |
|
</div> |
|
)} |
|
|
|
{} |
|
<div className="bg-gradient-to-r from-green-500 to-blue-500 text-white p-6 rounded-lg"> |
|
<h3 className="text-xl font-semibold mb-3 flex items-center gap-2"> |
|
<CheckCircle className="w-6 h-6" /> |
|
Confirmação do Sistema |
|
</h3> |
|
|
|
<div className="space-y-2"> |
|
<p className="flex items-center gap-2"> |
|
<span className="w-2 h-2 bg-white rounded-full"></span> |
|
✅ <strong>Algoritmo Verified:</strong> Gera exatamente {gameStats?.actualTotal} jogos conforme especificado |
|
</p> |
|
<p className="flex items-center gap-2"> |
|
<span className="w-2 h-2 bg-white rounded-full"></span> |
|
✅ <strong>Jogos Verticais:</strong> {gameStats?.verticalCount} jogos (colunas marcadas) |
|
</p> |
|
<p className="flex items-center gap-2"> |
|
<span className="w-2 h-2 bg-white rounded-full"></span> |
|
✅ <strong>Jogos Horizontais:</strong> {gameStats?.horizontalCount} jogos (linhas marcadas) |
|
</p> |
|
<p className="flex items-center gap-2"> |
|
<span className="w-2 h-2 bg-white rounded-full"></span> |
|
✅ <strong>Comparação Real:</strong> Cada jogo é comparado com resultado oficial da Caixa |
|
</p> |
|
<p className="flex items-center gap-2"> |
|
<span className="w-2 h-2 bg-white rounded-full"></span> |
|
✅ <strong>Análise Financeira:</strong> Custo total vs. prêmios reais obtidos |
|
</p> |
|
<p className="flex items-center gap-2"> |
|
<span className="w-2 h-2 bg-white rounded-full"></span> |
|
✅ <strong>Dados Oficiais:</strong> API da Caixa Econômica Federal integrada |
|
</p> |
|
</div> |
|
</div> |
|
</div> |
|
); |
|
}; |
|
|
|
export default CompleteSystemAnalysis; |
|
|