<?php
/**
 * [1.5.213] App Telemetry — captura "vida" da app a baixo custo.
 *
 * Objectivos:
 *   - Saber quantos utilizadores estão ONLINE agora (últimos 5 min)
 *   - Saber distribuição de VERSÕES da app instaladas
 *   - Não destruir performance — escrita à BD limitada a 1x/hora por user
 *
 * Implementação:
 *   - Online: transients de 5 min (KV em memcache se disponível, BD senão)
 *   - Distribuição: ALTER TABLE ADD COLUMN app_version + UPDATE rate-limited
 *
 * Funções públicas:
 *   - rmbz_app_telemetry_record($telemovel) — chamada por require_auth
 *   - rmbz_app_telemetry_stats() — agregado para o painel admin
 */

if ( ! defined( 'ABSPATH' ) ) exit;

/* ============================================================================
 * SCHEMA — adicionar app_version_code à tabela de refresh tokens
 * ============================================================================ */

function rmbz_app_telemetry_schema_install() {
    global $wpdb;
    $t = $wpdb->prefix . 'rmbz_api_refresh_tokens';

    if ( $wpdb->get_var( "SHOW TABLES LIKE '$t'" ) !== $t ) {
        return; // tabela ainda não foi criada (instalação muito fresca)
    }

    $cols = (array) $wpdb->get_col( "SHOW COLUMNS FROM $t" );

    if ( ! in_array( 'app_version', $cols, true ) ) {
        $wpdb->query( "ALTER TABLE $t ADD COLUMN app_version VARCHAR(20) DEFAULT NULL" );
        $wpdb->query( "ALTER TABLE $t ADD INDEX idx_app_version (app_version)" );
    }
    if ( ! in_array( 'app_version_code', $cols, true ) ) {
        $wpdb->query( "ALTER TABLE $t ADD COLUMN app_version_code INT(11) DEFAULT NULL" );
        $wpdb->query( "ALTER TABLE $t ADD INDEX idx_app_version_code (app_version_code)" );
    }
}
add_action( 'admin_init', 'rmbz_app_telemetry_schema_install', 9 );
add_action( 'init',       'rmbz_app_telemetry_schema_install', 9 );

/* ============================================================================
 * RECORD — chamado em require_auth com o telemóvel autenticado
 * ============================================================================ */

/**
 * Marca o utilizador como "online agora" e (rate-limited) actualiza o
 * registo da app version na BD.
 *
 * @param string $telemovel User autenticado
 */
function rmbz_app_telemetry_record( $telemovel ) {
    if ( ! $telemovel ) return;

    // ---- 1. Marcar online (transient) — sempre ----
    set_transient(
        'rmbz_app_online_' . md5( $telemovel ),
        time(),
        5 * MINUTE_IN_SECONDS
    );

    // Adicionar ao "set" de telemóveis online — usamos lista numa option
    // (não há SADD em wp_options, mas para painel admin é OK consultar lista)
    $online_set = (array) get_transient( 'rmbz_app_online_set' );
    $online_set[ $telemovel ] = time();
    // Limpar entries > 5 min
    $cutoff = time() - ( 5 * MINUTE_IN_SECONDS );
    foreach ( $online_set as $k => $v ) {
        if ( $v < $cutoff ) unset( $online_set[ $k ] );
    }
    set_transient( 'rmbz_app_online_set', $online_set, 10 * MINUTE_IN_SECONDS );

    // ---- 2. Actualizar app_version no token (rate-limited) ----
    $rl_key = 'rmbz_app_ver_rl_' . md5( $telemovel );
    if ( get_transient( $rl_key ) ) {
        return; // já actualizou nesta hora, skip
    }
    set_transient( $rl_key, 1, HOUR_IN_SECONDS );

    $app_version = isset( $_SERVER['HTTP_X_1MZ_APP_VERSION'] )
        ? substr( sanitize_text_field( $_SERVER['HTTP_X_1MZ_APP_VERSION'] ), 0, 20 )
        : null;
    $version_code = (int) ( $_SERVER['HTTP_X_1MZ_APP_VERSION_CODE'] ?? 0 );

    if ( ! $app_version && ! $version_code ) return;

    global $wpdb;
    $t = $wpdb->prefix . 'rmbz_api_refresh_tokens';
    $now = current_time( 'mysql', 1 );

    // Update mais recente token vivo do user (token rotation pode ter
    // múltiplos, queremos o mais recente).
    // Verificar se a coluna existe — se schema_install ainda não correu,
    // skip silenciosamente.
    $cols = (array) $wpdb->get_col( "SHOW COLUMNS FROM $t" );
    if ( ! in_array( 'app_version', $cols, true ) ) return;

    $updates = [ 'last_used_at' => $now ];
    $formats = [ '%s' ];
    if ( $app_version ) {
        $updates['app_version'] = $app_version;
        $formats[] = '%s';
    }
    if ( $version_code > 0 ) {
        $updates['app_version_code'] = $version_code;
        $formats[] = '%d';
    }

    $latest_id = (int) $wpdb->get_var( $wpdb->prepare(
        "SELECT id FROM $t
         WHERE user_telemovel = %s AND revoked_at IS NULL
         ORDER BY created_at DESC LIMIT 1",
        $telemovel
    ) );
    if ( $latest_id <= 0 ) return;

    $wpdb->update( $t, $updates, [ 'id' => $latest_id ], $formats, [ '%d' ] );
}

