#!/usr/bin/env php
<?php

const SUCCESS = 0;
const FAILURE = 1;

class Config
{
    public bool $colorized = false;
    public string $singleFilePath = '';
    public bool $checkStagedGitFilesOnly = false;
    public bool $stopOnFailure = false;
}

$mustHaveFiles = [
    'phpcs.xml',
    'phpmd.xml',
    'phpmd-tests.xml',
    'phpstan.neon',
    'phpcpd.xml',
    'phpmnd.xml',
    'phpdrc.yaml',
];

function writeLine(string $content, Config $config): void
{
    if ($config->colorized) {
        echo "\033[1;32m$content\033[0m\n";
    } else {
        echo $content."\n";
    }
}

/**
 * @param string[] $files
 */
function checkMusthaveFiles(array $files): void
{
    foreach ($files as $file) {
        if (!file_exists($file)) {
            throw new Exception("File $file does not exist");
        }
    }
}

function getConfigFromArgs(): Config
{
    $config = new Config();
    $args = getopt('m::p::c::s::');
    if (isset($args['c'])) {
        $config->colorized = true;
    }
    if (isset($args['p'])) {
        $path = $args['p'];
        /** @var string $path */
        $config->singleFilePath = $path;
    }
    if (isset($args['m'])) {
        $config->checkStagedGitFilesOnly = true;
    }
    if (isset($args['s'])) {
        $config->stopOnFailure = true;
    }

    return $config;

}

function checkSinglePath(
    string $path,
    Config $config
): int {
    $commandsToLaunch = [
        'phpcs' => sprintf(
            'vendor/bin/phpcs %s %s',
            $config->colorized ? '--colors' : '',
            $path
        ),
        'phpmd' => sprintf(
            "php -d 'error_reporting=E_ALL&~E_NOTICE&~E_DEPRECATED' vendor/bin/phpmd %s %s text phpmd.xml",
            $path,
            $config->colorized ? '--color' : ''
        ),
        'phpmd-tests' => sprintf(
            "php -d 'error_reporting=E_ALL&~E_NOTICE&~E_DEPRECATED' vendor/bin/phpmd %s %s text phpmd-tests.xml",
            $path,
            $config->colorized ? '--color' : ''
        ),
        'phpstan' => sprintf(
            'vendor/bin/phpstan %s %s %s --memory-limit=-1 --configuration=%s analyze %s',
            '-n',
            '--no-progress',
            $config->colorized ? '--ansi' : '',
            'phpstan.neon',
            $path
        ),
        'phpcpd' => sprintf(
            'vendor/bin/phpcpdrun %s',
            $path
        ),
        'phpmnd' => sprintf(
            'vendor/bin/phpmndrun %s %s',
            $path,
            $config->colorized ? '--ansi' : ''
        ),
        'phpdrc' => sprintf(
            'vendor/bin/phpdrc %s drc',
            $config->colorized ? '--ansi' : '--no-ansi'
        )
    ];

    $failedAtLeastOnce = false;
    foreach ($commandsToLaunch as $toolName => $command) {
        $status = launchToolWithReportingIssues(
            $toolName,
            $command,
            $config
        );
        if ($status !== SUCCESS) {
            $failedAtLeastOnce = true;
        }
        if ($status !== SUCCESS && $config->stopOnFailure) {
            return FAILURE;
        }
    }

    return $failedAtLeastOnce ? FAILURE : SUCCESS;
}

function launchToolWithReportingIssues(
    string $toolTitle,
    string $commandLaunch,
    Config $config
): int {
    exec(
        $commandLaunch,
        $output,
        $statusCode
    );
    if ($statusCode !== SUCCESS) {
        writeLine(
            $toolTitle,
            $config
        );
        echo implode(PHP_EOL, $output)."\n";
    }

    return $statusCode;
}

checkMusthaveFiles($mustHaveFiles);
$config = getConfigFromArgs();

if ($config->singleFilePath) {
    exit(checkSinglePath($config->singleFilePath, $config));
} elseif ($config->checkStagedGitFilesOnly) {
    exec('git ls-files -om --exclude-standard', $stagingFiles);
    foreach ($stagingFiles as $file) {
        exit(checkSinglePath($file, $config));
    }
} else {
    exit(checkSinglePath(getcwd(), $config));
}
