<?php
declare(strict_types=1);

/**
 * Compara informes generados por audit_plugin_freshness.php.
 *
 * Uso:
 *   php tools/compare_plugin_freshness.php vm1.json vm2.json vm3.json vm4.json
 *   php tools/compare_plugin_freshness.php --csv=var/plugin-freshness-compare.csv vm1.json vm2.json
 */

function compare_arg_value(array $args, string $name, ?string $default = null): ?string
{
    $prefix = $name . '=';
    foreach ($args as $arg) {
        if ($arg === $name) {
            return '';
        }
        if (strpos($arg, $prefix) === 0) {
            return substr($arg, strlen($prefix));
        }
    }
    return $default;
}

function compare_format_time(int $mtime): string
{
    return $mtime > 0 ? date('Y-m-d H:i:s', $mtime) : '';
}

function compare_latest_mtime(array $item): int
{
    return max((int) ($item['plugin_latest_mtime'] ?? 0), (int) ($item['app_latest_mtime'] ?? 0));
}

function compare_latest_origin(array $item): string
{
    if ((int) ($item['app_latest_mtime'] ?? 0) > (int) ($item['plugin_latest_mtime'] ?? 0)) {
        return 'apps';
    }
    if ((int) ($item['plugin_latest_mtime'] ?? 0) > 0) {
        return 'plugin';
    }
    return 'apps';
}

function compare_latest_file(array $item): string
{
    $origin = compare_latest_origin($item);
    if ($origin === 'apps') {
        return trim((string) ($item['app_path'] ?? '') . '/' . (string) ($item['app_latest_file'] ?? ''), '/');
    }
    return trim((string) ($item['plugin_path'] ?? '') . '/' . (string) ($item['plugin_latest_file'] ?? ''), '/');
}

function compare_report_label(string $path, array $payload): string
{
    $metaRoot = (string) ($payload['meta']['root'] ?? '');
    $base = pathinfo($path, PATHINFO_FILENAME);
    if ($base !== '') {
        return $base;
    }
    return $metaRoot !== '' ? $metaRoot : $path;
}

function compare_normalize_json_text(string $raw): string
{
    if (substr($raw, 0, 3) === "\xEF\xBB\xBF") {
        return substr($raw, 3);
    }

    $encoding = null;
    $offset = 0;
    if (substr($raw, 0, 2) === "\xFF\xFE") {
        $encoding = 'UTF-16LE';
        $offset = 2;
    } elseif (substr($raw, 0, 2) === "\xFE\xFF") {
        $encoding = 'UTF-16BE';
        $offset = 2;
    }

    if ($encoding === null) {
        return $raw;
    }

    $body = substr($raw, $offset);
    if (function_exists('mb_convert_encoding')) {
        return mb_convert_encoding($body, 'UTF-8', $encoding);
    }
    if (function_exists('iconv')) {
        $converted = iconv($encoding, 'UTF-8//IGNORE', $body);
        if (is_string($converted)) {
            return $converted;
        }
    }

    return $raw;
}

function compare_load_report(string $path): array
{
    $raw = @file_get_contents($path);
    if ($raw === false) {
        throw new RuntimeException('No se pudo leer el informe: ' . $path);
    }

    $raw = compare_normalize_json_text($raw);
    $payload = json_decode($raw, true);
    if (!is_array($payload) || !isset($payload['items']) || !is_array($payload['items'])) {
        throw new RuntimeException('Informe JSON no valido: ' . $path);
    }

    return $payload;
}

function compare_write_csv(string $path, array $rows): void
{
    $dir = dirname($path);
    if ($dir !== '' && $dir !== '.' && !is_dir($dir)) {
        @mkdir($dir, 0775, true);
    }

    $fh = fopen($path, 'wb');
    if ($fh === false) {
        throw new RuntimeException('No se pudo escribir el CSV: ' . $path);
    }

    fputcsv($fh, [
        'id',
        'kind',
        'winner',
        'latest_at',
        'winner_version',
        'winner_origin',
        'winner_file',
        'hash_status',
        'installations',
    ]);

    foreach ($rows as $row) {
        fputcsv($fh, [
            $row['id'],
            $row['kind'],
            $row['winner'],
            $row['latest_at'],
            $row['winner_version'],
            $row['winner_origin'],
            $row['winner_file'],
            $row['hash_status'],
            $row['installations'],
        ]);
    }

    fclose($fh);
}

