<?php
declare(strict_types=1);

/**
 * SCLS Audit Decrypt — POST /api/audit/decrypt.php
 *
 * Dashboard-facing API: decrypts an individual audit entry.
 * Requires admin role, rate limiting, and logs every decryption.
 * Auth: dashboard session (AuthChain) + RBAC admin role.
 */

define('DASHBOARD_ROOT', realpath(__DIR__ . '/../..'));
require_once DASHBOARD_ROOT . '/core/bootstrap.php';

// ── Auth gate ─────────────────────────────────────────────────────────────
if (!AuthChain::isAuthenticated()) {
    http_response_code(401);
    header('Content-Type: application/json');
    exit(json_encode(['status' => 'error', 'error' => 'Unauthorized']));
}

RBAC::enforce('decrypt.pii');
header('Content-Type: application/json');

if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit(json_encode(['status' => 'error', 'error' => 'Method not allowed']));
}

// ── Load SCLS security classes ────────────────────────────────────────────
require_once DASHBOARD_ROOT . '/security/DecryptionService.php';
require_once DASHBOARD_ROOT . '/security/AuditRateLimiter.php';

// ── Parse request ─────────────────────────────────────────────────────────
$rawBody = file_get_contents('php://input');
$input   = json_decode($rawBody, true);

if (!$input || empty($input['audit_id']) || empty($input['reason'])) {
    http_response_code(400);
    exit(json_encode(['status' => 'error', 'error' => 'Missing audit_id or reason']));
}

$auditId = (int)$input['audit_id'];
$reason  = trim(substr($input['reason'], 0, 500));

if ($auditId <= 0) {
    http_response_code(400);
    exit(json_encode(['status' => 'error', 'error' => 'Invalid audit_id']));
}

if (strlen($reason) < 10) {
    http_response_code(400);
    exit(json_encode(['status' => 'error', 'error' => 'Reason must be at least 10 characters']));
}

$adminId = (string)($_SESSION['admin_id'] ?? '');
if (!$adminId) {
    http_response_code(403);
    exit(json_encode(['status' => 'error', 'error' => 'No admin session']));
}

