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

/** The YesWiki console: every command inside a wiki, only those needing no wiki in a bare Program tree. */

namespace YesWiki\Core\Commands;

use Symfony\Component\Console\Application;
use YesWiki\Core\YesWikiLoader;
use YesWiki\Kernel\Command\RunsOutsideAnInstance;
use YesWiki\Kernel\Service\ConfigurationFileProvider;
use YesWiki\Kernel\Service\EnvironmentConfiguration;
use YesWiki\Kernel\Service\ExtensionRegistry;

require_once dirname(__DIR__) . '/bootstrap_paths.php';
require_once dirname(__DIR__) . '/autoload.inc.php';
require_once YESWIKI_PROGRAM_DIR . '/vendor/autoload.php';
require_once dirname(__DIR__) . '/YesWikiLoader.php';
YesWikiLoader::loadEnv();

$configFile = ConfigurationFileProvider::getConfigFileFromEnv();
$yeswikiConfig = [];
if (file_exists($configFile)) {
    include_once $configFile;
    $yeswikiConfig = (is_array($yeswikiConfig) && $yeswikiConfig !== []) ? $yeswikiConfig : ($wakkaConfig ?? []);
    $yeswikiConfig = EnvironmentConfiguration::apply($yeswikiConfig);
}

$configuredWiki = !empty($yeswikiConfig['base_url']);
$insideAnInstance = $configuredWiki;
$services = null;

if ($insideAnInstance) {
    $_SERVER['REQUEST_URI'] = $yeswikiConfig['base_url'] . ($yeswikiConfig['root_page'] ?? '');
    $_SERVER['HTTP_HOST'] = parse_url($yeswikiConfig['base_url'], PHP_URL_HOST);
    $_SERVER['REQUEST_METHOD'] = 'GET';
    $_GET['wiki'] = $yeswikiConfig['root_page'] ?? '';

    try {
        $wiki = YesWikiLoader::getWiki();
    } catch (\Throwable $bootFailure) {
        fwrite(STDERR, "\e[31m" . basename($configFile) . ' configures a wiki in ' . YESWIKI_INSTANCE_DIR
            . ", but it does not boot:\e[0m\n" . $bootFailure->getMessage() . "\n");
        exit(1);
    }
    $services = $wiki->services;
}

$application = new Application(
    'YesWiki',
    ($insideAnInstance ? 'in ' : 'no wiki in ') . YESWIKI_INSTANCE_DIR
);

$activeExtensions = $services?->get(ExtensionRegistry::class)->all() ?? [];
foreach ([
    'core' => YESWIKI_PROGRAM_DIR . '/src/commands/*.php',
    'module' => YESWIKI_PROGRAM_DIR . '/src/*/Command/*.php',
    'custom' => YESWIKI_INSTANCE_DIR . '/custom/commands/*.php',
    'extensions' => YESWIKI_PROGRAM_DIR . '/extensions/*/commands/*.php',
    'custom-extensions' => YESWIKI_INSTANCE_DIR . '/custom/extensions/*/commands/*.php',
] as $type => $search) {
    $files = glob($search);
    foreach ($files as $filePath) {
        $filename = pathinfo($filePath)['filename'];
        switch ($type) {
            case 'core':
                $className = "\\YesWiki\\Core\\Commands\\$filename";
                break;
            case 'module':
                $moduleName = basename(dirname(dirname($filePath)));
                $className = "\\YesWiki\\{$moduleName}\\Command\\$filename";
                break;
            case 'custom':
                $className = "\\YesWiki\\Custom\\Commands\\$filename";
                break;
            case 'extensions':
            case 'custom-extensions':
                $extensionDir = dirname(dirname($filePath));
                $registered = $activeExtensions[basename($extensionDir)] ?? null;
                if ($registered === null || realpath($registered) !== realpath($extensionDir)) {
                    continue 2;
                }
                $toolName = ucfirst(strtolower(basename(dirname(dirname($filePath)))));
                $className = "\\YesWiki\\$toolName\\Commands\\$filename";
                break;
            default:
                $className = '';
                break;
        }
        if (!class_exists($className)) {
            continue;
        }
        if (!$insideAnInstance && !is_subclass_of($className, RunsOutsideAnInstance::class)) {
            continue;
        }
        $application->add(new $className($services));
    }
}

$asked = isset($_SERVER['argv'][1]) && !str_starts_with((string)$_SERVER['argv'][1], '-')
    ? (string)$_SERVER['argv'][1]
    : '';
if (!$insideAnInstance && ($asked === '' || $asked === 'list' || $asked === 'help')) {
    $inTheProgramTree = realpath(YESWIKI_INSTANCE_DIR) === realpath(YESWIKI_PROGRAM_DIR);
    $halfWritten = file_exists($configFile) && !$configuredWiki;
    if ($halfWritten) {
        $reason = "\e[33mThere is a " . basename($configFile) . ' in ' . YESWIKI_INSTANCE_DIR
            . ", but it configures no wiki (no base_url).\e[0m\n"
            . "An install that never finished leaves one behind. Finish it in a browser, or remove the file.\n\n";
    } elseif ($inTheProgramTree) {
        $reason = "\e[33mNo yeswiki.config.php here: this is a YesWiki program tree, not a wiki.\e[0m\n"
            . "Only the commands that need no wiki are listed. Run this from a wiki folder for the rest,\n"
            . "or make one here: \e[32m./yeswicli core:create-instance <path>\e[0m\n\n";
    } else {
        $reason = "\e[33mNo yeswiki.config.php in " . YESWIKI_INSTANCE_DIR . ": this wiki is not installed yet.\e[0m\n"
            . "Visit it in a browser to install it; every command below the installer needs is listed then.\n\n";
    }
    fwrite(STDERR, $reason);
}

$application->run();
