<?php

declare(strict_types=1);

namespace App\Framework\Console\Middleware;

use App\Framework\Console\ExitCode;
use App\Framework\Performance\Contracts\PerformanceCollectorInterface;
use App\Framework\Performance\PerformanceCategory;

final readonly class ConsolePerformanceMiddleware
{
    public function __construct(
        private PerformanceCollectorInterface $collector
    ) {
    }

    public function handle(string $commandName, callable $next): ExitCode
    {
        $metricKey = "console_command_{$commandName}";

        $this->collector->startTiming($metricKey, PerformanceCategory::CONSOLE, [
            'command_name' => $commandName,
            'execution_context' => 'console',
        ]);

        $this->collector->increment('console_command_executions', PerformanceCategory::CONSOLE, 1, [
            'command_name' => $commandName,
        ]);

        $memoryStart = memory_get_usage(true);
        $peakMemoryStart = memory_get_peak_usage(true);

        try {
            $result = $next();

            $this->collector->recordMetric(
                "console_command_{$commandName}_success",
                1.0,
                PerformanceCategory::CONSOLE,
                ['command_name' => $commandName, 'status' => 'success']
            );

            return $result;

        } catch (\Throwable $e) {
            $this->collector->recordMetric(
                "console_command_{$commandName}_error",
                1.0,
                PerformanceCategory::CONSOLE,
                [
                    'command_name' => $commandName,
                    'status' => 'error',
                    'error_type' => get_class($e),
                    'error_message' => $e->getMessage(),
                ]
            );

            throw $e;

        } finally {
            $this->collector->endTiming($metricKey);

            $memoryEnd = memory_get_usage(true);
            $peakMemoryEnd = memory_get_peak_usage(true);

            $this->collector->recordMetric(
                "console_command_{$commandName}_memory_usage",
                ($memoryEnd - $memoryStart) / 1024 / 1024, // MB
                PerformanceCategory::CONSOLE,
                ['command_name' => $commandName, 'unit' => 'MB']
            );

            $this->collector->recordMetric(
                "console_command_{$commandName}_peak_memory",
                ($peakMemoryEnd - $peakMemoryStart) / 1024 / 1024, // MB
                PerformanceCategory::CONSOLE,
                ['command_name' => $commandName, 'unit' => 'MB']
            );
        }
    }
}
