<?php

declare(strict_types=1);

namespace CpCreation\VitiCore\PageBuilder\Builder;

final readonly class BuilderTailwindCompiler
{
    public function __construct(
        private string $kernelProjectDir,
        private string $kernelEnvironment,
    ) {
    }

    /**
     * @return array{compiled: bool, exitCode?: int, skipped?: bool, output?: string, error?: string, reason?: string}
     */
    public function compile(): array
    {
        if ('prod' !== $this->kernelEnvironment) {
            return [
                'compiled' => true,
                'skipped' => true,
                'reason' => 'Compilation runtime inutile hors prod: le watcher dev doit compiler les assets.',
            ];
        }

        $lockPath = $this->kernelProjectDir.'/var/page-builder-tailwind-compile.lock';
        $lock = fopen($lockPath, 'c');

        if (false === $lock) {
            return ['compiled' => false, 'error' => 'Impossible de créer le verrou de compilation.'];
        }

        if (!flock($lock, LOCK_EX | LOCK_NB)) {
            fclose($lock);

            return ['compiled' => false, 'skipped' => true, 'error' => 'Une compilation est déjà en cours.'];
        }

        @set_time_limit(120);

        $process = proc_open(
            ['node', './node_modules/.bin/encore', 'production'],
            [
                1 => ['pipe', 'w'],
                2 => ['pipe', 'w'],
            ],
            $pipes,
            $this->kernelProjectDir,
        );

        if (!\is_resource($process)) {
            flock($lock, LOCK_UN);
            fclose($lock);

            return ['compiled' => false, 'error' => 'Impossible de lancer Encore.'];
        }

        $output = stream_get_contents($pipes[1]);
        $error = stream_get_contents($pipes[2]);
        fclose($pipes[1]);
        fclose($pipes[2]);

        $exitCode = proc_close($process);
        flock($lock, LOCK_UN);
        fclose($lock);

        return [
            'compiled' => 0 === $exitCode,
            'exitCode' => $exitCode,
            'output' => trim(((string) $output)."\n".((string) $error)),
        ];
    }
}
