<?php
if (!defined('WP_CLI') || !WP_CLI) {
    return;
}

$wpCliTimeout = max( (int) getenv('WP_CLI_COMMAND_TIMEOUT'), 0 ) ?: 600;
ini_set('max_execution_time', $wpCliTimeout);

define('WPAAS_MHP_CLI_HELPER_BOUNDARY_START', '////////WPAAS_MHP_START////////');
define('WPAAS_MHP_CLI_HELPER_BOUNDARY_END', '////////WPAAS_MHP_END////////');

/**
 * wp-cli cmds to add boundary to
 */
$boundaryWpCliCmds = [
    'cache',
    'cli',
    'config',
    'core',
    'cron',
    'db',
    'godaddy',
    'nux',
    'option',
    'plugin',
    'post',
    'rewrite',
    'search',
    'theme',
    'user',
    'wpaas',
];

// Get error key
function wpaas_mhp_cli_helper_get_error_key($errno, $errstr)
{
    // Maybe generalize the unserialize offset notices.
    if ((E_NOTICE === $errno || E_WARNING === $errno) && false !== strpos($errstr, 'unserialize(): Error at offset')) {
        $errstr = 'unserialize(): Error at offset X of Y bytes (generalized)';
    }

    return "{$errno}-{$errstr}";
}

function wpaas_mhp_cli_helper_error_handler($errno, $errstr, $errfile = null, $errline = null) {
    static $errorCounter = [];
    static $errorTypeCounter = [];

    $errorKey = wpaas_mhp_cli_helper_get_error_key($errno, $errstr);

    if (!isset($errorCounter[$errorKey])) {
        $errorCounter[$errorKey] = 0;
    }

    if (!isset($errorTypeCounter[$errno])) {
        $errorTypeCounter[$errno] = 0;
    }

    // Swallow the error if there are large numbers of the same one.
    if (20 < $errorCounter[$errorKey]) {
        return;
    }

    // Swallow the error if there are large numbers of the same type.
    if (100 < $errorTypeCounter[$errno]) {
        return;
    }

    $errorCounter[$errorKey]++;
    $errorTypeCounter[$errno]++;

    $formattedError = wpaas_mhp_cli_helper_format_error($errno, $errstr, $errfile, $errline);

    fwrite(STDERR, $formattedError);

    $isFatal = $errno & (E_ERROR | E_PARSE | E_CORE_ERROR | E_COMPILE_ERROR | E_USER_ERROR);
    if ($isFatal) {
        exit(1);
    }
}

set_error_handler('wpaas_mhp_cli_helper_error_handler');

foreach ($boundaryWpCliCmds as $cmd) {
    WP_CLI::add_hook('before_invoke:' . $cmd, static function () {
        fwrite(STDOUT, WPAAS_MHP_CLI_HELPER_BOUNDARY_START . PHP_EOL);
    });
    WP_CLI::add_hook('after_invoke:' . $cmd, static function () {
        fwrite(STDOUT, PHP_EOL . WPAAS_MHP_CLI_HELPER_BOUNDARY_END);
    });
}

function wpaas_mhp_cli_helper_format_error($errno, $errstr, $errfile = null, $errline = null)
{
    $errType = wpaas_mhp_cli_helper_error_type($errno);

    return "{$errType}({$errno}): {$errstr} {$errfile}#{$errline}" . PHP_EOL;
}

function wpaas_mhp_cli_helper_error_type($errno)
{
    switch ($errno) {
        case E_ERROR:
            return 'Error';
        case E_WARNING:
            return 'Warning';
        case E_PARSE:
            return 'Parse';
        case E_NOTICE:
            return 'Notice';
        case E_CORE_ERROR:
            return 'Core Error';
        case E_CORE_WARNING:
            return 'Core Warning';
        case E_COMPILE_ERROR:
            return 'Compile Error';
        case E_COMPILE_WARNING:
            return 'Compile Warning';
        case E_DEPRECATED:
            return 'Deprecated';
        case E_USER_ERROR:
            return 'User Error';
        case E_USER_WARNING:
            return 'User Warning';
        case E_USER_NOTICE:
            return 'User Notice';
        case E_USER_DEPRECATED:
            return 'User Deprecated';
        case E_STRICT:
            return 'Strict';
        default:
            return 'Unknown';
    }
}
