#!/usr/bin/env php
<?php
/**
 * Reservation Expiration Worker
 *
 * Cierra/expira reservas vencidas:
 *   - Pendientes (Estado=0) cuyo HoraInicio paso     -> Negada (5)
 *   - Confirmadas (1) sin entrega y HoraFin vencido  -> No asistio (4)
 *   - Confirmadas entregadas con HoraFin vencido     -> log warning
 *
 * Uso:
 *   php bin/expire-citas
 *   php bin/expire-citas --dry-run
 *   php bin/expire-citas --json
 *   php bin/expire-citas --confirmed-grace=15 --pending-grace=0 --return-grace=60
 *   php bin/expire-citas --batch=200
 *
 * Variables de entorno (override de defaults):
 *   CITAS_EXPIRE_PENDING_GRACE_MIN     (default: 0)
 *   CITAS_EXPIRE_CONFIRMED_GRACE_MIN   (default: 30)
 *   CITAS_EXPIRE_RETURN_GRACE_MIN      (default: 60)
 *   CITAS_EXPIRE_BATCH                 (default: 500)
 *
 * Programar via cron (ej. cada 5 min):
 *   * /5 * * * * php /ruta/timeklee2/bin/expire-citas --json >> /var/log/citas-expire.log 2>&1
 */

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

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

if (file_exists($basePath . '/app/config/Config.php')) {
    require $basePath . '/app/config/Config.php';
}
if (file_exists($basePath . '/app/config/ConfigEnv.php')) {
    require $basePath . '/app/config/ConfigEnv.php';
}

require_once $basePath . '/app/services/ReservationExpirationService.php';
require_once $basePath . '/app/services/ClientReservationPolicyService.php';
require_once $basePath . '/app/services/WaitlistService.php';

// ─── argumentos ─────────────────────────────────────────────────
$args = array_slice($argv, 1);
$opts = array(
    'dry-run' => false,
    'json' => false,
    'pending-grace' => null,
    'confirmed-grace' => null,
    'return-grace' => null,
    'batch' => null,
);

foreach ($args as $arg) {
    if ($arg === '--help' || $arg === '-h') {
        echo "\nReservation Expiration Worker\n";
        echo "Uso:\n";
        echo "  php bin/expire-citas [--dry-run] [--json] [--pending-grace=N] [--confirmed-grace=N] [--return-grace=N] [--batch=N]\n\n";
        exit(0);
    }
    if ($arg === '--dry-run') {
        $opts['dry-run'] = true;
        continue;
    }
    if ($arg === '--json') {
        $opts['json'] = true;
        continue;
    }
    foreach (array('pending-grace', 'confirmed-grace', 'return-grace', 'batch') as $key) {
        $prefix = '--' . $key . '=';
        if (strpos($arg, $prefix) === 0) {
            $opts[$key] = (int)substr($arg, strlen($prefix));
        }
    }
}

$envInt = function ($name, $default) {
    $v = getenv($name);
    if ($v === false || $v === '') {
        return $default;
    }
    return (int)$v;
};

$pendingGrace   = $opts['pending-grace']   !== null ? $opts['pending-grace']   : $envInt('CITAS_EXPIRE_PENDING_GRACE_MIN', 0);
$confirmedGrace = $opts['confirmed-grace'] !== null ? $opts['confirmed-grace'] : $envInt('CITAS_EXPIRE_CONFIRMED_GRACE_MIN', 30);
$returnGrace    = $opts['return-grace']    !== null ? $opts['return-grace']    : $envInt('CITAS_EXPIRE_RETURN_GRACE_MIN', 60);
$batchLimit     = $opts['batch']           !== null ? $opts['batch']           : $envInt('CITAS_EXPIRE_BATCH', 500);

