<?php

namespace Lucent\Command;

use Lucent\Command\Data\CommandLogItem;
use Lucent\Id\Id;
use Lucent\LucentException;
use Symfony\Component\Process\PhpExecutableFinder;


class CommandService
{

    public function __construct(
        private CommandRepo $commandRepo,
    )
    {
    }

    public function run(string $signature): CommandLogItem
    {
        $commandLogItem = $this->commandRepo->findBySignature($signature);

        if (empty($commandLogItem)) {
            $commandLogItem = new CommandLogItem(
                id: Id::new(),
                signature: $signature,
                pid: null,
                logs: ""
            );
        } elseif ($this->commandIsRunning($commandLogItem->pid)) {
            throw new LucentException('Command is already running');
        }

        $commandLogItem->pid = $this->runCommand($signature);
        $commandLogItem->logs = "";
        $this->commandRepo->upsertCommand($commandLogItem);
        return $commandLogItem;
    }

    public function logWriter(string $signature): callable
    {
        return function (string $line) use($signature) {
            $this->commandRepo->appendToLogs($signature, $line.PHP_EOL);
        };
    }

    private function runCommand(string $signature): int
    {
        $phpBinaryFinder = new PhpExecutableFinder();
        $phpBinaryPath = $phpBinaryFinder->find();
        $pid = (int)shell_exec("cd " . base_path() . " && $phpBinaryPath artisan {$signature} > /dev/null 2>&1 & echo $!");
        return $pid;
    }

    public function commandIsRunning(int $pid): bool
    {
        return file_exists("/proc/$pid");
    }
}