#!/usr/bin/env php
<?php
/**
 * Mail Queue Processor CLI
 *
 * Uso:
 *   php bin/process-mail-queue
 *   php bin/process-mail-queue --limit=50
 *   php bin/process-mail-queue --dry-run
 *   php bin/process-mail-queue --help
 */

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

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

if (file_exists($basePath . '/vendor/autoload.php')) {
    require $basePath . '/vendor/autoload.php';
}

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 $basePath . '/core/MailService.php';

$args = array_slice($argv, 1);

if (in_array('--help', $args, true) || in_array('-h', $args, true)) {
    echo "\nKlee Mail Queue Processor\n";
    echo "Uso:\n";
    echo "  php bin/process-mail-queue\n";
    echo "  php bin/process-mail-queue --limit=50\n";
    echo "  php bin/process-mail-queue --dry-run\n\n";
    echo "Opciones:\n";
    echo "  --limit=N    Máximo de mensajes a procesar (default: 100)\n";
    echo "  --dry-run    No envía; solo valida y marca como procesado simulado\n";
    exit(0);
}

$limit = 100;
$dryRun = in_array('--dry-run', $args, true);

foreach ($args as $arg) {
    if (strpos($arg, '--limit=') === 0) {
        $limitValue = (int)substr($arg, 8);
        if ($limitValue > 0) {
            $limit = $limitValue;
        }
    }
}

$queueDir = $basePath . '/storage/pendientes';
$queueFile = $queueDir . '/mail_queue.jsonl';
$processedDir = $queueDir . '/processed';

if (!is_dir($queueDir)) {
    echo "[ok] No existe directorio de cola ({$queueDir}). Nada por procesar.\n";
    exit(0);
}

if (!is_file($queueFile)) {
    echo "[ok] No existe archivo de cola ({$queueFile}). Nada por procesar.\n";
    exit(0);
}

if (!is_dir($processedDir) && !@mkdir($processedDir, 0775, true) && !is_dir($processedDir)) {
    echo "[error] No fue posible crear directorio de procesados: {$processedDir}\n";
    exit(2);
}

$defaultMailConfig = array();
if (class_exists('ConfigEnv') && method_exists('ConfigEnv', 'getEmailSendConfig')) {
    $defaultMailConfig = ConfigEnv::getEmailSendConfig();
} elseif (class_exists('Config') && method_exists('Config', 'getEmailSendConfig')) {
    $defaultMailConfig = Config::getEmailSendConfig();
}

$appendArchive = function ($status, $record) use ($processedDir) {
    $safeStatus = preg_replace('/[^a-z0-9_-]+/i', '_', (string)$status);
    $archiveFile = $processedDir . '/mail_' . $safeStatus . '_' . date('Ymd') . '.jsonl';
    $line = json_encode($record, JSON_UNESCAPED_UNICODE) . PHP_EOL;
    return file_put_contents($archiveFile, $line, FILE_APPEND | LOCK_EX) !== false;
};

$normalizeOptions = function ($value) {
    if (!is_array($value)) {
        return array('isHtml' => true);
    }

    // Los payloads actuales usan metadata para opciones de MailService::send().
    if (!array_key_exists('isHtml', $value)) {
        $value['isHtml'] = true;
    }

    return $value;
};

$processed = 0;
$sent = 0;
$failed = 0;
$invalid = 0;
$left = 0;

$fh = fopen($queueFile, 'c+');
if ($fh === false) {
    echo "[error] No fue posible abrir el archivo de cola: {$queueFile}\n";
    exit(2);
}

try {
    if (!flock($fh, LOCK_EX)) {
        echo "[error] No fue posible obtener lock exclusivo de la cola.\n";
        fclose($fh);
        exit(2);
    }

    rewind($fh);
    $raw = stream_get_contents($fh);
    $allLines = preg_split('/\r\n|\r|\n/', (string)$raw);
    $allLines = is_array($allLines) ? $allLines : array();

    // Quitar línea vacía final para evitar contar registros fantasma.
    if (!empty($allLines) && trim((string)end($allLines)) === '') {
        array_pop($allLines);
    }

    $toProcess = array_slice($allLines, 0, $limit);
    $remaining = array_slice($allLines, count($toProcess));

    foreach ($toProcess as $lineNumber => $line) {
        $line = trim((string)$line);
        if ($line === '') {
            continue;
        }

        $processed++;
        $decoded = json_decode($line, true);

        if (!is_array($decoded)) {
            $invalid++;
            $appendArchive('invalid', array(
                'status' => 'invalid',
                'processed_at' => date('c'),
                'error' => 'JSON inválido en cola.',
                'line_number' => $lineNumber + 1,
                'raw_line' => $line,
            ));
            continue;
        }

        $to = $decoded['to'] ?? array();
        $subject = $decoded['subject'] ?? '';
        $body = $decoded['body'] ?? '';
        $mailConfig = isset($decoded['config']) && is_array($decoded['config']) ? $decoded['config'] : array();
        $options = $normalizeOptions($decoded['metadata'] ?? array());

        if (empty($mailConfig)) {
            $mailConfig = $defaultMailConfig;
        }

        if ($dryRun) {
            $sent++;
            $appendArchive('dryrun', array(
                'status' => 'dryrun',
                'processed_at' => date('c'),
                'payload' => $decoded,
                'result' => array('success' => true, 'message' => 'Simulación --dry-run'),
            ));
            continue;
        }

        $result = MailService::send($to, $subject, $body, $mailConfig, $options);
        $ok = isset($result['success']) && $result['success'];

        if ($ok) {
            $sent++;
            $appendArchive('sent', array(
                'status' => 'sent',
                'processed_at' => date('c'),
                'payload' => $decoded,
                'result' => $result,
            ));
        } else {
            $failed++;
            $appendArchive('failed', array(
                'status' => 'failed',
                'processed_at' => date('c'),
                'payload' => $decoded,
                'result' => $result,
            ));
        }
    }

    $left = count($remaining);

    rewind($fh);
    ftruncate($fh, 0);

    if ($left > 0) {
        fwrite($fh, implode(PHP_EOL, $remaining) . PHP_EOL);
    }

    fflush($fh);
    flock($fh, LOCK_UN);
    fclose($fh);
} catch (Exception $e) {
    if (is_resource($fh)) {
        @flock($fh, LOCK_UN);
        @fclose($fh);
    }

    echo "[error] Excepción al procesar la cola: " . $e->getMessage() . "\n";
    exit(2);
}

echo "[ok] Proceso finalizado.\n";
echo "  procesados: {$processed}\n";
echo "  enviados: {$sent}\n";
echo "  fallidos: {$failed}\n";
echo "  inválidos: {$invalid}\n";
echo "  pendientes: {$left}\n";

if ($failed > 0 || $invalid > 0) {
    exit(1);
}

exit(0);
