<?php
/**
 * api_public.php — API REST pública do MonitorPing
 * Autenticação via Bearer Token (tabela api_tokens)
 *
 * Endpoints:
 *   GET  /api_public.php/hosts           → lista hosts do usuário
 *   GET  /api_public.php/hosts/{id}      → detalhe de um host
 *   GET  /api_public.php/hosts/{id}/logs → logs de ping (últimas 24h)
 *   GET  /api_public.php/stats           → estatísticas gerais
 *   GET  /api_public.php/tags            → lista de tags
 */

require_once __DIR__ . '/db.php';
require_once __DIR__ . '/includes/functions.php';

header('Content-Type: application/json; charset=UTF-8');
header('X-Content-Type-Options: nosniff');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: GET, OPTIONS');
header('Access-Control-Allow-Headers: Authorization, Content-Type');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
    http_response_code(204);
    exit;
}

// ── Autenticação por Bearer Token ─────────────────────────────────────────────
function api_error(int $code, string $message): void {
    http_response_code($code);
    echo json_encode(['error' => $message], JSON_UNESCAPED_UNICODE);
    exit;
}

function api_response(array $data, int $code = 200): void {
    http_response_code($code);
    echo json_encode($data, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
    exit;
}

$authHeader = $_SERVER['HTTP_AUTHORIZATION'] ?? '';
if (!preg_match('/^Bearer\s+(.+)$/i', $authHeader, $m)) {
    api_error(401, 'Token de autorização ausente. Use o header: Authorization: Bearer SEU_TOKEN');
}
$rawToken = trim($m[1]);

$pdo = db();
$tokenStmt = $pdo->prepare("
    SELECT t.*, u.id AS user_id, u.name AS user_name, u.role
    FROM api_tokens t
    JOIN users u ON u.id = t.user_id
    WHERE t.token = ? AND t.active = TRUE AND u.active = TRUE
    LIMIT 1
");
$tokenStmt->execute([$rawToken]);
$tokenRow = $tokenStmt->fetch();

if (!$tokenRow) {
    api_error(401, 'Token inválido ou inativo.');
}

// Atualiza last_used_at
$pdo->prepare("UPDATE api_tokens SET last_used_at = NOW() WHERE id = ?")->execute([$tokenRow['id']]);

$userId = (int)$tokenRow['user_id'];

// ── Roteamento ────────────────────────────────────────────────────────────────
$path = $_SERVER['PATH_INFO'] ?? ($_GET['path'] ?? '/');
$path = '/' . ltrim($path, '/');
$method = $_SERVER['REQUEST_METHOD'];

// GET /hosts
if ($path === '/hosts' && $method === 'GET') {
    $tag = $_GET['tag'] ?? null;
    $status = $_GET['status'] ?? null;

    $sql = "
        SELECT mi.id, mi.label, mi.host, mi.check_method, mi.interval_seconds,
               mi.last_status, mi.last_latency_ms, mi.last_check_at,
               mi.active, mi.ssl_expires_at, mi.ssl_check_enabled,
               COALESCE(
                   (SELECT json_agg(t.name ORDER BY t.name)
                    FROM ip_tags it JOIN tags t ON t.id = it.tag_id
                    WHERE it.monitored_ip_id = mi.id), '[]'::json
               ) AS tags
        FROM monitored_ips mi
        WHERE mi.user_id = ?
    ";
    $params = [$userId];

    if ($status && in_array($status, ['online','offline','unknown'], true)) {
        $sql .= " AND mi.last_status = ?";
        $params[] = $status;
    }

    if ($tag) {
        $sql .= " AND EXISTS (
            SELECT 1 FROM ip_tags it2 JOIN tags t2 ON t2.id = it2.tag_id
            WHERE it2.monitored_ip_id = mi.id AND t2.name = ?
        )";
        $params[] = $tag;
    }

    $sql .= " ORDER BY mi.label ASC";
    $stmt = $pdo->prepare($sql);
    $stmt->execute($params);
    $hosts = $stmt->fetchAll();

    foreach ($hosts as &$h) {
        $h['tags'] = json_decode($h['tags'] ?? '[]', true) ?: [];
        $h['last_check_at_iso'] = $h['last_check_at'] ?? null;
        $h['ssl_days_left'] = null;
        if ($h['ssl_expires_at']) {
            $exp = new DateTimeImmutable($h['ssl_expires_at']);
            $h['ssl_days_left'] = (int)(new DateTimeImmutable())->diff($exp)->days * ($exp > new DateTimeImmutable() ? 1 : -1);
        }
    }

    api_response([
        'data'  => $hosts,
        'count' => count($hosts),
        'meta'  => ['user' => $tokenRow['user_name'], 'generated_at' => date('c')]
    ]);
}

// GET /hosts/{id}
if (preg_match('#^/hosts/(\d+)$#', $path, $pm) && $method === 'GET') {
    $ipId = (int)$pm[1];
    $stmt = $pdo->prepare("
        SELECT mi.*, 
               COALESCE(
                   (SELECT json_agg(t.name ORDER BY t.name)
                    FROM ip_tags it JOIN tags t ON t.id = it.tag_id
                    WHERE it.monitored_ip_id = mi.id), '[]'::json
               ) AS tags
        FROM monitored_ips mi
        WHERE mi.id = ? AND mi.user_id = ? LIMIT 1
    ");
    $stmt->execute([$ipId, $userId]);
    $host = $stmt->fetch();
    if (!$host) api_error(404, 'Host não encontrado.');

    // Uptime 24h
    $upStmt = $pdo->prepare("
        SELECT ROUND(100.0 * SUM(CASE WHEN status='online' THEN 1 ELSE 0 END) / NULLIF(COUNT(*),0), 2) AS uptime_24h,
               ROUND(AVG(latency_ms) FILTER (WHERE status='online'), 1) AS avg_latency_24h
        FROM ping_logs WHERE monitored_ip_id = ? AND checked_at >= NOW() - INTERVAL '1 day'
    ");
    $upStmt->execute([$ipId]);
    $upRow = $upStmt->fetch();

    $host['tags'] = json_decode($host['tags'] ?? '[]', true) ?: [];
    $host['uptime_24h'] = $upRow['uptime_24h'] ? (float)$upRow['uptime_24h'] : null;
    $host['avg_latency_24h'] = $upRow['avg_latency_24h'] ? (float)$upRow['avg_latency_24h'] : null;

    api_response(['data' => $host]);
}

// GET /hosts/{id}/logs
if (preg_match('#^/hosts/(\d+)/logs$#', $path, $pm) && $method === 'GET') {
    $ipId = (int)$pm[1];
    $hours = min(168, max(1, (int)($_GET['hours'] ?? 24)));

    $ipCheck = $pdo->prepare("SELECT id FROM monitored_ips WHERE id = ? AND user_id = ?");
    $ipCheck->execute([$ipId, $userId]);
    if (!$ipCheck->fetch()) api_error(404, 'Host não encontrado.');

    $logs = $pdo->prepare("
        SELECT id, status, latency_ms, checked_at
        FROM ping_logs
        WHERE monitored_ip_id = ? AND checked_at >= NOW() - INTERVAL '1 hour' * ?
        ORDER BY checked_at DESC
        LIMIT 1000
    ");
    $logs->execute([$ipId, $hours]);

    api_response([
        'data'  => $logs->fetchAll(),
        'hours' => $hours,
        'host_id' => $ipId
    ]);
}

// GET /stats
if ($path === '/stats' && $method === 'GET') {
    $s = $pdo->prepare("
        SELECT
            COUNT(*) AS total_hosts,
            SUM(CASE WHEN last_status='online' THEN 1 ELSE 0 END) AS online,
            SUM(CASE WHEN last_status='offline' THEN 1 ELSE 0 END) AS offline,
            SUM(CASE WHEN last_status='unknown' THEN 1 ELSE 0 END) AS unknown,
            SUM(CASE WHEN active=TRUE THEN 1 ELSE 0 END) AS active_hosts
        FROM monitored_ips WHERE user_id = ?
    ");
    $s->execute([$userId]);
    $summary = $s->fetch();

    $up = $pdo->prepare("
        SELECT ROUND(100.0 * SUM(CASE WHEN status='online' THEN 1 ELSE 0 END) / NULLIF(COUNT(*),0), 2) AS uptime,
               ROUND(AVG(latency_ms) FILTER (WHERE status='online'), 1) AS avg_latency
        FROM ping_logs pl
        JOIN monitored_ips mi ON mi.id = pl.monitored_ip_id
        WHERE mi.user_id = ? AND pl.checked_at >= NOW() - INTERVAL '1 day'
    ");
    $up->execute([$userId]);
    $upRow = $up->fetch();

    api_response([
        'data' => [
            'hosts'       => $summary,
            'uptime_24h'  => $upRow['uptime'] ? (float)$upRow['uptime'] : null,
            'avg_lat_24h' => $upRow['avg_latency'] ? (float)$upRow['avg_latency'] : null,
            'generated_at'=> date('c'),
        ]
    ]);
}

// GET /tags
if ($path === '/tags' && $method === 'GET') {
    $tags = $pdo->prepare("SELECT id, name, color FROM tags WHERE user_id = ? ORDER BY name ASC");
    $tags->execute([$userId]);
    api_response(['data' => $tags->fetchAll()]);
}

// GET / — documentação básica
if ($path === '/' || $path === '') {
    api_response([
        'name'    => 'MonitorPing API',
        'version' => '1.0',
        'endpoints' => [
            'GET /hosts'              => 'Lista todos os hosts. Params: ?status=online|offline|unknown&tag=nome',
            'GET /hosts/{id}'         => 'Detalhe de um host com uptime 24h',
            'GET /hosts/{id}/logs'    => 'Logs de ping. Params: ?hours=24 (max 168)',
            'GET /stats'              => 'Estatísticas gerais do usuário',
            'GET /tags'               => 'Lista de tags criadas',
        ],
        'auth' => 'Bearer Token via header Authorization',
        'docs' => 'Gere seu token em: Perfil → Tokens de API',
    ]);
}

api_error(404, 'Endpoint não encontrado. Acesse / para ver a documentação.');