$args = array_slice($argv ?? [], 1);
$csvPath = compare_arg_value($args, '--csv', null);
$files = [];
foreach ($args as $arg) {
    if (strpos($arg, '--') === 0) {
        continue;
    }
    $files[] = $arg;
}

if (count($files) < 2) {
    fwrite(STDERR, "Uso: php tools/compare_plugin_freshness.php vm1.json vm2.json [vm3.json ...]\n");
    exit(1);
}

$byId = [];
foreach ($files as $file) {
    $payload = compare_load_report($file);
    $label = compare_report_label($file, $payload);

    foreach ($payload['items'] as $item) {
        if (!is_array($item)) {
            continue;
        }

        $id = (string) ($item['id'] ?? '');
        if ($id === '') {
            continue;
        }

        $latestMtime = compare_latest_mtime($item);
        $byId[$id][] = [
            'label' => $label,
            'kind' => (string) ($item['kind'] ?? ''),
            'version' => (string) ($item['version'] ?? ''),
            'latest_mtime' => $latestMtime,
            'latest_at' => compare_format_time($latestMtime),
            'origin' => compare_latest_origin($item),
            'file' => compare_latest_file($item),
            'fingerprint' => (string) ($item['fingerprint'] ?? ''),
        ];
    }
}

ksort($byId, SORT_NATURAL | SORT_FLAG_CASE);

$rows = [];
foreach ($byId as $id => $entries) {
    usort($entries, static function (array $a, array $b): int {
        $cmp = (int) $b['latest_mtime'] <=> (int) $a['latest_mtime'];
        if ($cmp !== 0) {
            return $cmp;
        }
        return strcmp((string) $a['label'], (string) $b['label']);
    });

    $winner = $entries[0];
    $maxMtime = (int) $winner['latest_mtime'];
    $winners = array_values(array_filter($entries, static function (array $entry) use ($maxMtime): bool {
        return (int) $entry['latest_mtime'] === $maxMtime;
    }));
    $winnerLabel = implode('+', array_map(static function (array $entry): string {
        return (string) $entry['label'];
    }, $winners));

    $hashes = [];
    foreach ($entries as $entry) {
        if ((string) $entry['fingerprint'] !== '') {
            $hashes[$entry['fingerprint']] = true;
        }
    }
    $hashStatus = count($hashes) === 0 ? 'sin hash' : (count($hashes) === 1 ? 'igual' : 'distinto');

    $installations = implode(' | ', array_map(static function (array $entry): string {
        $version = (string) $entry['version'] !== '' ? (string) $entry['version'] : 'sin version';
        return $entry['label'] . ':' . $version . '@' . $entry['latest_at'];
    }, $entries));

    $rows[] = [
        'id' => $id,
        'kind' => implode(',', array_values(array_unique(array_map(static function (array $entry): string {
            return (string) $entry['kind'];
        }, $entries)))),
        'winner' => $winnerLabel,
        'latest_at' => compare_format_time($maxMtime),
        'winner_version' => (string) $winner['version'],
        'winner_origin' => (string) $winner['origin'],
        'winner_file' => (string) $winner['file'],
        'hash_status' => $hashStatus,
        'installations' => $installations,
    ];
}

if ($csvPath !== null) {
    $csvPath = $csvPath !== '' ? (string) $csvPath : 'plugin-freshness-compare.csv';
    compare_write_csv($csvPath, $rows);
    fwrite(STDERR, 'CSV escrito en: ' . $csvPath . PHP_EOL);
}

echo str_repeat('-', 150) . PHP_EOL;
printf(
    "%-28s %-13s %-22s %-19s %-10s %-7s %-34s %-9s\n",
    'ID',
    'Tipo',
    'Mas reciente',
    'Fecha',
    'Version',
    'Origen',
    'Fichero',
    'Hash'
);
echo str_repeat('-', 150) . PHP_EOL;

foreach ($rows as $row) {
    printf(
        "%-28s %-13s %-22s %-19s %-10s %-7s %-34s %-9s\n",
        substr((string) $row['id'], 0, 28),
        substr((string) $row['kind'], 0, 13),
        substr((string) $row['winner'], 0, 22),
        (string) $row['latest_at'],
        substr((string) $row['winner_version'], 0, 10),
        substr((string) $row['winner_origin'], 0, 7),
        substr((string) $row['winner_file'], 0, 34),
        substr((string) $row['hash_status'], 0, 9)
    );
}
