/*
 * ============================================================
 *  Ejemplo 08 — Control de Sesiones con Heartbeat
 *
 *  Descripcion:
 *    Despues de autenticarse, el loader llama periodicamente a
 *    /api/client/heartbeat con su session_token.
 *    Si el admin cierra la sesion desde el panel, el servidor
 *    responde session_killed y el programa se cierra.
 *
 *  Integracion en 3 pasos:
 *    1. Autenticarte normalmente (license / login / register)
 *    2. Guardar el session_token que devuelve SaoAuthApp.init()
 *    3. Lanzar el thread de heartbeat mostrado abajo
 *
 *  Compatible con:
 *    - Auth.h (protocolo legacy — usa sessionid internamente)
 *    - SaoAuth.hpp (protocolo moderno — usa session_token JSON)
 * ============================================================
 */
#include "SaoAuth.hpp"   // o tu Auth.h segun corresponda
#include <iostream>
#include <string>
#include <thread>
#include <chrono>
#include <atomic>

// ── Configura con tus datos del panel (Aplicaciones → Credenciales) ──────────
SaoAuth::api SaoAuthApp(
    "MiApp",
    "TU_OWNERID_AQUI",
    "TU_SECRET_AQUI",
    "1.0",
    "https://saoauth.com/api/client/auth"
);

// ── Variable global que indica si la sesion sigue activa ─────────────────────
std::atomic<bool> g_sessionAlive{ true };

// ── Funcion que hace el GET al heartbeat endpoint ─────────────────────────────
// Retorna true = sesion activa, false = session_killed
bool checkHeartbeat(const std::string& session_token) {
#ifdef _WIN32
    // Implementacion con WinINet (Windows)
    #include <wininet.h>
    #pragma comment(lib, "wininet.lib")

    HINTERNET hNet = InternetOpenA("SaoLoader", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    if (!hNet) return true;

    HINTERNET hConn = InternetConnectA(hNet, "saoauth.com",
        INTERNET_DEFAULT_HTTPS_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
    if (!hConn) { InternetCloseHandle(hNet); return true; }

    std::string path = "/api/client/heartbeat?session_token=" + session_token;
    const char* types[] = { "*/*", NULL };
    HINTERNET hReq = HttpOpenRequestA(hConn, "GET", path.c_str(), NULL, NULL, types,
        INTERNET_FLAG_SECURE |
        INTERNET_FLAG_IGNORE_CERT_CN_INVALID |
        INTERNET_FLAG_IGNORE_CERT_DATE_INVALID, 0);
    if (!hReq) { InternetCloseHandle(hConn); InternetCloseHandle(hNet); return true; }

    HttpSendRequestA(hReq, NULL, 0, NULL, 0);

    std::string body;
    char buf[2048]; DWORD rd;
    while (InternetReadFile(hReq, buf, sizeof(buf), &rd) && rd > 0)
        body.append(buf, rd);

    InternetCloseHandle(hReq);
    InternetCloseHandle(hConn);
    InternetCloseHandle(hNet);

    if (body.empty()) return true; // sin respuesta → asumir activo
    // Buscar "session_killed" sin necesidad de JSON completo
    return body.find("session_killed") == std::string::npos;
#else
    // Para otros sistemas: usa libcurl o equivalente
    // curl -s "https://saoauth.com/api/client/heartbeat?session_token=TOKEN"
    return true;
#endif
}

// ── Thread que corre en segundo plano cada 15 segundos ───────────────────────
void heartbeatThread(const std::string& session_token) {
    std::this_thread::sleep_for(std::chrono::seconds(5)); // espera inicial

    while (g_sessionAlive.load()) {
        std::this_thread::sleep_for(std::chrono::seconds(15));

        if (!checkHeartbeat(session_token)) {
            g_sessionAlive.store(false);
#ifdef _WIN32
            MessageBoxA(NULL,
                "Tu sesion fue cerrada por el administrador.",
                "Sesion Terminada",
                MB_ICONWARNING | MB_OK);
            TerminateProcess(GetCurrentProcess(), 0);
#else
            std::cerr << "[Auth] Sesion cerrada por el administrador.\n";
            std::exit(0);
#endif
        }
    }
}

// ── Main de ejemplo ───────────────────────────────────────────────────────────
int main() {
    // 1. Pedir credenciales
    std::string username, password, key;
    std::cout << "Usuario: "; std::cin >> username;
    std::cout << "Password: "; std::cin >> password;

    // 2. Autenticar (user_login en este ejemplo)
    auto result = SaoAuthApp.userLogin(username, password);
    if (!result.success) {
        MessageBoxA(nullptr, result.error.c_str(), "Error de autenticacion", MB_ICONERROR);
        return 1;
    }

    std::cout << "[OK] Autenticado: " << username << "\n";
    std::cout << "  Session token: " << result.session_token << "\n";

    // 3. Lanzar heartbeat en background
    //    El thread verifica cada 15s si la sesion sigue activa.
    //    Si el admin la cierra desde Control de Sesiones → programa termina.
    std::thread hb(heartbeatThread, result.session_token);
    hb.detach();

    // 4. Tu logica principal aqui
    std::cout << "Programa corriendo. Presiona Enter para salir.\n";
    std::cin.ignore();
    std::cin.get();

    g_sessionAlive.store(false);
    return 0;
}

/*
 * ── Integracion rapida si usas Auth.h (protocolo legacy) ────────────────────
 *
 * En Auth.h ya tienes heartbeat() y getSessionId() disponibles.
 * Solo agrega esto en tu main() despues de login/register exitoso:
 *
 *   CreateThread(nullptr, 0, [](LPVOID) -> DWORD {
 *       Sleep(5000);
 *       while (true) {
 *           Sleep(15000);
 *           std::string tok = SaoAuthApp.getSessionId();
 *           if (!tok.empty() && !SaoAuthApp.heartbeat(tok)) {
 *               MessageBoxA(NULL, "Sesion cerrada por el administrador.",
 *                   "Sesion Terminada", MB_ICONWARNING | MB_OK);
 *               TerminateProcess(GetCurrentProcess(), 0);
 *           }
 *       }
 *       return 0;
 *   }, nullptr, 0, nullptr);
 *
 * ── Como funciona desde el panel ────────────────────────────────────────────
 *
 *   Panel → Control de Sesiones → [Cerrar sesion] o [Cerrar todas]
 *   └→ Elimina la fila de client_sessions en la BD
 *   └→ En el proximo heartbeat el servidor responde: {"success":false,"message":"session_killed"}
 *   └→ El thread detecta esto y cierra el proceso
 *
 * ── Intervalo recomendado ────────────────────────────────────────────────────
 *
 *   15s  → deteccion rapida, minimo impacto en red
 *   30s  → balance ideal para la mayoria de apps
 *   60s  → si quieres minimo trafico de red
 */
