<?php

declare(strict_types=1);

namespace App\Framework\Database\Profiling;

use App\Framework\Database\Profiling\Reports\OptimizationReport;
use App\Framework\Database\Profiling\Reports\PerformanceReport;
use App\Framework\Database\Profiling\Reports\ProfilingReport;
use App\Framework\Database\Profiling\Reports\SlowQueryReport;

/**
 * Dashboard for database profiling visualization and reporting
 */
final class ProfilingDashboard
{
    private array $profilingConnections = [];

    public function __construct()
    {
    }

    /**
     * Register a profiling connection for monitoring
     */
    public function registerConnection(string $name, ProfilingConnection $connection): void
    {
        $this->profilingConnections[$name] = $connection;
    }

    /**
     * Get overview data for all registered connections
     */
    public function getOverview(): array
    {
        $overview = [
            'total_connections' => count($this->profilingConnections),
            'connections' => [],
            'global_stats' => [
                'total_queries' => 0,
                'total_slow_queries' => 0,
                'total_execution_time_ms' => 0,
                'average_execution_time_ms' => 0,
            ],
        ];

        $totalQueries = 0;
        $totalSlowQueries = 0;
        $totalExecutionTime = 0.0;

        foreach ($this->profilingConnections as $name => $connection) {
            $summary = $connection->getProfilingSummary();
            $stats = $connection->getProfilingStatistics();

            $connectionData = [
                'name' => $name,
                'enabled' => $connection->isProfilingEnabled(),
                'queries_count' => $summary->totalQueries,
                'slow_queries_count' => $summary->slowQueries,
                'slow_query_percentage' => $summary->getSlowQueryPercentage()->format(),
                'total_execution_time_ms' => $summary->totalExecutionTime?->toMilliseconds() ?? 0,
                'average_execution_time_ms' => $summary->averageExecutionTime?->toMilliseconds() ?? 0,
                'performance_assessment' => $summary->getPerformanceAssessment(),
                'profiler_active_profiles' => $stats['profiler_stats']['active_profiles'] ?? 0,
            ];

            $overview['connections'][$name] = $connectionData;

            $totalQueries += $summary->totalQueries;
            $totalSlowQueries += $summary->slowQueries;
            $totalExecutionTime += $summary->totalExecutionTime?->toMilliseconds() ?? 0;
        }

        $overview['global_stats'] = [
            'total_queries' => $totalQueries,
            'total_slow_queries' => $totalSlowQueries,
            'total_execution_time_ms' => $totalExecutionTime,
            'average_execution_time_ms' => $totalQueries > 0 ? $totalExecutionTime / $totalQueries : 0,
            'slow_query_percentage' => $totalQueries > 0 ? ($totalSlowQueries / $totalQueries) * 100 : 0,
        ];

        return $overview;
    }

    /**
     * Get detailed profiling report
     */
    public function getProfilingReport(?string $connectionName = null): ProfilingReport
    {
        if ($connectionName && ! isset($this->profilingConnections[$connectionName])) {
            throw new \InvalidArgumentException("Connection '$connectionName' not registered");
        }

        $connections = $connectionName
            ? [$connectionName => $this->profilingConnections[$connectionName]]
            : $this->profilingConnections;

        $allProfiles = [];
        $connectionStats = [];

        foreach ($connections as $name => $connection) {
            $profiler = $connection->getProfiler();
            $profiles = $profiler->getProfiles();
            $summary = $profiler->getSummary();

            $allProfiles = array_merge($allProfiles, $profiles);
            $connectionStats[$name] = [
                'summary' => $summary,
                'statistics' => $connection->getProfilingStatistics(),
                'profile_count' => count($profiles),
            ];
        }

        return new ProfilingReport($allProfiles, $connectionStats);
    }

