<?php
/**
 * Run tests via CLI.
 *
 * This command tries to run PHPUnit via:
 * - flowaxy/Support/Tests/_tools/phpunit-*.phar (preferred)
 * - vendor/bin/phpunit (if exists)
 * - phpunit from PATH
 * - phpunit.phar in project root
 *
 * @package Flowaxy\Interface\CLI\Commands
 */

declare(strict_types=1);

namespace Flowaxy\Interface\CLI\Commands;

use Flowaxy\Core\System\PathResolver;
use Flowaxy\Interface\CLI\Command;

use function escapeshellarg;
use function exec;
use function file_exists;
use function glob;
use function implode;
use function is_array;
use function count;
use function defined;
use function str_starts_with;
use function trim;

final class TestRunCommand extends Command
{
    public function getName(): string
    {
        return 'test:run';
    }

    public function getDescription(): string
    {
        return 'Run test suite via PHPUnit (no UI output)';
    }

    public function getHelp(): string
    {
        return "Usage:\n"
            . "  php index.php test:run\n"
            . "  php index.php test:run --filter=<pattern>\n"
            . "  php index.php test:run <path_or_testfile>\n";
    }

    protected function handle(array $args): int
    {
        $projectRoot = PathResolver::root();
        $flowaxyDir = PathResolver::flowaxy();

        $phpunit = null;

        // Prefer bundled PHPUnit PHAR from flowaxy/Support/Tests/_tools
        $toolsDir = $flowaxyDir . DS . 'Support' . DS . 'Tests' . DS . '_tools';
        $toolPhars = [];
        if (file_exists($toolsDir)) {
            // glob() is available in standard PHP; if disabled, we just skip.
            if (function_exists('glob')) {
                $toolPhars = glob($toolsDir . DS . 'phpunit-*.phar') ?: [];
            }
        }
        if (is_array($toolPhars) && count($toolPhars) > 0) {
            // Use the first match (versions are embedded in filename; keep it simple)
            $phpBin = defined('PHP_BINARY') && PHP_BINARY !== '' ? escapeshellarg(PHP_BINARY) : 'php';
            $phpunit = $phpBin . ' ' . escapeshellarg((string) $toolPhars[0]);
        }

        $vendorBin = $projectRoot . DS . 'vendor' . DS . 'bin' . DS . 'phpunit';
        if ($phpunit === null && file_exists($vendorBin)) {
            $phpunit = escapeshellarg($vendorBin);
        } elseif ($phpunit === null) {
            // Try phpunit from PATH
            $out = [];
            $code = 0;
            @exec('phpunit --version', $out, $code);
            if ($code === 0) {
                $phpunit = 'phpunit';
            } else {
                $phar = $projectRoot . DS . 'phpunit.phar';
                if (file_exists($phar)) {
                    $phpBin = defined('PHP_BINARY') && PHP_BINARY !== '' ? escapeshellarg(PHP_BINARY) : 'php';
                    $phpunit = $phpBin . ' ' . escapeshellarg($phar);
                }
            }
        }

        if ($phpunit === null) {
            $this->error('PHPUnit not found. Put phpunit-*.phar into flowaxy/Support/Tests/_tools or install phpunit.');
            return 1;
        }

        $cmd = $phpunit;

        // Prefer configuration if present
        $phpunitXml = $projectRoot . DS . 'phpunit.xml';
        $phpunitXmlAlt = $flowaxyDir . DS . 'Support' . DS . 'Tests' . DS . 'phpunit.xml';
        if (file_exists($phpunitXml)) {
            $cmd .= ' -c ' . escapeshellarg($phpunitXml);
        } elseif (file_exists($phpunitXmlAlt)) {
            $cmd .= ' -c ' . escapeshellarg($phpunitXmlAlt);
        }

        // Pass through args as-is
        $hasNonFlagArg = false;
        $hasBootstrapFlag = false;
        $hasConfigFlag = false;
        if (is_array($args) && count($args) > 0) {
            $escaped = [];
            foreach ($args as $arg) {
                $a = trim((string) $arg);
                if ($a === '') {
                    continue;
                }
                // keep --flags unquoted when possible
                if (str_starts_with($a, '--')) {
                    if (str_starts_with($a, '--bootstrap')) {
                        $hasBootstrapFlag = true;
                    }
                    if (str_starts_with($a, '--configuration')) {
                        $hasConfigFlag = true;
                    }
                    $escaped[] = $a;
                } else {
                    if ($a === '-c') {
                        $hasConfigFlag = true;
                    }
                    if ($a === '--bootstrap') {
                        $hasBootstrapFlag = true;
                    }
                    if (!str_starts_with($a, '-')) {
                        $hasNonFlagArg = true;
                    }
                    $escaped[] = escapeshellarg($a);
                }
            }
            if (count($escaped) > 0) {
                $cmd .= ' ' . implode(' ', $escaped);
            }
        }

        // If there is no phpunit.xml and user didn't provide config, add sane defaults
        $hasAnyConfig = file_exists($phpunitXml) || file_exists($phpunitXmlAlt) || $hasConfigFlag;
        if (!$hasAnyConfig && !$hasBootstrapFlag) {
            $bootstrap = $flowaxyDir . DS . 'Support' . DS . 'Tests' . DS . 'bootstrap.php';
            if (file_exists($bootstrap)) {
                $cmd .= ' --bootstrap ' . escapeshellarg($bootstrap);
            }
        }
        if (!$hasNonFlagArg) {
            $cmd .= ' ' . escapeshellarg($flowaxyDir . DS . 'Support' . DS . 'Tests');
        }

        $this->output("Running: {$cmd}");
        $output = [];
        $exit = 0;
        exec($cmd, $output, $exit);
        foreach ($output as $line) {
            $this->output((string) $line);
        }

        return $exit;
    }
}