/* ============================================================================
 * STATS — agregados para o painel admin
 * ============================================================================ */

/**
 * Devolve métricas resumidas para o painel:
 *   [
 *     'online_now'        => 5,    // últimos 5 min
 *     'active_24h'        => 47,   // last_used_at < 24h
 *     'active_7d'         => 230,  // last_used_at < 7 dias
 *     'total_devices'     => 850,  // total tokens activos
 *     'version_breakdown' => [
 *        ['version' => '1.6.99', 'code' => 199, 'count' => 320, 'pct' => 37.6],
 *        ['version' => '1.6.97', 'code' => 197, 'count' => 280, 'pct' => 32.9],
 *        ...
 *     ],
 *   ]
 */
function rmbz_app_telemetry_stats() {
    global $wpdb;
    $t = $wpdb->prefix . 'rmbz_api_refresh_tokens';

    if ( $wpdb->get_var( "SHOW TABLES LIKE '$t'" ) !== $t ) {
        return [
            'online_now' => 0, 'active_24h' => 0, 'active_7d' => 0,
            'total_devices' => 0, 'version_breakdown' => [],
        ];
    }

    // Online agora — contagem do set transient
    $online_set = (array) get_transient( 'rmbz_app_online_set' );
    $cutoff = time() - ( 5 * MINUTE_IN_SECONDS );
    $online_now = 0;
    foreach ( $online_set as $ts ) {
        if ( $ts >= $cutoff ) $online_now++;
    }

    // Activos 24h
    $active_24h = (int) $wpdb->get_var(
        "SELECT COUNT(DISTINCT user_telemovel) FROM $t
         WHERE revoked_at IS NULL
           AND last_used_at >= DATE_SUB(NOW(), INTERVAL 24 HOUR)"
    );

    // Activos 7d
    $active_7d = (int) $wpdb->get_var(
        "SELECT COUNT(DISTINCT user_telemovel) FROM $t
         WHERE revoked_at IS NULL
           AND last_used_at >= DATE_SUB(NOW(), INTERVAL 7 DAY)"
    );

    // Total dispositivos
    $total_devices = (int) $wpdb->get_var(
        "SELECT COUNT(*) FROM $t WHERE revoked_at IS NULL AND expires_at > NOW()"
    );

    // Distribuição de versões — só conta o token MAIS RECENTE de cada user
    // (porque rotation cria múltiplos tokens mas todos da mesma versão)
    $cols = (array) $wpdb->get_col( "SHOW COLUMNS FROM $t" );
    $has_av = in_array( 'app_version', $cols, true );

    $breakdown = [];
    if ( $has_av ) {
        $rows = $wpdb->get_results(
            "SELECT app_version,
                    MAX(app_version_code) AS code,
                    COUNT(DISTINCT user_telemovel) AS users
             FROM $t
             WHERE revoked_at IS NULL
               AND app_version IS NOT NULL
               AND last_used_at >= DATE_SUB(NOW(), INTERVAL 30 DAY)
             GROUP BY app_version
             ORDER BY code DESC, users DESC"
        );
        $sum_users = 0;
        foreach ( (array) $rows as $r ) $sum_users += (int) $r->users;
        foreach ( (array) $rows as $r ) {
            $users = (int) $r->users;
            $breakdown[] = [
                'version' => (string) $r->app_version,
                'code'    => (int) ( $r->code ?? 0 ),
                'count'   => $users,
                'pct'     => $sum_users > 0 ? round( ( $users / $sum_users ) * 100, 1 ) : 0,
            ];
        }
    }

    return [
        'online_now'        => $online_now,
        'active_24h'        => $active_24h,
        'active_7d'         => $active_7d,
        'total_devices'     => $total_devices,
        'version_breakdown' => $breakdown,
    ];
}
