<?php
require_once __DIR__ . '/auth.php';
require_once __DIR__ . '/helpers.php';
require_once __DIR__ . '/mailer.php';

requireLogin();
header('Content-Type: application/json; charset=utf-8');

$pdo    = db();
$user   = currentUser();
$action = $_GET['action'] ?? '';
$period = $_GET['period'] ?? '24h';
$isAdmin = $user['role'] === 'admin';

// Calcular rango de fechas
$periodMap = ['6h' => 6, '24h' => 24, '7d' => 168, '30d' => 720];
$hours = $periodMap[$period] ?? 24;
$since = date('Y-m-d H:i:s', strtotime("-{$hours} hours"));

// Acciones que no necesitan resolución de clientIds (no tocan query_logs por cliente)
$noClientActions = ['sync_status','admin_users','admin_save_user','admin_delete_user',
                    'adguard_clients','users_list','report_config_get','report_config_save',
                    'report_send_test','smtp_config_get','smtp_config_save','smtp_test',
                    'explain_domain'];

$ph        = '';
$clientIds = [];

if (!in_array($action, $noClientActions)) {
    // Client IDs a consultar
    if ($isAdmin && !empty($_GET['view_user'])) {
        $viewUserId = (int)$_GET['view_user'];
        $stmt = $pdo->prepare("SELECT adguard_client_id FROM client_mapping WHERE user_id = ?");
        $stmt->execute([$viewUserId]);
        $clientIds = $stmt->fetchAll(PDO::FETCH_COLUMN);
        if (empty($clientIds)) $clientIds = ['__no_match__'];
    } elseif ($isAdmin && !empty($_GET['client_id'])) {
        $clientIds = [$_GET['client_id']];
    } elseif ($isAdmin) {
        // Admin sin filtro: limitar a últimos 30d para evitar full scan
        $allClients = $pdo->query("
            SELECT DISTINCT adguard_client_id FROM query_logs
            WHERE log_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)
        ")->fetchAll(PDO::FETCH_COLUMN);
        $clientIds = $allClients;
    } else {
        $clientIds = $user['client_ids'];
    }

    if (empty($clientIds)) {
        echo json_encode($isAdmin
            ? ['error' => 'Sin datos sincronizados aún. Ejecute el cron.php.']
            : ['error' => 'Sin clientes asignados. Contacte al administrador.']
        );
        exit;
    }

    $ph = clientIdPlaceholders($clientIds);
}

