<?php

declare(strict_types=1);

namespace App\Framework\Process\Exceptions;

use App\Framework\Exception\Core\ConsoleErrorCode;
use App\Framework\Exception\Core\FileSystemErrorCode;
use App\Framework\Exception\Core\SystemErrorCode;
use App\Framework\Exception\FrameworkException;
use App\Framework\Process\ProcessResult;
use App\Framework\Process\ValueObjects\Command;

/**
 * Exception für Prozess-bezogene Fehler.
 */
final class ProcessException extends FrameworkException
{
    /**
     * Erstellt eine Exception, wenn ein Prozess nicht gestartet werden kann.
     */
    public static function failedToStart(Command $command, ?string $reason = null): self
    {
        $message = "Failed to start process: {$command->toString()}";
        if ($reason !== null) {
            $message .= " - {$reason}";
        }

        return self::create(
            SystemErrorCode::RESOURCE_EXHAUSTED,
            $message
        )->withData([
            'command' => $command->toString(),
            'reason' => $reason,
        ]);
    }

    /**
     * Erstellt eine Exception, wenn ein Prozess fehlschlägt.
     */
    public static function executionFailed(ProcessResult $result): self
    {
        return self::create(
            SystemErrorCode::INITIALIZATION_FAILED,
            "Process execution failed: {$result->command->toString()}"
        )->withData([
            'command' => $result->command->toString(),
            'exit_code' => $result->exitCode->value,
            'exit_description' => $result->exitCode->getDescription(),
            'stderr' => $result->stderr,
            'runtime_ms' => $result->runtime->toMilliseconds(),
        ]);
    }

    /**
     * Erstellt eine Exception, wenn ein Kommando nicht gefunden wird.
     */
    public static function commandNotFound(string $commandName): self
    {
        return self::create(
            ConsoleErrorCode::COMMAND_NOT_FOUND,
            "Command not found: {$commandName}"
        )->withData([
            'command' => $commandName,
        ]);
    }

    /**
     * Erstellt eine Exception, wenn ein Signal nicht gesendet werden kann.
     */
    public static function failedToSendSignal(int $pid, int $signal): self
    {
        return self::create(
            SystemErrorCode::RESOURCE_EXHAUSTED,
            "Failed to send signal {$signal} to process {$pid}"
        )->withData([
            'pid' => $pid,
            'signal' => $signal,
        ]);
    }

    /**
     * Erstellt eine Exception, wenn das Arbeitsverzeichnis ungültig ist.
     */
    public static function invalidWorkingDirectory(string $path): self
    {
        return self::create(
            FileSystemErrorCode::FILE_NOT_FOUND,
            "Invalid working directory: {$path}"
        )->withData([
            'path' => $path,
        ]);
    }
}
