<?php

declare(strict_types=1);

namespace App\Framework\Performance;

use App\Framework\Performance\ValueObjects\GcStatus;
use App\Framework\Performance\ValueObjects\GcResult;
use App\Framework\Core\ValueObjects\Timestamp;

/**
 * Garbage Collection Monitor
 *
 * Framework-consistent wrapper for PHP's garbage collection system.
 * Provides structured Value Objects instead of raw arrays and integrates
 * with the Performance monitoring ecosystem.
 *
 * Features:
 * - GC status tracking with Value Objects
 * - GC cycle execution and measurement
 * - Integration with MemoryMonitor for complete memory analysis
 * - Performance metrics for GC overhead
 *
 * Usage:
 * ```php
 * $gcMonitor = new GarbageCollectionMonitor();
 * $status = $gcMonitor->getStatus();
 * $result = $gcMonitor->forceCollection();
 * ```
 */
final readonly class GarbageCollectionMonitor
{
    /**
     * Get current garbage collection status
     */
    public function getStatus(): GcStatus
    {
        $status = gc_status();

        return new GcStatus(
            runs: $status['runs'] ?? 0,
            collected: $status['collected'] ?? 0,
            threshold: $status['threshold'] ?? 10001,
            roots: $status['roots'] ?? 0,
            running: $status['running'] ?? false
        );
    }

    /**
     * Get number of GC runs
     */
    public function getRuns(): int
    {
        return gc_status()['runs'] ?? 0;
    }

    /**
     * Get number of collected cycles
     */
    public function getCollected(): int
    {
        return gc_status()['collected'] ?? 0;
    }

    /**
     * Get current GC threshold
     */
    public function getThreshold(): int
    {
        return gc_status()['threshold'] ?? 10001;
    }

    /**
     * Check if GC is currently running
     */
    public function isRunning(): bool
    {
        return gc_status()['running'] ?? false;
    }

    /**
     * Force garbage collection cycle and measure performance
     *
     * Returns GcResult with:
     * - Collected cycles
     * - Execution duration
     * - Memory freed
     * - Before/after GC status
     */
    public function forceCollection(): GcResult
    {
        $memoryMonitor = new MemoryMonitor();
        $startTime = Timestamp::now();
        $memoryBefore = $memoryMonitor->getCurrentMemory();
        $statusBefore = $this->getStatus();

        // Force GC cycle
        $collected = gc_collect_cycles();

        $endTime = Timestamp::now();
        $memoryAfter = $memoryMonitor->getCurrentMemory();
        $statusAfter = $this->getStatus();

        $duration = $startTime->diff($endTime);
        $memoryFreed = $memoryBefore->subtract($memoryAfter);

        return new GcResult(
            collected: $collected,
            duration: $duration,
            memoryFreed: $memoryFreed,
            statusBefore: $statusBefore,
            statusAfter: $statusAfter,
            timestamp: $startTime
        );
    }

    /**
     * Enable garbage collection
     */
    public function enable(): void
    {
        gc_enable();
    }

    /**
     * Disable garbage collection
     */
    public function disable(): void
    {
        gc_disable();
    }

    /**
     * Check if garbage collection is enabled
     */
    public function isEnabled(): bool
    {
        return gc_enabled();
    }

    /**
     * Get GC efficiency metrics
     *
     * Returns array with:
     * - collection_rate: cycles collected per run
     * - threshold_ratio: roots to threshold ratio
     * - is_healthy: whether GC is performing well
     */
    public function getEfficiencyMetrics(): array
    {
        $status = $this->getStatus();

        $collectionRate = $status->runs > 0
            ? $status->collected / $status->runs
            : 0.0;

        $thresholdRatio = $status->threshold > 0
            ? $status->roots / $status->threshold
            : 0.0;

        // GC is healthy if:
        // - Collection rate is reasonable (collecting cycles)
        // - Threshold ratio is below 90% (not constantly hitting threshold)
        $isHealthy = $collectionRate > 0 && $thresholdRatio < 0.9;

        return [
            'collection_rate' => round($collectionRate, 2),
            'threshold_ratio' => round($thresholdRatio, 2),
            'is_healthy' => $isHealthy,
            'runs' => $status->runs,
            'collected' => $status->collected,
            'roots' => $status->roots,
            'threshold' => $status->threshold,
        ];
    }

    /**
     * Take GC snapshot for comparison
     *
     * Useful for tracking GC behavior over time
     */
    public function takeSnapshot(string $label = 'checkpoint'): array
    {
        return [
            'label' => $label,
            'timestamp' => Timestamp::now()->toIso8601(),
            'status' => $this->getStatus()->toArray(),
            'efficiency' => $this->getEfficiencyMetrics(),
        ];
    }
}
