#!/usr/bin/env php
<?php
/**
 * Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
 *
 * This file is part of a Moko Consulting project.
 *
 * SPDX-License-Identifier: GPL-3.0-or-later
 *
 * FILE INFORMATION
 * DEFGROUP: MokoStandards.CLI
 * INGROUP: MokoStandards
 * REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
 * PATH: /bin/moko
 * BRIEF: Unified CLI dispatcher — run any MokoStandards script without needing GitHub Actions
 *
 * USAGE
 *   php bin/moko <command> [options]     (all platforms)
 *   ./bin/moko <command> [options]       (Unix, after: chmod +x bin/moko)
 *
 * COMMANDS
 *   sync                  Bulk-sync MokoStandards to organisation repos
 *   health                Full repository health check (runs most validators)
 *   inventory             Refresh docs/reference/REPOSITORY_INVENTORY.md
 *
 *   check:syntax          PHP syntax check (php -l) on all tracked .php files
 *   check:version         Verify VERSION fields and badges match composer.json
 *   check:changelog       Validate CHANGELOG.md format
 *   check:structure       Verify required root files and directories
 *   check:headers         Check SPDX-License-Identifier presence in source files
 *   check:secrets         Scan for leaked credentials / API keys
 *   check:tabs            Detect tab characters in YAML files
 *   check:paths           Detect backslash path separators in PHP source
 *   check:xml             Validate XML files are well-formed
 *   check:enterprise      Full enterprise-readiness check (headers, strict types, PSR-12)
 *   check:dolibarr        Validate Dolibarr module directory structure
 *   check:joomla          Validate Joomla XML manifest
 *   check:language        Validate Joomla/Dolibarr .ini language files
 *   detect                Auto-detect repository platform type
 *   drift                 Scan org repos for drift from MokoStandards templates
 *
 * COMMON OPTIONS (passed through to each script)
 *   --path <dir>          Repository root to check (default: .)
 *   --dry-run             Preview changes without applying them
 *   --verbose             Show passing checks as well as failures
 *   --quiet               Show only failures
 *   --json                Machine-readable JSON output
 *   --help                Show help for the selected command
 *
 * AUTHENTICATION
 *   Token resolution order (first non-empty wins):
 *     1. GH_TOKEN environment variable
 *     2. GITHUB_TOKEN environment variable
 *     3. `gh auth token` (GitHub CLI — run `gh auth login` once)
 *     4. .env file in repo root (GH_TOKEN=... line)
 *
 * EXAMPLES
 *   php bin/moko health
 *   php bin/moko sync -- --repos MokoDoliTraining --dry-run
 *   php bin/moko check:version --path .
 *   php bin/moko drift -- --org mokoconsulting-tech --json
 */

declare(strict_types=1);

// ── Bootstrap ────────────────────────────────────────────────────────────────

$repoRoot   = dirname(__DIR__);
$autoloader = $repoRoot . '/vendor/autoload.php';

if (!is_file($autoloader)) {
    fwrite(STDERR, "Error: vendor/autoload.php not found.\nRun: composer install\n");
    exit(2);
}

require_once $autoloader;

// ── Command map ──────────────────────────────────────────────────────────────

/**
 * Map of moko command names → relative path to the PHP script.
 * All paths are relative to the repo root.
 */
const COMMAND_MAP = [
    // Automation
    'sync'             => 'api/automation/bulk_sync.php',

    // Maintenance
    'inventory'        => 'api/maintenance/update_repo_inventory.php',

    // Validation — general
    'health'           => 'api/validate/check_repo_health.php',
    'check:syntax'     => 'api/validate/check_php_syntax.php',
    'check:version'    => 'api/validate/check_version_consistency.php',
    'check:changelog'  => 'api/validate/check_changelog.php',
    'check:structure'  => 'api/validate/check_structure.php',
    'check:headers'    => 'api/validate/check_license_headers.php',
    'check:secrets'    => 'api/validate/check_no_secrets.php',
    'check:tabs'       => 'api/validate/check_tabs.php',
    'check:paths'      => 'api/validate/check_paths.php',
    'check:xml'        => 'api/validate/check_xml_wellformed.php',
    'check:enterprise' => 'api/validate/check_enterprise_readiness.php',

    // Validation — platform-specific
    'check:dolibarr'   => 'api/validate/check_dolibarr_module.php',
    'check:joomla'     => 'api/validate/check_joomla_manifest.php',
    'check:language'   => 'api/validate/check_language_structure.php',

    // Detection
    'detect'           => 'api/validate/auto_detect_platform.php',

    // Org-wide
    'drift'            => 'api/validate/scan_drift.php',

    // Release
    'release'              => 'api/cli/release.php',

    // CLI utilities (used by workflows — centralized logic)
    'version:read'         => 'api/cli/version_read.php',
    'version:bump'         => 'api/cli/version_bump.php',
    'version:propagate'    => 'api/maintenance/update_version_from_readme.php',
    'version:set-platform' => 'api/cli/version_set_platform.php',
    'platform:detect'      => 'api/cli/platform_detect.php',
    'release:notes'        => 'api/cli/release_notes.php',
    'validate:module'      => 'bin/validate-module',
];

