<?php
/**
 * /api/dashboard/diagnostics.php
 *
 * Returns live status of the DMS stack for the current tenant:
 *   - MariaDB tenant tables (counts, FULLTEXT index)
 *   - Qdrant bnl_client_chunks collection (points)
 *   - LiteLLM embed endpoint (reachability + model)
 *   - FalkorDB dbn_client_graph (node count for this client)
 *   - On-disk storage usage
 *
 * GET → { ok, sections: [{key,label,value,status,detail}] }
 */

declare(strict_types=1);

require_once dirname(__DIR__, 2) . '/includes/bootstrap.php';

dbnToolsRequireAuth();

try {
    $tenant = dbnToolsEnsureDashboardTenant();
} catch (DbnToolsHttpException $e) {
    dbnToolsError($e->getMessage(), $e->status, $e->errorCode);
}
$clientId = (int)$tenant['client_id'];

$out = [];

/* MariaDB doc/chunk counts */
try {
    $db = dbnToolsDb();
    $docs = (int)$db->query("SELECT COUNT(*) FROM client_documents WHERE client_id = {$clientId} AND deleted_at IS NULL")->fetchColumn();
    $deleted = (int)$db->query("SELECT COUNT(*) FROM client_documents WHERE client_id = {$clientId} AND deleted_at IS NOT NULL")->fetchColumn();
    $chunks = 0;
    try {
        $chunks = (int)$db->query("SELECT COUNT(*) FROM client_chunks WHERE client_id = {$clientId}")->fetchColumn();
    } catch (Throwable $_) {}
    $out[] = ['key' => 'mariadb', 'label' => 'MariaDB (bnl_admin)',
              'value' => "{$docs} docs · {$chunks} chunks · {$deleted} trashed",
              'status' => 'ok',
              'detail' => 'chloe MySQL — client_documents + client_chunks tables'];
} catch (Throwable $e) {
    $out[] = ['key' => 'mariadb', 'label' => 'MariaDB', 'value' => 'unreachable', 'status' => 'err', 'detail' => $e->getMessage()];
}

/* FULLTEXT index presence */
try {
    $db = dbnToolsDb();
    $ft = $db->query("SHOW INDEX FROM client_chunks WHERE Key_name = 'ft_content'")->fetchAll();
    $out[] = ['key' => 'fulltext', 'label' => 'MariaDB FULLTEXT (BM25)',
              'value' => $ft ? 'present on client_chunks.content' : 'missing',
              'status' => $ft ? 'ok' : 'warn',
              'detail' => 'Required for hybrid keyword search; migration 007'];
} catch (Throwable $e) {
    $out[] = ['key' => 'fulltext', 'label' => 'MariaDB FULLTEXT', 'value' => '—', 'status' => 'warn', 'detail' => $e->getMessage()];
}

/* Qdrant — count vectors for this client via scroll */
try {
    $ch = curl_init('http://10.0.1.10:6333/collections/bnl_client_chunks/points/count');
    curl_setopt_array($ch, [
        CURLOPT_POST => true,
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 4,
        CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
        CURLOPT_POSTFIELDS => json_encode([
            'exact' => true,
            'filter' => [ 'must' => [ ['key' => 'client_id', 'match' => ['value' => $clientId]] ] ],
        ]),
    ]);
    $body = curl_exec($ch);
    $http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    if ($http === 200 && $body) {
        $j = json_decode($body, true);
        $cnt = (int)($j['result']['count'] ?? 0);
        $out[] = ['key' => 'qdrant', 'label' => 'Qdrant (bnl_client_chunks)',
                  'value' => $cnt . ' points',
                  'status' => 'ok',
                  'detail' => 'Colin Docker @ 10.0.2.10:6333, filtered by client_id'];
    } else {
        $out[] = ['key' => 'qdrant', 'label' => 'Qdrant', 'value' => 'http ' . $http, 'status' => 'warn', 'detail' => 'Not reachable from web container; vector search may fall back to MariaDB.'];
    }
} catch (Throwable $e) {
    $out[] = ['key' => 'qdrant', 'label' => 'Qdrant', 'value' => 'error', 'status' => 'err', 'detail' => $e->getMessage()];
}