// ─── conexion a BD (mismo patron que bin/migrate) ───────────────
$dbConfig = null;
if (class_exists('ConfigEnv') && property_exists('ConfigEnv', 'DB_CONNECTIONS')) {
    $connections = ConfigEnv::$DB_CONNECTIONS;
    if (isset($connections['klee'])) {
        $dbConfig = $connections['klee'];
    }
}
if (!$dbConfig) {
    $dbConfig = array(
        'driver' => getenv('DB_DRIVER') ?: 'mysql',
        'host' => getenv('DB_HOST') ?: 'localhost',
        'port' => getenv('DB_PORT') ?: '3306',
        'dbname' => getenv('DB_NAME') ?: '',
        'user' => getenv('DB_USER') ?: '',
        'password' => getenv('DB_PASS') ?: '',
    );
}

if (empty($dbConfig['host']) || empty($dbConfig['dbname']) || empty($dbConfig['user'])) {
    fwrite(STDERR, "[error] Configuracion de base de datos incompleta.\n");
    exit(1);
}

if (($dbConfig['driver'] ?? 'mysql') !== 'mysql') {
    fwrite(STDERR, "[error] Driver no soportado por este worker: " . $dbConfig['driver'] . "\n");
    exit(1);
}

try {
    $port = isset($dbConfig['port']) && $dbConfig['port'] !== '' ? $dbConfig['port'] : '3306';
    $dsn = "mysql:host={$dbConfig['host']};port={$port};dbname={$dbConfig['dbname']};charset=utf8mb4";
    $pdo = new PDO($dsn, $dbConfig['user'], $dbConfig['password']);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    $pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
} catch (PDOException $e) {
    fwrite(STDERR, "[error] No se pudo conectar a la base de datos: " . $e->getMessage() . "\n");
    exit(1);
}

// ─── ejecucion ──────────────────────────────────────────────────
$service = new ReservationExpirationService();
$service
    ->setDryRun($opts['dry-run'])
    ->setPendingGraceMinutes($pendingGrace)
    ->setConfirmedGraceMinutes($confirmedGrace)
    ->setOverdueReturnGraceMinutes($returnGrace)
    ->setBatchLimit($batchLimit);

// El policy service necesita la misma conexion para autobloqueos.
ClientReservationPolicyService::setPdo($pdo);
WaitlistService::setPdo($pdo);

$startedAt = microtime(true);
try {
    $stats = $service->run($pdo);
} catch (Throwable $e) {
    fwrite(STDERR, "[error] Falla en worker de expiracion: " . $e->getMessage() . "\n");
    exit(2);
}
$elapsedMs = (int)round((microtime(true) - $startedAt) * 1000);

$payload = array(
    'ok' => true,
    'dry_run' => (bool)$opts['dry-run'],
    'elapsed_ms' => $elapsedMs,
    'thresholds' => array(
        'pending_grace_min' => $pendingGrace,
        'confirmed_grace_min' => $confirmedGrace,
        'return_grace_min' => $returnGrace,
        'batch_limit' => $batchLimit,
    ),
    'stats' => $stats,
);

if ($opts['json']) {
    echo json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . PHP_EOL;
} else {
    $tag = $opts['dry-run'] ? '[DRY-RUN]' : '[OK]';
    echo "{$tag} Reservation expiration worker\n";
    echo "  Pending expired (-> Negada):       " . (int)$stats['pending_expired'] . "\n";
    echo "  Confirmed no-show (-> No asistio): " . (int)$stats['confirmed_no_show'] . "\n";
    echo "  Overdue returns (warned):          " . (int)$stats['overdue_return_warned'] . "\n";
    echo "  Clients auto-blocked (no-show):    " . (int)($stats['clients_auto_blocked'] ?? 0) . "\n";
    echo "  Waitlist notified:                 " . (int)($stats['waitlist_notified'] ?? 0) . "\n";
    echo "  Errors:                            " . (int)$stats['errors'] . "\n";
    echo "  Elapsed:                           {$elapsedMs} ms\n";
}

exit($stats['errors'] > 0 ? 3 : 0);