// ── Argument parsing ─────────────────────────────────────────────────────────

$args    = array_slice($argv, 1);
$command = array_shift($args) ?? '';

// Strip leading -- separator that Composer passes when using `composer run-script cmd -- extra-args`
if (isset($args[0]) && $args[0] === '--') {
    array_shift($args);
}

// ── Help / list ───────────────────────────────────────────────────────────────

if ($command === '' || $command === '--help' || $command === '-h' || $command === 'help') {
    printHelp();
    exit(0);
}

if ($command === 'list' || $command === 'commands') {
    printCommandList();
    exit(0);
}

// ── Dispatch ──────────────────────────────────────────────────────────────────

if (!array_key_exists($command, COMMAND_MAP)) {
    fwrite(STDERR, "Error: Unknown command '{$command}'\n\n");
    printCommandList();
    exit(2);
}

$scriptPath = $repoRoot . '/' . COMMAND_MAP[$command];

if (!is_file($scriptPath)) {
    fwrite(STDERR, "Error: Script not found: " . COMMAND_MAP[$command] . "\n");
    fwrite(STDERR, "Ensure the repository is complete and run: composer install\n");
    exit(2);
}

// Rebuild $argv as if the target script were invoked directly, then include it.
// This is equivalent to: php <script> [args…]  but keeps us in the same process.
$argv  = array_merge([$scriptPath], $args);
$argc  = count($argv);

// Suppress the "run directly" guard that some scripts use (they check realpath($argv[0]) === __FILE__).
// By setting $argv[0] to the script's own path the guard passes naturally.
require $scriptPath;

// ── Helpers ───────────────────────────────────────────────────────────────────

function printHelp(): void
{
    echo <<<'HELP'
╔══════════════════════════════════════════════════════════╗
║              MokoStandards CLI  (bin/moko)               ║
╚══════════════════════════════════════════════════════════╝

Run any MokoStandards script locally without GitHub Actions.

USAGE
  php bin/moko <command> [options]     (all platforms)
  ./bin/moko <command> [options]       (Unix, after: chmod +x bin/moko)

Run `php bin/moko list` to see all available commands.
Run `php bin/moko <command> --help` for command-specific help.

QUICK START
  1. composer install
  2. cp .env.example .env   # add your GH_TOKEN
  3. php bin/moko health    # run full health check

AUTHENTICATION
  GH_TOKEN env var  →  GITHUB_TOKEN env var  →  gh auth login

HELP;
}

function printCommandList(): void
{
    echo "Available commands:\n\n";

    $groups = [
        'Automation'          => ['sync'],
        'Maintenance'         => ['inventory'],
        'Validation (general)' => ['health', 'check:syntax', 'check:version', 'check:changelog',
                                   'check:structure', 'check:headers', 'check:secrets',
                                   'check:tabs', 'check:paths', 'check:xml', 'check:enterprise'],
        'Validation (platform)' => ['check:dolibarr', 'check:joomla', 'check:language', 'detect'],
        'Organisation-wide'   => ['drift'],
    ];

    foreach ($groups as $group => $commands) {
        echo "  {$group}:\n";
        foreach ($commands as $cmd) {
            printf("    %-22s %s\n", $cmd, COMMAND_MAP[$cmd]);
        }
        echo "\n";
    }

    echo "Run: php bin/moko <command> --help   for command-specific options.\n";
    echo "All platforms: php bin/moko <command>\n";
}
