<?php

namespace App\Commands\Concerns;

use Illuminate\Contracts\Process\ProcessResult;
use Illuminate\Process\PendingProcess;
use Illuminate\Support\Facades\Process;
use RuntimeException;

trait InteractsWithPijul
{
    protected function runPijul(
        array $arguments,
        bool $interactive = false,
        array $environment = [],
        bool $disableTimeout = false,
    ): ProcessResult {
        return $this->ensurePijulSucceeded($this->tryPijul($arguments, $interactive, $environment, $disableTimeout));
    }

    protected function tryPijul(
        array $arguments,
        bool $interactive = false,
        array $environment = [],
        bool $disableTimeout = false,
    ): ProcessResult {
        $pendingProcess = Process::path(base_path());

        if ($environment !== []) {
            $pendingProcess = $pendingProcess->env($environment);
        }

        if ($disableTimeout) {
            $pendingProcess = $pendingProcess->forever();
        }

        if ($interactive) {
            $pendingProcess = $this->configureInteractiveProcess($pendingProcess);
        }

        return $pendingProcess->run(array_merge(['pijul'], $arguments));
    }

    protected function ensurePijulSucceeded(ProcessResult $result): ProcessResult
    {
        if ($result->failed()) {
            $errorOutput = trim($result->errorOutput());

            throw new RuntimeException($errorOutput !== ''
                ? $errorOutput
                : sprintf('The command "%s" failed.', $result->command()));
        }

        return $result;
    }

    private function configureInteractiveProcess(PendingProcess $pendingProcess): PendingProcess
    {
        $pendingProcess = $pendingProcess->forever();

        if (Process::supportsTty()) {
            $pendingProcess = $pendingProcess->tty();
        }

        return $pendingProcess;
    }
}