#!/usr/bin/env php
<?php
/**
 * Klee Smoke Tests (HTTP)
 *
 * Uso:
 *   php bin/smoke
 *   php bin/smoke --base-url=http://127.0.0.1:8000 --user=admin --pass=admin123
 *   php bin/smoke --json
 *   php bin/smoke --help
 */

$basePath = dirname(__DIR__);
define('BASE_PATH', $basePath . '/');

require $basePath . '/core/helpers/Env.php';
Env::load($basePath . '/.env');

$args = array_slice($argv, 1);
$jsonOutput = in_array('--json', $args, true);

if (!function_exists('smoke_exit')) {
    function smoke_exit($exitCode, $payload, $jsonOutput)
    {
        if ($jsonOutput) {
            echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . PHP_EOL;
        } else {
            if (isset($payload['message']) && is_string($payload['message']) && $payload['message'] !== '') {
                fwrite(STDERR, $payload['message'] . PHP_EOL);
            }
        }
        exit((int)$exitCode);
    }
}

if (in_array('--help', $args, true) || in_array('-h', $args, true)) {
    echo "\nKlee Smoke Tests\n";
    echo "Uso:\n";
    echo "  php bin/smoke\n";
    echo "  php bin/smoke --base-url=http://127.0.0.1:8000 --user=admin --pass=admin123\n";
    echo "  php bin/smoke --json\n";
    echo "Opciones:\n";
    echo "  --base-url=URL     Base URL de la app (ej: http://127.0.0.1:8000 o .../index.php)\n";
    echo "  --user=USUARIO     Usuario para login smoke\n";
    echo "  --pass=CLAVE       Clave para login smoke\n";
    echo "  --timeout=SEG      Timeout por request (default: 15)\n\n";
    echo "  --json             Salida en JSON (útil para CI)\n";
    echo "  --json-file=PATH   Guarda además el reporte JSON en archivo\n\n";
    exit(0);
}

if (!extension_loaded('curl')) {
    smoke_exit(2, array(
        'ok' => false,
        'message' => '[error] Extensión curl no disponible. Instálala para ejecutar smoke tests HTTP.',
    ), $jsonOutput);
}

$toBool = function ($value) {
    if (is_bool($value)) {
        return $value;
    }

    $value = strtolower(trim((string)$value));
    return in_array($value, array('1', 'true', 'yes', 'on'), true);
};

$options = array(
    'base-url' => getenv('SMOKE_BASE_URL') !== false ? trim((string)getenv('SMOKE_BASE_URL')) : 'http://127.0.0.1:8000',
    'user' => getenv('SMOKE_USER') !== false ? trim((string)getenv('SMOKE_USER')) : 'admin',
    'pass' => getenv('SMOKE_PASS') !== false ? (string)getenv('SMOKE_PASS') : 'admin123',
    'timeout' => getenv('SMOKE_TIMEOUT') !== false ? (int)getenv('SMOKE_TIMEOUT') : 15,
    'json' => getenv('SMOKE_JSON') !== false ? $toBool(getenv('SMOKE_JSON')) : $jsonOutput,
    'json-file' => getenv('SMOKE_JSON_FILE') !== false ? trim((string)getenv('SMOKE_JSON_FILE')) : '',
);

foreach ($args as $arg) {
    if (strpos($arg, '--base-url=') === 0) {
        $options['base-url'] = substr($arg, 11);
    } elseif (strpos($arg, '--user=') === 0) {
        $options['user'] = substr($arg, 7);
    } elseif (strpos($arg, '--pass=') === 0) {
        $options['pass'] = substr($arg, 7);
    } elseif (strpos($arg, '--timeout=') === 0) {
        $options['timeout'] = (int)substr($arg, 10);
    } elseif ($arg === '--json') {
        $options['json'] = true;
    } elseif (strpos($arg, '--json-file=') === 0) {
        $options['json-file'] = trim((string)substr($arg, 12));
    }
}