// ── Engine DB connection ──────────────────────────────────────────────────
function getEngineDbDecrypt(): PDO
{
    static $pdo = null;
    if ($pdo !== null) return $pdo;

    $host   = '172.28.41.2';
    $port   = 3306;
    $dbname = 'engine';
    $user   = 'dashboard';
    $pass   = '';

    if (class_exists('CredentialStore')) {
        try {
            $creds = CredentialStore::get('engine_db');
            if ($creds) {
                $host = $creds['host'] ?? $host;
                $port = (int)($creds['port'] ?? $port);
                $user = $creds['user'] ?? $user;
                $pass = $creds['pass'] ?? $pass;
            }
        } catch (\Throwable $e) {}
    }

    $envFile = '/var/www/private/engine_db.env';
    if ($pass === '' && file_exists($envFile)) {
        $lines = file($envFile, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
        foreach ($lines as $line) {
            if (str_starts_with(trim($line), '#')) continue;
            [$k, $v] = explode('=', $line, 2) + ['', ''];
            $k = trim($k);
            $v = trim($v, " \t\n\r\"'");
            match ($k) {
                'ENGINE_DB_HOST' => $host = $v,
                'ENGINE_DB_PORT' => $port = (int)$v,
                'ENGINE_DB_USER' => $user = $v,
                'ENGINE_DB_PASS' => $pass = $v,
                'ENGINE_DB_NAME' => $dbname = $v,
                default          => null,
            };
        }
    }

    $dsn = "mysql:host={$host};port={$port};dbname={$dbname};charset=utf8mb4";
    $pdo = new PDO($dsn, $user, $pass, [
        PDO::ATTR_ERRMODE            => PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES   => false,
        PDO::ATTR_TIMEOUT            => 10,
    ]);
    return $pdo;
}

try {
    $engineDb = getEngineDbDecrypt();
} catch (\Throwable $e) {
    http_response_code(500);
    exit(json_encode(['status' => 'error', 'error' => 'Engine DB unavailable']));
}

// ── Rate limit check ──────────────────────────────────────────────────────
$rateLimiter = new AuditRateLimiter($engineDb);

if (!$rateLimiter->check($adminId)) {
    $stats = $rateLimiter->getStats($adminId);
    http_response_code(429);
    exit(json_encode([
        'status'    => 'error',
        'error'     => 'Decryption rate limit exceeded (10/min)',
        'remaining' => 0,
        'limit'     => $stats['limit'],
        'retry_in'  => 60 - (time() % 60),
    ]));
}

// ── Fetch audit entry ─────────────────────────────────────────────────────
$stmt = $engineDb->prepare(
    'SELECT id, event_uuid, node_id, tool_id, tool_name, tool_category,
            encrypted_statement, encryption_iv, encryption_version,
            hmac_signature, session_id, admin_id, status, severity,
            started_at, completed_at
     FROM sec_audit_log
     WHERE id = ?
     LIMIT 1'
);
$stmt->execute([$auditId]);
$auditEntry = $stmt->fetch();

if (!$auditEntry) {
    http_response_code(404);
    exit(json_encode(['status' => 'error', 'error' => 'Audit entry not found']));
}

// ── Decrypt ───────────────────────────────────────────────────────────────
$decryptionService = new DecryptionService($engineDb);

try {
    $result = $decryptionService->decrypt($auditEntry);
} catch (\RuntimeException $e) {
    http_response_code(422);
    exit(json_encode([
        'status' => 'error',
        'error'  => 'Decryption failed: ' . $e->getMessage(),
    ]));
}

// ── Increment rate limiter ────────────────────────────────────────────────
$rateLimiter->increment($adminId);

// ── Log decryption to sec_audit_decryptions ───────────────────────────────
try {
    $logStmt = $engineDb->prepare(
        'INSERT INTO sec_audit_decryptions (audit_id, admin_id, reason, ip_address, user_agent, decrypted_at)
         VALUES (?, ?, ?, ?, ?, NOW())'
    );
    $logStmt->execute([
        $auditId,
        $adminId,
        $reason,
        $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0',
        substr($_SERVER['HTTP_USER_AGENT'] ?? '', 0, 300),
    ]);
} catch (\Throwable $e) {
    // Non-fatal: decryption succeeds even if logging fails,
    // but we still return the result
}

// ── Log to dashboard events if available ──────────────────────────────────
if (class_exists('Events')) {
    try {
        Events::record(Events::CAT_SECURITY, 'audit.decrypt', 'audit', (string)$auditId, [
            'admin_id' => $adminId,
            'node_id'  => $auditEntry['node_id'],
            'tool_id'  => $auditEntry['tool_id'],
            'reason'   => $reason,
        ]);
    } catch (\Throwable $e) {}
}

// ── Response ──────────────────────────────────────────────────────────────
$rlStats = $rateLimiter->getStats($adminId);

echo json_encode([
    'status'     => 'ok',
    'data'       => [
        'decrypted'  => $result,
        'audit_meta' => [
            'id'         => $auditEntry['id'],
            'event_uuid' => $auditEntry['event_uuid'],
            'node_id'    => $auditEntry['node_id'],
            'tool_id'    => $auditEntry['tool_id'],
            'tool_name'  => $auditEntry['tool_name'],
            'status'     => $auditEntry['status'],
            'severity'   => $auditEntry['severity'],
            'started_at' => $auditEntry['started_at'],
        ],
        'rate_limit' => [
            'remaining' => $rlStats['remaining'],
            'limit'     => $rlStats['limit'],
            'total'     => $rlStats['total'],
        ],
    ],
    'ts' => date('c'),
], JSON_PRETTY_PRINT);