    /**
     * Get slow query report
     */
    public function getSlowQueryReport(?string $connectionName = null): SlowQueryReport
    {
        if ($connectionName && ! isset($this->profilingConnections[$connectionName])) {
            throw new \InvalidArgumentException("Connection '$connectionName' not registered");
        }

        $connections = $connectionName
            ? [$connectionName => $this->profilingConnections[$connectionName]]
            : $this->profilingConnections;

        $slowQueries = [];

        foreach ($connections as $name => $connection) {
            $profiler = $connection->getProfiler();
            $connectionSlowQueries = $profiler->getSlowQueries();

            foreach ($connectionSlowQueries as $profile) {
                $slowQueries[] = [
                    'connection' => $name,
                    'profile' => $profile,
                ];
            }
        }

        // Sort by execution time (slowest first)
        usort($slowQueries, function ($a, $b) {
            return $b['profile']->executionTime->toMilliseconds() <=>
                   $a['profile']->executionTime->toMilliseconds();
        });

        return new SlowQueryReport($slowQueries);
    }

    /**
     * Get performance report
     */
    public function getPerformanceReport(?string $connectionName = null): PerformanceReport
    {
        if ($connectionName && ! isset($this->profilingConnections[$connectionName])) {
            throw new \InvalidArgumentException("Connection '$connectionName' not registered");
        }

        $connections = $connectionName
            ? [$connectionName => $this->profilingConnections[$connectionName]]
            : $this->profilingConnections;

        $performanceData = [];

        foreach ($connections as $name => $connection) {
            $summary = $connection->getProfilingSummary();

            $performanceData[$name] = [
                'total_queries' => $summary->totalQueries,
                'total_execution_time' => $summary->totalExecutionTime,
                'average_execution_time' => $summary->averageExecutionTime,
                'queries_per_second' => $summary->getQueriesPerSecond(),
                'memory_usage' => $summary->getTotalMemoryUsageBytes(),
                'query_distribution' => $summary->getQueryTypeDistributionWithPercentages(),
                'performance_assessment' => $summary->getPerformanceAssessment(),
                'slowest_query' => $summary->slowestQuery,
            ];
        }

        return new PerformanceReport($performanceData);
    }

    /**
     * Get optimization report with suggestions
     */
    public function getOptimizationReport(?string $connectionName = null): OptimizationReport
    {
        if ($connectionName && ! isset($this->profilingConnections[$connectionName])) {
            throw new \InvalidArgumentException("Connection '$connectionName' not registered");
        }

        $connections = $connectionName
            ? [$connectionName => $this->profilingConnections[$connectionName]]
            : $this->profilingConnections;

        $optimizationData = [];

        foreach ($connections as $name => $connection) {
            $summary = $connection->getProfilingSummary();
            $recommendations = $summary->getRecommendations();

            // Get profiler for more detailed analysis
            $profiler = $connection->getProfiler();
            $profiles = $profiler->getProfiles();

            // Calculate additional optimization metrics
            $slowQueryPatterns = [];
            $indexSuggestions = [];
            $performanceIssues = [];

            foreach ($profiles as $profile) {
                if ($profile->isSlow) {
                    $normalizedSql = $profile->getNormalizedSql();
                    $slowQueryPatterns[$normalizedSql] = ($slowQueryPatterns[$normalizedSql] ?? 0) + 1;
                }

                // Simple index suggestion based on WHERE clauses
                if (preg_match('/WHERE\s+(\w+)\s*(=|<|>)/', $profile->sql, $matches)) {
                    $column = $matches[1];
                    $indexSuggestions[] = "Consider index on: {$column}";
                }

                if ($profile->executionTime->toSeconds() > 5.0) {
                    $performanceIssues[] = [
                        'type' => 'very_slow_query',
                        'profile_id' => $profile->id,
                        'execution_time_ms' => $profile->executionTime->toMilliseconds(),
                        'sql' => substr($profile->sql, 0, 100) . '...',
                    ];
                }
            }

            // Remove duplicate index suggestions
            $indexSuggestions = array_unique($indexSuggestions);

            $optimizationData[$name] = [
                'recommendations' => $recommendations,
                'slow_query_patterns' => $slowQueryPatterns,
                'index_suggestions' => array_slice($indexSuggestions, 0, 10),
                'performance_issues' => $performanceIssues,
                'optimization_priority' => $this->calculateOptimizationPriority($summary),
                'total_issues' => count($performanceIssues),
            ];
        }

        return new OptimizationReport($optimizationData);
    }

