<?php

declare(strict_types=1);

namespace App\Framework\Performance;

use App\Framework\Performance\Contracts\PerformanceCollectorInterface;
use App\Framework\Performance\Contracts\PerformanceReporterInterface;
use App\Framework\Performance\Contracts\PerformanceServiceInterface;

final readonly class PerformanceService implements PerformanceServiceInterface
{
    public function __construct(
        private PerformanceCollectorInterface $collector,
        private PerformanceConfig             $config,
        private ?PerformanceReporterInterface $reporter = null
    ) {
    }

    /**
     * Quick method to measure a function's execution
     */
    public function measure(string $key, callable $callback, PerformanceCategory $category = PerformanceCategory::CUSTOM, array $context = []): mixed
    {
        return $this->collector->measure($key, $category, $callback, $context);
    }

    /**
     * Start timing an operation
     */
    public function startTiming(string $key, PerformanceCategory $category = PerformanceCategory::CUSTOM, array $context = []): void
    {
        $this->collector->startTiming($key, $category, $context);
    }

    /**
     * End timing an operation
     */
    public function endTiming(string $key): void
    {
        $this->collector->endTiming($key);
    }

    /**
     * Record a metric value
     */
    public function recordMetric(string $key, float $value, PerformanceCategory $category = PerformanceCategory::CUSTOM, array $context = []): void
    {
        $this->collector->recordMetric($key, $category, $value, $context);
    }

    /**
     * Increment a counter
     */
    public function increment(string $key, int $amount = 1, PerformanceCategory $category = PerformanceCategory::CUSTOM, array $context = []): void
    {
        $this->collector->increment($key, $category, $amount, $context);
    }

    /**
     * Get all metrics for a category
     */
    public function getMetrics(?PerformanceCategory $category = null): array
    {
        return $this->collector->getMetrics($category);
    }

    /**
     * Get a specific metric
     */
    public function getMetric(string $key): ?PerformanceMetric
    {
        return $this->collector->getMetric($key);
    }

    /**
     * Generate a performance report
     */
    public function generateReport(string $format = 'array'): string|array
    {
        if ($this->reporter === null) {
            return $format === 'array' ? [] : '';
        }

        return $this->reporter->generateReport($format);
    }

    /**
     * Get current request statistics
     */
    public function getRequestStats(): array
    {
        return [
            'time_ms' => $this->collector->getTotalRequestTime(),
            'memory_bytes' => $this->collector->getTotalRequestMemory(),
            'peak_memory_bytes' => $this->collector->getPeakMemory(),
            'metrics_count' => count($this->collector->getMetrics()),
        ];
    }

    /**
     * Reset all metrics
     */
    public function reset(): void
    {
        $this->collector->reset();
    }

    /**
     * Check if performance tracking is enabled
     */
    public function isEnabled(): bool
    {
        return $this->collector->isEnabled();
    }

    /**
     * Enable or disable performance tracking
     */
    public function setEnabled(bool $enabled): void
    {
        $this->collector->setEnabled($enabled);
    }

    /**
     * Get configuration
     */
    public function getConfig(): PerformanceConfig
    {
        return $this->config;
    }

    /**
     * Convenience method for database query timing
     */
    public function measureDatabaseQuery(string $queryType, callable $callback, array $context = []): mixed
    {
        return $this->measure("db_query_{$queryType}", $callback, PerformanceCategory::DATABASE, $context);
    }

    /**
     * Convenience method for cache operation timing
     */
    public function measureCacheOperation(string $operation, callable $callback, array $context = []): mixed
    {
        return $this->measure("cache_{$operation}", $callback, PerformanceCategory::CACHE, $context);
    }

    /**
     * Convenience method for view rendering timing
     */
    public function measureViewRender(string $view, callable $callback, array $context = []): mixed
    {
        return $this->measure("view_render_{$view}", $callback, PerformanceCategory::VIEW, $context);
    }

    /**
     * Get performance summary as array
     */
    public function getSummary(): array
    {
        $report = $this->generateReport('array');

        return $report['summary'] ?? [];
    }

    /**
     * Get slowest operations
     */
    public function getSlowestOperations(int $limit = 10): array
    {
        $report = $this->generateReport('array');
        $metrics = $report['metrics'] ?? [];

        $metricsWithTime = array_filter($metrics, function ($metric) {
            return $metric['measurements']['total_duration_ms'] > 0;
        });

        usort($metricsWithTime, function ($a, $b) {
            return $b['measurements']['total_duration_ms'] <=> $a['measurements']['total_duration_ms'];
        });

        return array_slice($metricsWithTime, 0, $limit);
    }

    /**
     * Export metrics to array for external processing
     */
    public function exportMetrics(): array
    {
        $metrics = [];
        foreach ($this->collector->getMetrics() as $metric) {
            $metrics[] = $metric->toArray();
        }

        return $metrics;
    }
}
