<?php

declare(strict_types=1);

require_once __DIR__ . '/../init.php';
require_once __DIR__ . '/../../lib/SubscriptionService.php';

/**
 * Respuesta JSON corta y cerrada explícitamente. Algunos servidores compartidos
 * conservan la conexión abierta aunque la transacción ya terminó; Content-Length
 * y el vaciado de buffers permiten que el navegador reciba el resultado de inmediato.
 */
function af_renewal_json(array $payload, int $status = 200): never
{
    if (session_status() === PHP_SESSION_ACTIVE) {
        session_write_close();
    }

    while (ob_get_level() > 0) {
        @ob_end_clean();
    }

    $json = json_encode($payload, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    if (!is_string($json)) {
        $status = 500;
        $json = '{"success":false,"message":"No fue posible generar la respuesta del servidor."}';
    }

    if (!headers_sent()) {
        http_response_code($status);
        header('Content-Type: application/json; charset=utf-8');
        header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
        header('X-Content-Type-Options: nosniff');
        header('Content-Length: ' . strlen($json));
        header('Connection: close');
    }

    echo $json;
    @flush();
    if (function_exists('fastcgi_finish_request')) {
        @fastcgi_finish_request();
    }
    exit;
}

Security::headers(true);

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    af_renewal_json(['success' => false, 'message' => 'Método no permitido.'], 405);
}

Security::requireCsrf();

$role = mb_strtolower(trim((string) ($_SESSION['admin']['rol'] ?? '')), 'UTF-8');
$registeredBy = (int) ($_SESSION['admin']['uid'] ?? 0);
if ($role !== 'superadmin' || $registeredBy <= 0) {
    af_renewal_json(['success' => false, 'message' => 'Solo el Superadmin puede registrar renovaciones desde este módulo.'], 403);
}

$action = trim((string) ($_POST['action'] ?? 'guardar_pago'));
$idempotency = trim((string) ($_POST['payment_key'] ?? $_POST['clave_idempotencia'] ?? ''));

// No conservar el bloqueo de la sesión durante consultas o transacciones.
if (session_status() === PHP_SESSION_ACTIVE) {
    session_write_close();
}

@ignore_user_abort(true);
@set_time_limit(20);

try {
    $service = new SubscriptionService($pdo);

    if ($action === 'consultar_pago') {
        if (!preg_match('/^[A-Za-z0-9_-]{16,64}$/', $idempotency)) {
            throw new InvalidArgumentException('La clave de seguimiento no es válida.');
        }
        $existing = $service->findByIdempotency($idempotency, $registeredBy);
        af_renewal_json([
            'success' => true,
            'processed' => $existing !== null,
            'result' => $existing,
        ]);
    }

    if ($action !== 'guardar_pago') {
        throw new InvalidArgumentException('La acción solicitada no está disponible.');
    }

    $result = $service->registerPaymentAndRenew($_POST, $registeredBy);
    $newEnd = !empty($result['new_end_date']) && strtotime((string) $result['new_end_date']) !== false
        ? date('d/m/Y', strtotime((string) $result['new_end_date']))
        : 'la fecha registrada';

    af_renewal_json([
        'success' => true,
        'message' => !empty($result['duplicate'])
            ? 'La renovación ya había sido registrada. La vigencia termina el ' . $newEnd . '.'
            : 'Pago registrado. La nueva vigencia termina el ' . $newEnd . '.',
        'new_end_date' => $result['new_end_date'] ?? null,
        'payment_id' => $result['payment_id'] ?? null,
        'duplicate' => (bool) ($result['duplicate'] ?? false),
        'referral_job' => $result['referral_job'] ?? null,
    ]);
} catch (PDOException $e) {
    $message = match ((string) $e->getCode()) {
        '40001', 'HY000' => 'La base de datos estaba ocupada con otra operación. Espera unos segundos y vuelve a intentarlo.',
        default => APP_DEBUG ? $e->getMessage() : 'No fue posible registrar la renovación en la base de datos.',
    };
    af_renewal_json(['success' => false, 'message' => $message], 409);
} catch (Throwable $e) {
    af_renewal_json(['success' => false, 'message' => $e->getMessage()], 422);
}