$baseUrl = trim((string)$options['base-url']);
$user = (string)$options['user'];
$pass = (string)$options['pass'];
$timeout = max(3, (int)$options['timeout']);
$jsonOutput = !empty($options['json']);
$jsonFile = (string)$options['json-file'];

if ($baseUrl === '') {
    smoke_exit(2, array(
        'ok' => false,
        'message' => '[error] base-url vacío',
    ), $jsonOutput);
}

$cookieJar = tempnam(sys_get_temp_dir(), 'klee_smoke_');
if ($cookieJar === false) {
    smoke_exit(2, array(
        'ok' => false,
        'message' => '[error] No fue posible crear archivo temporal para cookies.',
    ), $jsonOutput);
}

register_shutdown_function(function () use ($cookieJar) {
    if (is_string($cookieJar) && is_file($cookieJar)) {
        @unlink($cookieJar);
    }
});

$buildUrl = function ($params) use ($baseUrl) {
    $query = http_build_query($params);
    if (strpos($baseUrl, '?') !== false) {
        return $baseUrl . '&' . $query;
    }

    if (preg_match('/\.php\/?$/i', $baseUrl)) {
        return rtrim($baseUrl, '/') . '?' . $query;
    }

    return rtrim($baseUrl, '/') . '/?' . $query;
};

$request = function ($method, $url, $postFields = null) use ($cookieJar, $timeout) {
    $start = microtime(true);

    $ch = curl_init($url);
    curl_setopt_array($ch, array(
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_HEADER => true,
        CURLOPT_FOLLOWLOCATION => false,
        CURLOPT_CONNECTTIMEOUT => $timeout,
        CURLOPT_TIMEOUT => $timeout,
        CURLOPT_COOKIEJAR => $cookieJar,
        CURLOPT_COOKIEFILE => $cookieJar,
        CURLOPT_SSL_VERIFYPEER => false,
        CURLOPT_SSL_VERIFYHOST => false,
        CURLOPT_USERAGENT => 'klee-smoke/1.0',
    ));

    if (strtoupper($method) === 'POST') {
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, is_array($postFields) ? http_build_query($postFields) : (string)$postFields);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/x-www-form-urlencoded'));
    }

    $raw = curl_exec($ch);
    $err = curl_error($ch);
    $status = (int)curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    $headerSize = (int)curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $totalTimeMs = (int)round((microtime(true) - $start) * 1000);
    curl_close($ch);

    if ($raw === false) {
        return array(
            'ok' => false,
            'status' => 0,
            'headers' => '',
            'body' => '',
            'error' => $err !== '' ? $err : 'curl_exec failed',
            'time_ms' => $totalTimeMs,
        );
    }

    $headers = substr($raw, 0, $headerSize);
    $body = substr($raw, $headerSize);

    return array(
        'ok' => true,
        'status' => $status,
        'headers' => $headers,
        'body' => $body,
        'error' => '',
        'time_ms' => $totalTimeMs,
    );
};

$extractCsrf = function ($html) {
    if (preg_match('/name="_csrf_token"\s+value="([^"]+)"/i', $html, $m)) {
        return $m[1];
    }
    return '';
};

$containsAny = function ($body, $needles) {
    foreach ($needles as $needle) {
        if ($needle !== '' && stripos($body, $needle) !== false) {
            return true;
        }
    }
    return false;
};

$tests = array();
$failures = 0;

$record = function ($name, $ok, $detail, $ms) use (&$tests, &$failures) {
    $tests[] = array('name' => $name, 'ok' => $ok, 'detail' => $detail, 'ms' => $ms);
    if (!$ok) {
        $failures++;
    }
};

$startedAt = date('c');

if (!$jsonOutput) {
    echo "\nKlee Smoke Tests\n";
    echo str_repeat('-', 70) . "\n";
    echo "Base URL: {$baseUrl}\n";
    echo "Usuario: {$user}\n";
    echo str_repeat('-', 70) . "\n";
}