switch ($action) {

    // ----------------------------------------------------------
    case 'stats':
        $stmt = $pdo->prepare("
            SELECT
                COUNT(*)                                               AS total_queries,
                SUM(reason LIKE 'Filtered%')                          AS total_blocked,
                SUM(reason = 'FilteredBlackList')                     AS blocked_list,
                SUM(reason = 'FilteredSafeBrowsing')                  AS blocked_sb,
                SUM(reason = 'FilteredParental')                      AS blocked_parental
            FROM query_logs
            WHERE adguard_client_id IN ($ph)
              AND log_time >= ?
        ");
        $stmt->execute([...$clientIds, $since]);
        $row = $stmt->fetch();

        // Top categoria
        $catStmt = $pdo->prepare("
            SELECT category, COUNT(*) AS cnt
            FROM query_logs
            WHERE adguard_client_id IN ($ph)
              AND reason LIKE 'Filtered%'
              AND log_time >= ?
            GROUP BY category
            ORDER BY cnt DESC
            LIMIT 1
        ");
        $catStmt->execute([...$clientIds, $since]);
        $topCat = $catStmt->fetch();

        echo json_encode([
            'total_queries'   => (int)$row['total_queries'],
            'total_blocked'   => (int)$row['total_blocked'],
            'total_allowed'   => (int)$row['total_queries'] - (int)$row['total_blocked'],
            'block_rate'      => $row['total_queries'] > 0
                                    ? round(($row['total_blocked'] / $row['total_queries']) * 100, 1)
                                    : 0,
            'top_category'    => $topCat['category'] ?? '-',
        ]);
        break;

    // ----------------------------------------------------------
    case 'timeline':
        // Granularidad: hora si <= 48h, día si > 48h
        $granularity = $hours <= 48 ? '%Y-%m-%d %H:00:00' : '%Y-%m-%d 00:00:00';
        $stmt = $pdo->prepare("
            SELECT
                DATE_FORMAT(log_time, ?) AS ts,
                COUNT(*)                 AS total,
                SUM(reason LIKE 'Filtered%') AS blocked
            FROM query_logs
            WHERE adguard_client_id IN ($ph)
              AND log_time >= ?
            GROUP BY ts
            ORDER BY ts ASC
        ");
        $stmt->execute([$granularity, ...$clientIds, $since]);
        $rows = $stmt->fetchAll();

        $labels  = array_column($rows, 'ts');
        $totals  = array_map(fn($r) => (int)$r['total'],   $rows);
        $blocked = array_map(fn($r) => (int)$r['blocked'], $rows);

        echo json_encode(compact('labels', 'totals', 'blocked'));
        break;

    // ----------------------------------------------------------
    case 'categories':
        $stmt = $pdo->prepare("
            SELECT category, category_color, COUNT(*) AS cnt
            FROM query_logs
            WHERE adguard_client_id IN ($ph)
              AND reason LIKE 'Filtered%'
              AND log_time >= ?
            GROUP BY category, category_color
            ORDER BY cnt DESC
            LIMIT 12
        ");
        $stmt->execute([...$clientIds, $since]);
        $rows = $stmt->fetchAll();

        echo json_encode([
            'labels' => array_column($rows, 'category'),
            'values' => array_map(fn($r) => (int)$r['cnt'],            $rows),
            'colors' => array_column($rows, 'category_color'),
        ]);
        break;

    // ----------------------------------------------------------
    case 'top_domains':
        $limit = min((int)($_GET['limit'] ?? 10), 50);
        $stmt  = $pdo->prepare("
            SELECT domain, category, category_color, COUNT(*) AS cnt
            FROM query_logs
            WHERE adguard_client_id IN ($ph)
              AND reason LIKE 'Filtered%'
              AND log_time >= ?
            GROUP BY domain, category, category_color
            ORDER BY cnt DESC
            LIMIT ?
        ");
        $stmt->execute([...$clientIds, $since, $limit]);
        echo json_encode($stmt->fetchAll());
        break;

    // ----------------------------------------------------------
    case 'top_clients':
        // Solo admin
        if (!$isAdmin) { echo json_encode(['error' => 'No autorizado']); exit; }
        $stmt = $pdo->prepare("
            SELECT adguard_client_id, client_name,
                   COUNT(*) AS total,
                   SUM(reason LIKE 'Filtered%') AS blocked
            FROM query_logs
            WHERE adguard_client_id IN ($ph)
              AND log_time >= ?
            GROUP BY adguard_client_id, client_name
            ORDER BY total DESC
            LIMIT 20
        ");
        $stmt->execute([...$clientIds, $since]);
        echo json_encode($stmt->fetchAll());
        break;

    // ----------------------------------------------------------
    case 'logs':
        $page     = max(1, (int)($_GET['page'] ?? 1));
        $limit    = min(100, max(10, (int)($_GET['limit'] ?? 50)));
        $offset   = ($page - 1) * $limit;
        $search   = $_GET['search']   ?? '';
        $category = $_GET['category'] ?? '';
        $reason   = $_GET['reason']   ?? '';
        $dateFrom = $_GET['date_from'] ?? '';
        $dateTo   = $_GET['date_to']   ?? '';

        $where  = ["adguard_client_id IN ($ph)", "log_time >= ?"];
        $params = [...$clientIds, $since];

        if ($search) {
            $where[]  = "domain LIKE ?";
            $params[] = "%$search%";
        }
        if ($category) {
            $where[]  = "category = ?";
            $params[] = $category;
        }
        if ($reason) {
            $where[]  = "reason = ?";
            $params[] = $reason;
        }
        if ($dateFrom) {
            $where[]  = "log_time >= ?";
            $params[] = $dateFrom . ' 00:00:00';
        }
        if ($dateTo) {
            $where[]  = "log_time <= ?";
            $params[] = $dateTo . ' 23:59:59';
        }

        $whereSQL = implode(' AND ', $where);

        $countStmt = $pdo->prepare("SELECT COUNT(*) FROM query_logs WHERE $whereSQL");
        $countStmt->execute($params);
        $total = (int)$countStmt->fetchColumn();

        $dataStmt = $pdo->prepare("
            SELECT log_time, adguard_client_id, client_name, domain, query_type,
                   reason, category, category_color, filter_name, rule_text, status, elapsed_ms
            FROM query_logs
            WHERE $whereSQL
            ORDER BY log_time DESC
            LIMIT ? OFFSET ?
        ");
        $dataStmt->execute([...$params, $limit, $offset]);
        $rows = $dataStmt->fetchAll();

        echo json_encode([
            'total'       => $total,
            'pages'       => ceil($total / $limit),
            'current_page'=> $page,
            'data'        => $rows,
        ]);
        break;

    // ----------------------------------------------------------
    case 'categories_list':
        $stmt = $pdo->prepare("
            SELECT DISTINCT category, category_color
            FROM query_logs
            WHERE adguard_client_id IN ($ph)
              AND reason LIKE 'Filtered%'
              AND log_time >= ?
            ORDER BY category
        ");
        $stmt->execute([...$clientIds, $since]);
        echo json_encode($stmt->fetchAll());
        break;

    // ----------------------------------------------------------
    case 'sync_status':
        if (!$isAdmin) { echo json_encode(['error' => 'No autorizado']); exit; }
        // Último sync de cada servidor
        $syncs = [];
        foreach (ADGUARD_SERVERS as $srv) {
            $row = $pdo->prepare("SELECT * FROM sync_log WHERE server_id = ? ORDER BY id DESC LIMIT 1");
            $row->execute([$srv['id']]);
            $lastSync = $row->fetch();
            $stateRow = $pdo->prepare("SELECT state_value FROM sync_state WHERE state_key = ?");
            $stateRow->execute(['last_log_time_' . $srv['id']]);
            $syncs[] = [
                'server_id'     => $srv['id'],
                'server_name'   => $srv['name'],
                'last_sync'     => $lastSync ?: null,
                'last_log_time' => $stateRow->fetchColumn() ?: null,
            ];
        }
        echo json_encode($syncs);
        break;

    // ----------------------------------------------------------
    // ADMIN: gestión de usuarios
    case 'admin_users':
        if (!$isAdmin) { echo json_encode(['error' => 'No autorizado']); exit; }
        $users = $pdo->query("
            SELECT u.id, u.username, u.display_name, u.email, u.role, u.active, u.last_login,
                   GROUP_CONCAT(cm.adguard_client_id ORDER BY cm.adguard_client_id SEPARATOR ',') AS client_ids
            FROM users u
            LEFT JOIN client_mapping cm ON cm.user_id = u.id
            GROUP BY u.id
            ORDER BY u.role DESC, u.display_name
        ")->fetchAll();
        echo json_encode($users);
        break;

    case 'admin_save_user':
        if (!$isAdmin) { echo json_encode(['error' => 'No autorizado']); exit; }
        $data = json_decode(file_get_contents('php://input'), true) ?? [];
        $userId      = (int)($data['id'] ?? 0);
        $username    = strtolower(trim($data['username'] ?? ''));
        $displayName = trim($data['display_name'] ?? '');
        $email       = trim($data['email'] ?? '');
        $role        = in_array($data['role'] ?? '', ['admin','client']) ? $data['role'] : 'client';
        $active      = (int)(bool)($data['active'] ?? 1);
        $clientIdsRaw= trim($data['client_ids'] ?? '');
        $password    = $data['password'] ?? '';

        if (!$username || !$displayName) {
            echo json_encode(['error' => 'Nombre de usuario y nombre completo son requeridos']); exit;
        }

        if ($userId === 0) {
            // Crear
            if (!$password) { echo json_encode(['error' => 'La contraseña es requerida para nuevos usuarios']); exit; }
            $hash = password_hash($password, PASSWORD_DEFAULT);
            $stmt = $pdo->prepare("INSERT INTO users (username, password, display_name, email, role, active) VALUES (?,?,?,?,?,?)");
            $stmt->execute([$username, $hash, $displayName, $email ?: null, $role, $active]);
            $userId = (int)$pdo->lastInsertId();
        } else {
            // Editar
            if ($password) {
                $hash = password_hash($password, PASSWORD_DEFAULT);
                $pdo->prepare("UPDATE users SET username=?, password=?, display_name=?, email=?, role=?, active=? WHERE id=?")
                    ->execute([$username, $hash, $displayName, $email ?: null, $role, $active, $userId]);
            } else {
                $pdo->prepare("UPDATE users SET username=?, display_name=?, email=?, role=?, active=? WHERE id=?")
                    ->execute([$username, $displayName, $email ?: null, $role, $active, $userId]);
            }
        }

        // Actualizar mapeo de clientes
        $pdo->prepare("DELETE FROM client_mapping WHERE user_id = ?")->execute([$userId]);
        $newClientIds = array_filter(array_map('trim', explode(',', $clientIdsRaw)));
        foreach ($newClientIds as $cid) {
            if ($cid) {
                $pdo->prepare("INSERT IGNORE INTO client_mapping (user_id, adguard_client_id) VALUES (?,?)")
                    ->execute([$userId, $cid]);
            }
        }

        echo json_encode(['success' => true, 'user_id' => $userId]);
        break;

    case 'admin_delete_user':
        if (!$isAdmin) { echo json_encode(['error' => 'No autorizado']); exit; }
        $data = json_decode(file_get_contents('php://input'), true) ?? [];
        $userId = (int)($data['id'] ?? 0);
        if ($userId === $user['id']) { echo json_encode(['error' => 'No puede eliminar su propio usuario']); exit; }
        $pdo->prepare("DELETE FROM users WHERE id = ?")->execute([$userId]);
        echo json_encode(['success' => true]);
        break;

    // ----------------------------------------------------------
    case 'adguard_clients':
        if (!$isAdmin) { echo json_encode(['error' => 'No autorizado']); exit; }
        $stmt = $pdo->prepare("
            SELECT adguard_client_id, MAX(client_name) AS client_name, COUNT(*) AS total
            FROM query_logs
            WHERE log_time >= DATE_SUB(NOW(), INTERVAL 30 DAY)
            GROUP BY adguard_client_id
            ORDER BY total DESC
            LIMIT 200
        ");
        $stmt->execute();
        echo json_encode($stmt->fetchAll());
        break;

    // ----------------------------------------------------------
    case 'users_list':
        if (!$isAdmin) { echo json_encode(['error' => 'No autorizado']); exit; }
        $rows = $pdo->query("
            SELECT u.id, u.username, u.display_name,
                   GROUP_CONCAT(cm.adguard_client_id ORDER BY cm.adguard_client_id SEPARATOR ',') AS client_ids
            FROM users u
            LEFT JOIN client_mapping cm ON cm.user_id = u.id
            WHERE u.active = 1 AND u.role = 'client'
            GROUP BY u.id
            ORDER BY u.display_name
        ")->fetchAll();
        echo json_encode($rows);
        break;

    // ----------------------------------------------------------
    case 'report_config_get':
        if (!$isAdmin) { echo json_encode(['error' => 'No autorizado']); exit; }
        $targetId = (int)($_GET['user_id'] ?? 0);
        if (!$targetId) { echo json_encode(['error' => 'user_id requerido']); exit; }
        $stmt = $pdo->prepare("SELECT * FROM report_config WHERE user_id = ?");
        $stmt->execute([$targetId]);
        $cfg = $stmt->fetch();
        echo json_encode($cfg ?: ['user_id' => $targetId, 'emails' => '', 'day_of_week' => 1, 'send_hour' => 8, 'send_minute' => 0, 'active' => 0]);
        break;

    // ----------------------------------------------------------
    case 'report_send_test':
        if (!$isAdmin) { echo json_encode(['error' => 'No autorizado']); exit; }
        $data     = json_decode(file_get_contents('php://input'), true) ?? [];
        $targetId = (int)($data['user_id'] ?? 0);
        $emails   = array_filter(array_map('trim', explode(',', $data['emails'] ?? '')));
        if (!$targetId)      { echo json_encode(['error' => 'user_id requerido']); exit; }
        if (empty($emails))  { echo json_encode(['error' => 'Ingresá al menos un email destino']); exit; }

        require_once __DIR__ . '/report.php';
        $html = generateReport($pdo, $targetId, 7);
        if (!$html) { echo json_encode(['error' => 'No se pudo generar el reporte (usuario sin clientes asignados)']); exit; }

        $uRow = $pdo->prepare("SELECT display_name FROM users WHERE id = ?");
        $uRow->execute([$targetId]);
        $uName = $uRow->fetchColumn() ?: 'Cliente';

        $subject = "[PRUEBA] Informe DNS – $uName – " . date('d/m/Y H:i');
        $sent = 0; $failed = [];
        foreach ($emails as $email) {
            if (!filter_var($email, FILTER_VALIDATE_EMAIL)) { $failed[] = "$email (inválido)"; continue; }
            try {
                sendMail($pdo, $email, $subject, $html);
                $sent++;
            } catch (Throwable $e) {
                $failed[] = "$email (" . $e->getMessage() . ")";
            }
        }
        echo json_encode([
            'success' => $sent > 0,
            'sent'    => $sent,
            'failed'  => $failed,
            'message' => $sent > 0 ? "Enviado a $sent email(s) correctamente." : "No se pudo enviar.",
        ]);
        break;

    // ----------------------------------------------------------
    case 'report_config_save':
        if (!$isAdmin) { echo json_encode(['error' => 'No autorizado']); exit; }
        // Garantizar que la columna send_minute exista (ADD COLUMN sin IF NOT EXISTS = compatible con MySQL 5.x)
        try { $pdo->exec("ALTER TABLE report_config ADD COLUMN send_minute TINYINT UNSIGNED NOT NULL DEFAULT 0"); } catch (PDOException $e) { /* 1060 = duplicate column = ya existe */ }
        $data = json_decode(file_get_contents('php://input'), true) ?? [];
        $targetId  = (int)($data['user_id'] ?? 0);
        $emails    = trim($data['emails'] ?? '');
        $dayOfWeek = max(0, min(6,  (int)($data['day_of_week']  ?? 1)));
        $sendHour  = max(0, min(23, (int)($data['send_hour']    ?? 8)));
        $sendMin   = max(0, min(55, (int)($data['send_minute']  ?? 0)));
        $sendMin   = (int)round($sendMin / 5) * 5; // forzar múltiplo de 5
        $active    = (int)(bool)($data['active'] ?? 0);
        if (!$targetId) { echo json_encode(['error' => 'user_id requerido']); exit; }
        $pdo->prepare("
            INSERT INTO report_config (user_id, emails, day_of_week, send_hour, send_minute, active)
            VALUES (?, ?, ?, ?, ?, ?)
            ON DUPLICATE KEY UPDATE emails=VALUES(emails), day_of_week=VALUES(day_of_week),
                                    send_hour=VALUES(send_hour), send_minute=VALUES(send_minute), active=VALUES(active)
        ")->execute([$targetId, $emails, $dayOfWeek, $sendHour, $sendMin, $active]);
        echo json_encode(['success' => true]);
        break;

    // ----------------------------------------------------------
    case 'smtp_config_get':
        if (!$isAdmin) { echo json_encode(['error' => 'No autorizado']); exit; }
        $cfg = smtpGetConfig($pdo);
        $cfg['pass'] = $cfg['pass'] !== '' ? '••••••••' : ''; // no exponer la clave
        echo json_encode($cfg);
        break;

    // ----------------------------------------------------------
    case 'smtp_config_save':
        if (!$isAdmin) { echo json_encode(['error' => 'No autorizado']); exit; }
        $data = json_decode(file_get_contents('php://input'), true) ?? [];
        smtpSaveConfig($pdo, $data);
        echo json_encode(['success' => true]);
        break;

    // ----------------------------------------------------------
    case 'smtp_test':
        if (!$isAdmin) { echo json_encode(['error' => 'No autorizado']); exit; }
        $data    = json_decode(file_get_contents('php://input'), true) ?? [];
        $toEmail = trim($data['to'] ?? '');
        if (!filter_var($toEmail, FILTER_VALIDATE_EMAIL)) {
            echo json_encode(['error' => 'Email destino inválido']); exit;
        }
        // Si viene contraseña nueva en el test, guardarla primero
        if (!empty($data['pass']) && $data['pass'] !== '••••••••') {
            smtpSaveConfig($pdo, $data);
        }
        $cfg = smtpGetConfig($pdo);
        if (!$cfg['enabled'] || !$cfg['host']) {
            echo json_encode(['error' => 'SMTP no configurado o no habilitado']); exit;
        }
        try {
            $html = '<html><body style="font-family:Arial;padding:24px">
                <h2 style="color:#1e3a5f">✅ SMTP funcionando</h2>
                <p>Este es un email de prueba desde <strong>ZeroTrust Shield</strong>.</p>
                <p style="color:#64748b;font-size:12px">Servidor: ' . htmlspecialchars($cfg['host']) . ':' . $cfg['port'] . ' / ' . strtoupper($cfg['encryption']) . '</p>
            </body></html>';
            smtpSend($cfg, $toEmail, 'Prueba SMTP – ZeroTrust Shield', $html);
            echo json_encode(['success' => true, 'message' => "Email de prueba enviado a $toEmail"]);
        } catch (Throwable $e) {
            echo json_encode(['error' => $e->getMessage()]);
        }
        break;

    // ----------------------------------------------------------
    // Explicación en lenguaje simple de un dominio bloqueado (IA + caché)
    case 'explain_domain':
        if (!OPENAI_ENABLED) {
            echo json_encode(['error' => 'La función de explicación está desactivada.']); exit;
        }
        $rawDomain = $_GET['domain'] ?? '';
        $category  = trim($_GET['category'] ?? '');
        if ($category === '' || strlen($category) > 60) $category = 'Desconocida';

        $domain = sanitizeDomain($rawDomain);
        if (!$domain) {
            echo json_encode(['error' => 'Dominio inválido.']); exit;
        }

        $exp = getDomainExplanation($pdo, $domain, $category);
        if (!$exp) {
            echo json_encode(['error' => 'No se pudo generar la explicación en este momento. Intentá de nuevo en unos segundos.']); exit;
        }
        echo json_encode([
            'success' => true,
            'domain'  => $domain,
            'que_es'  => $exp['que_es'],
            'por_que' => $exp['por_que'],
            'riesgo'  => $exp['riesgo'],
            'consejo' => $exp['consejo'],
            'cached'  => !empty($exp['cached']),
        ]);
        break;

    default:
        echo json_encode(['error' => 'Acción no reconocida']);
}