/* LiteLLM embed endpoint */
try {
    $ch = curl_init('http://10.0.1.10:4000/v1/models');
    curl_setopt_array($ch, [
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT => 4,
        CURLOPT_HTTPHEADER => ['Authorization: Bearer sk-bnl-litellm-26xR9mK4qvN3wL8sTj7pB2d'],
    ]);
    $body = curl_exec($ch);
    $http = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);
    $hasEmbed = $body && strpos($body, 'nomic-embed') !== false;
    $out[] = ['key' => 'litellm', 'label' => 'LiteLLM (Colin)',
              'value' => $http === 200 ? ($hasEmbed ? 'reachable · nomic-embed-text registered' : 'reachable · embed model not found') : ('http ' . $http),
              'status' => $http === 200 ? ($hasEmbed ? 'ok' : 'warn') : 'warn',
              'detail' => 'http://10.0.1.10:4000 — chunker uses /v1/embeddings'];
} catch (Throwable $e) {
    $out[] = ['key' => 'litellm', 'label' => 'LiteLLM', 'value' => 'error', 'status' => 'err', 'detail' => $e->getMessage()];
}

/* FalkorDB nodes for this client */
try {
    $sock = @stream_socket_client('tcp://10.0.2.10:6379', $errno, $errstr, 2);
    if ($sock) {
        $cmd = "GRAPH.QUERY";
        $graph = "dbn_client_graph";
        $cypher = "MATCH (d:Document {client_id: {$clientId}}) RETURN count(d)";
        $payload = "*4\r\n$" . strlen($cmd) . "\r\n{$cmd}\r\n$" . strlen($graph) . "\r\n{$graph}\r\n$" . strlen($cypher) . "\r\n{$cypher}\r\n$8\r\n--compact\r\n";
        fwrite($sock, $payload);
        stream_set_timeout($sock, 2);
        $resp = @fread($sock, 8192);
        fclose($sock);
        $count = 0;
        if (preg_match('/(\d+)/', (string)$resp, $m)) $count = (int)$m[1];
        $out[] = ['key' => 'falkor', 'label' => 'FalkorDB (dbn_client_graph)',
                  'value' => $count . ' Document nodes',
                  'status' => 'ok',
                  'detail' => 'Colin @ 10.0.2.10:6379 — populated during ingest'];
    } else {
        $out[] = ['key' => 'falkor', 'label' => 'FalkorDB', 'value' => 'unreachable', 'status' => 'warn',
                  'detail' => 'Graph features hidden; ingest still works.'];
    }
} catch (Throwable $e) {
    $out[] = ['key' => 'falkor', 'label' => 'FalkorDB', 'value' => 'error', 'status' => 'warn', 'detail' => $e->getMessage()];
}

/* On-disk storage usage */
try {
    $root = dbnToolsEnv('DBN_TOOLS_UPLOAD_ROOT', '')
        ?: (is_dir('/home/dobetternorge/uploads') ? '/home/dobetternorge/uploads' : DBN_TOOLS_ROOT . '/uploads');
    $clientDir = rtrim($root, '/') . '/' . $clientId;
    $total = 0; $files = 0;
    if (is_dir($clientDir)) {
        $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($clientDir, FilesystemIterator::SKIP_DOTS));
        foreach ($it as $f) {
            if ($f->isFile()) { $total += $f->getSize(); $files++; }
        }
    }
    $human = $total < 1024*1024 ? round($total/1024) . ' KB'
            : ($total < 1024*1024*1024 ? round($total/1024/1024, 1) . ' MB' : round($total/1024/1024/1024, 2) . ' GB');
    $out[] = ['key' => 'storage', 'label' => 'Original file storage',
              'value' => $human . ' · ' . $files . ' files',
              'status' => is_dir($clientDir) ? 'ok' : 'warn',
              'detail' => $clientDir];
} catch (Throwable $e) {
    $out[] = ['key' => 'storage', 'label' => 'Storage', 'value' => 'error', 'status' => 'warn', 'detail' => $e->getMessage()];
}

dbnToolsRespond([
    'ok' => true,
    'tenant' => [
        'client_id' => $clientId,
        'corpus_id' => (int)$tenant['corpus_id'],
        'user_id'   => (int)$tenant['client_user_id'],
    ],
    'sections' => $out,
]);