// 1) Login page
$loginUrl = $buildUrl(array('c' => 'login', 'a' => 'admin'));
$loginGet = $request('GET', $loginUrl);
if (!$loginGet['ok']) {
    $record('GET login', false, 'No se pudo conectar: ' . $loginGet['error'], $loginGet['time_ms']);
} else {
    $loginFormOk = ($loginGet['status'] === 200) && $containsAny($loginGet['body'], array('name="user"', 'Iniciar sesión'));
    $record('GET login', $loginFormOk, 'status=' . $loginGet['status'], $loginGet['time_ms']);
}

$csrfToken = $extractCsrf($loginGet['body'] ?? '');

// 2) Login POST
$loginPostUrl = $buildUrl(array('c' => 'login', 'a' => 'validate'));
$payload = array(
    '_csrf_token' => $csrfToken,
    'user' => $user,
    'pass' => $pass,
);
$loginPost = $request('POST', $loginPostUrl, $payload);
if (!$loginPost['ok']) {
    $record('POST login', false, 'Error HTTP: ' . $loginPost['error'], $loginPost['time_ms']);
} else {
    $isRedirect = in_array($loginPost['status'], array(301, 302, 303), true);
    $goesHome = stripos($loginPost['headers'], 'Location:') !== false && stripos($loginPost['headers'], 'c=home') !== false;
    $loginOk = $isRedirect && $goesHome;
    $record('POST login', $loginOk, 'status=' . $loginPost['status'], $loginPost['time_ms']);
}

// 3) Protected routes with authenticated cookie
$protectedRoutes = array(
    'GET home' => array('c' => 'home', 'a' => 'index'),
    'GET usuarios/list' => array('c' => 'usuarios', 'a' => 'list'),
    'GET roles/list' => array('c' => 'roles', 'a' => 'list'),
    'GET permisos/list' => array('c' => 'permisos', 'a' => 'list'),
    'GET alertas/list' => array('c' => 'alertas', 'a' => 'list'),
);

foreach ($protectedRoutes as $label => $params) {
    $routeUrl = $buildUrl($params);
    $res = $request('GET', $routeUrl);

    if (!$res['ok']) {
        $record($label, false, 'Error HTTP: ' . $res['error'], $res['time_ms']);
        continue;
    }

    $statusOk = ($res['status'] === 200);
    $notLoginScreen = !$containsAny($res['body'], array('name="user"', 'name="pass"', 'Iniciar sesión'));
    $layoutOk = $containsAny($res['body'], array('kt_content_container', 'kt_toolbar', 'card'));

    $ok = $statusOk && $notLoginScreen && $layoutOk;
    $detail = 'status=' . $res['status'];
    $record($label, $ok, $detail, $res['time_ms']);
}

if (!$jsonOutput) {
    foreach ($tests as $item) {
        $icon = $item['ok'] ? '[ok]' : '[fail]';
        echo sprintf("%s %-22s %6dms  %s\n", $icon, $item['name'], (int)$item['ms'], $item['detail']);
    }

    echo str_repeat('-', 70) . "\n";
    echo 'Resumen: total=' . count($tests) . ' fail=' . $failures . "\n";
}

$exitCode = ($failures > 0) ? 1 : 0;
$report = array(
    'ok' => $exitCode === 0,
    'base_url' => $baseUrl,
    'user' => $user,
    'started_at' => $startedAt,
    'ended_at' => date('c'),
    'summary' => array(
        'total' => count($tests),
        'failed' => $failures,
        'passed' => count($tests) - $failures,
    ),
    'tests' => $tests,
    'exit_code' => $exitCode,
);

if ($jsonFile !== '') {
    $jsonDir = dirname($jsonFile);
    if (!is_dir($jsonDir)) {
        @mkdir($jsonDir, 0755, true);
    }
    @file_put_contents($jsonFile, json_encode($report, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . PHP_EOL);
}

if ($jsonOutput) {
    echo json_encode($report, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . PHP_EOL;
}

exit($exitCode);
