#!/usr/bin/env php
<?php
require_once __DIR__ . '/../includes/db.php';
require_once __DIR__ . '/../includes/settings.php';
require_once __DIR__ . '/../includes/util.php';
require_once __DIR__ . '/../includes/helpers.php';
require_once __DIR__ . '/../includes/mailer.php';

$limit = (int)($argv[1] ?? 50);
if ($limit <= 0) $limit = 50;

$pdo = pdo();
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$lockName = 'cartas_informativas_worker';
$got = $pdo->query("SELECT GET_LOCK(" . $pdo->quote($lockName) . ", 1)")->fetchColumn();
if ((int)$got !== 1) { fwrite(STDERR, "No lock\n"); exit(0); }

try {
    $job = $pdo->query("SELECT * FROM cartas_jobs WHERE status IN ('queued','running','cancel_requested') ORDER BY id ASC LIMIT 1")->fetch(PDO::FETCH_ASSOC);
    if (!$job) exit(0);

    $jobId = (int)$job['id'];
    if ($job['status'] === 'queued') {
        $pdo->prepare("UPDATE cartas_jobs SET status='running', started_at=NOW(), last_heartbeat_at=NOW(), last_message='Iniciando' WHERE id=?")->execute([$jobId]);
        $job['status'] = 'running';
    }
    if ($job['status'] === 'cancel_requested') {
        $pdo->prepare("UPDATE cartas_jobs SET status='cancelled', finished_at=NOW(), last_message='Cancelado por usuario' WHERE id=?")->execute([$jobId]);
        exit(0);
    }

    $stItems = $pdo->prepare("SELECT * FROM cartas_job_items WHERE job_id=? AND status='pending' ORDER BY id ASC LIMIT ?");
    $stItems->bindValue(1, $jobId, PDO::PARAM_INT);
    $stItems->bindValue(2, $limit, PDO::PARAM_INT);
    $stItems->execute();
    $items = $stItems->fetchAll(PDO::FETCH_ASSOC);

    if (!$items) {
        $pdo->prepare("UPDATE cartas_jobs SET status='finished', finished_at=NOW(), last_heartbeat_at=NOW(), last_message='Finalizado' WHERE id=?")->execute([$jobId]);
        exit(0);
    }

    $minMs = max(0, (int)(setting_get('throttle_min_ms','3500') ?? 3500));
    $maxMs = max($minMs, (int)(setting_get('throttle_max_ms','6500') ?? 6500));
    $mailer = new CartasMailer();
    $campaignCode = (string)$job['campaign_code'];

    foreach ($items as $it) {
        $pdo->prepare("UPDATE cartas_jobs SET last_heartbeat_at=NOW() WHERE id=?")->execute([$jobId]);
        $st = $pdo->prepare("SELECT status FROM cartas_jobs WHERE id=?");
        $st->execute([$jobId]);
        if ((string)$st->fetchColumn() === 'cancel_requested') {
            $pdo->prepare("UPDATE cartas_jobs SET status='cancelled', finished_at=NOW(), last_message='Cancelado por usuario', last_heartbeat_at=NOW() WHERE id=?")->execute([$jobId]);
            break;
        }

        $itemId = (int)$it['id'];
        $nif = (string)$it['nif'];
        $email = (string)$it['email'];
        $pdfPath = (string)($it['pdf_path'] ?? '');
        if ($pdfPath === '' || !is_file($pdfPath) || !is_readable($pdfPath)) {
            $pdfPath = cartas_find_pdf_for_nif($nif) ?? '';
        }

        if ($pdfPath === '') {
            $pdo->prepare("UPDATE cartas_job_items SET status='missing_pdf', error_code='missing_pdf', error_msg='PDF no encontrado' WHERE id=?")->execute([$itemId]);
            $pdo->prepare("UPDATE cartas_jobs SET counts_missing_pdf=counts_missing_pdf+1, counts_pending=GREATEST(counts_pending-1,0), last_message='PDF no encontrado' WHERE id=?")->execute([$jobId]);
            continue;
        }

        $htmlRendered = cartas_render_template((string)$job['email_html'], [
            'nif' => $nif,
            'email' => $email,
            'campaign_code' => $campaignCode,
            'fecha_hoy' => date('d/m/Y'),
        ]);
        $subjectRendered = strtr((string)$job['email_subject'], [
            '{{NIF}}'=>$nif,
            '{{EMAIL}}'=>$email,
            '{{CAMPAIGN_CODE}}'=>$campaignCode,
            '{{FECHA_HOY}}'=>date('d/m/Y'),
        ]);

        try {
            $mailer->sendWithAttachment($email, $subjectRendered, $htmlRendered, $pdfPath, basename($pdfPath));

            try {
                $ins = $pdo->prepare("INSERT INTO cartas_sent_registry
                    (nif,campaign_code,sent_at,origin_type,origin_id,sent_by,sent_by_name,email,pdf_path,created_at)
                    VALUES (?,?,NOW(),'job',?,?,?,?,?,NOW())");
                $ins->execute([$nif, $campaignCode, $itemId, $job['created_by'], $job['created_by_name'], $email, $pdfPath]);

                $pdo->prepare("UPDATE cartas_job_items SET status='sent', sent_at=NOW(), pdf_filename=?, pdf_path=?, error_code=NULL, error_msg=NULL WHERE id=?")
                    ->execute([basename($pdfPath), $pdfPath, $itemId]);
                $pdo->prepare("UPDATE cartas_jobs SET counts_sent=counts_sent+1, counts_pending=GREATEST(counts_pending-1,0), last_message='Enviado' WHERE id=?")->execute([$jobId]);
            } catch (Throwable $dup) {
                $pdo->prepare("UPDATE cartas_job_items SET status='already_sent', error_code='already_sent', error_msg='Ya enviado en esta campana', pdf_filename=?, pdf_path=? WHERE id=?")
                    ->execute([basename($pdfPath), $pdfPath, $itemId]);
                $pdo->prepare("UPDATE cartas_jobs SET counts_already_sent=counts_already_sent+1, counts_pending=GREATEST(counts_pending-1,0), last_message='Ya enviado' WHERE id=?")->execute([$jobId]);
            }

            if ($maxMs > 0) {
                $ms = ($maxMs === $minMs) ? $minMs : random_int($minMs, $maxMs);
                usleep($ms * 1000);
            }
        } catch (Throwable $e) {
            $pdo->prepare("UPDATE cartas_job_items SET status='smtp_error', error_code='smtp_error', error_msg=? WHERE id=?")
                ->execute([substr($e->getMessage(), 0, 255), $itemId]);
            $pdo->prepare("UPDATE cartas_jobs SET counts_smtp_error=counts_smtp_error+1, counts_pending=GREATEST(counts_pending-1,0), last_message='Error SMTP' WHERE id=?")->execute([$jobId]);
        }
    }

    $stp = $pdo->prepare("SELECT COUNT(*) FROM cartas_job_items WHERE job_id=? AND status='pending'");
    $stp->execute([$jobId]);
    $pendingLeft = (int)$stp->fetchColumn();
    $pdo->prepare("UPDATE cartas_jobs SET counts_pending=?, last_heartbeat_at=NOW() WHERE id=?")->execute([$pendingLeft, $jobId]);
    if ($pendingLeft === 0) {
        $pdo->prepare("UPDATE cartas_jobs SET status='finished', finished_at=NOW(), last_message='Finalizado', last_heartbeat_at=NOW() WHERE id=? AND status='running'")->execute([$jobId]);
    }
} finally {
    $pdo->query("SELECT RELEASE_LOCK(" . $pdo->quote($lockName) . ")");
}