    /**
     * Calculate optimization priority
     */
    private function calculateOptimizationPriority(ProfileSummary $summary): string
    {
        $slowQueryPercentage = $summary->getSlowQueryPercentage()->getValue();
        $avgTimeMs = $summary->averageExecutionTime?->toMilliseconds() ?? 0;

        if ($slowQueryPercentage > 30 || $avgTimeMs > 2000) {
            return 'critical';
        }

        if ($slowQueryPercentage > 15 || $avgTimeMs > 500) {
            return 'high';
        }

        if ($slowQueryPercentage > 5 || $avgTimeMs > 100) {
            return 'medium';
        }

        return 'low';
    }

    /**
     * Export dashboard data in different formats
     */
    public function export(string $format = 'json', ?string $connectionName = null): string
    {
        $data = [
            'overview' => $this->getOverview(),
            'profiling_report' => $this->getProfilingReport($connectionName)->toArray(),
            'slow_query_report' => $this->getSlowQueryReport($connectionName)->toArray(),
            'performance_report' => $this->getPerformanceReport($connectionName)->toArray(),
            'optimization_report' => $this->getOptimizationReport($connectionName)->toArray(),
            'export_timestamp' => date('c'),
        ];

        return match (strtolower($format)) {
            'json' => json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES),
            'html' => $this->exportAsHtml($data),
            default => throw new \InvalidArgumentException("Unsupported export format: $format")
        };
    }

    /**
     * Export dashboard as HTML
     */
    private function exportAsHtml(array $data): string
    {
        $html = '<html><head><title>Database Profiling Dashboard</title>';
        $html .= '<style>
            body { font-family: Arial, sans-serif; margin: 20px; }
            .section { margin-bottom: 30px; }
            .metric { display: inline-block; margin: 10px; padding: 10px; border: 1px solid #ccc; }
            .critical { background-color: #ffebee; }
            .warning { background-color: #fff3e0; }
            .success { background-color: #e8f5e8; }
            table { border-collapse: collapse; width: 100%; }
            th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }
            th { background-color: #f2f2f2; }
        </style></head><body>';

        $html .= '<h1>Database Profiling Dashboard</h1>';
        $html .= '<p>Generated: ' . date('Y-m-d H:i:s') . '</p>';

        // Overview section
        $html .= '<div class="section"><h2>Overview</h2>';
        $overview = $data['overview'];
        $html .= "<p>Total Connections: {$overview['total_connections']}</p>";
        $html .= "<p>Total Queries: {$overview['global_stats']['total_queries']}</p>";
        $html .= "<p>Slow Queries: {$overview['global_stats']['total_slow_queries']}</p>";
        $html .= '</div>';

        // Performance metrics
        $html .= '<div class="section"><h2>Connection Performance</h2>';
        $html .= '<table><tr><th>Connection</th><th>Queries</th><th>Slow Queries</th><th>Avg Time (ms)</th><th>Status</th></tr>';

        foreach ($overview['connections'] as $name => $conn) {
            $statusClass = match($conn['performance_assessment']) {
                'excellent', 'good' => 'success',
                'fair', 'moderate' => 'warning',
                default => 'critical'
            };

            $html .= "<tr class='{$statusClass}'>";
            $html .= "<td>{$name}</td>";
            $html .= "<td>{$conn['queries_count']}</td>";
            $html .= "<td>{$conn['slow_queries_count']} ({$conn['slow_query_percentage']})</td>";
            $html .= "<td>" . round($conn['average_execution_time_ms'], 2) . "</td>";
            $html .= "<td>" . ucfirst($conn['performance_assessment']) . "</td>";
            $html .= "</tr>";
        }

        $html .= '</table></div>';
        $html .= '</body></html>';

        return $html;
    }

    /**
     * Clear all profiling data for registered connections
     */
    public function clearAllProfilingData(): void
    {
        foreach ($this->profilingConnections as $connection) {
            $connection->clearProfilingData();
        }
    }

    /**
     * Get list of registered connection names
     */
    public function getRegisteredConnections(): array
    {
        return array_keys($this->profilingConnections);
    }
}
