<?php
/**
 * [1.6.116] AVISOS GLOBAIS — REST API
 *
 * Endpoints:
 *   GET  /1mz/v1/announcements                — Lista avisos activos para o user
 *   POST /1mz/v1/announcements/{id}/dismiss   — Dispensa permanente
 *
 * Filtros aplicados no GET:
 *   - is_active = 1
 *   - starts_at IS NULL OR starts_at <= NOW (UTC)
 *   - ends_at   IS NULL OR ends_at   >= NOW (UTC)
 *   - audience matches user (all / vip / non_vip)
 *   - não está em rmbz_app_announcement_dismissals (se dismissible = 2)
 *   - ordenado por sort_order ASC, id DESC
 *
 * @package 1MZ_For_Artists
 * @since 1.6.116
 */

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


add_action( 'rest_api_init', 'rmbz_api_register_announcements_routes' );

function rmbz_api_register_announcements_routes() {
    register_rest_route( RMBZ_API_NAMESPACE, '/announcements', [
        'methods'             => 'GET',
        'callback'            => 'rmbz_api_handle_list_announcements',
        'permission_callback' => 'rmbz_api_require_auth',
    ] );

    register_rest_route( RMBZ_API_NAMESPACE, '/announcements/(?P<id>\d+)/dismiss', [
        'methods'             => 'POST',
        'callback'            => 'rmbz_api_handle_dismiss_announcement',
        'permission_callback' => 'rmbz_api_require_auth',
        'args' => [
            'id' => [ 'type' => 'integer', 'required' => true ],
        ],
    ] );

    // [1.6.116.4] Métricas — view, dismiss, cta_click
    register_rest_route( RMBZ_API_NAMESPACE, '/announcements/(?P<id>\d+)/event', [
        'methods'             => 'POST',
        'callback'            => 'rmbz_api_handle_announcement_event',
        'permission_callback' => 'rmbz_api_require_auth',
        'args' => [
            'id'         => [ 'type' => 'integer', 'required' => true ],
            'event_type' => [ 'type' => 'string', 'required' => true ],
        ],
    ] );
}


/**
 * Determina se o user é VIP (algum plano activo).
 * Reutilizamos lógica existente se disponível, fallback simples senão.
 */
function rmbz_announcements_user_is_vip( $telemovel ) {
    // Fonte canónica: verifica rmbz_subscriptions.end_date > now.
    if ( function_exists( 'rmbz_user_has_active_subscription' ) ) {
        return (bool) rmbz_user_has_active_subscription( $telemovel );
    }
    // Fallback defensivo (instalações sem a função canónica).
    if ( function_exists( 'rmbz_api_get_active_plan_name' ) ) {
        return ! empty( rmbz_api_get_active_plan_name( $telemovel ) );
    }
    return false;
}


/**
 * GET /announcements — Lista avisos activos para o user autenticado.
 */
function rmbz_api_handle_list_announcements( WP_REST_Request $request ) {
    $telemovel = (string) $request->get_param( 'rmbz_telemovel' );
    global $wpdb;

    $t_ann = $wpdb->prefix . 'rmbz_app_announcements';
    $t_dis = $wpdb->prefix . 'rmbz_app_announcement_dismissals';

    // Se as tabelas não existem ainda (não foi activado), devolver vazio
    if ( $wpdb->get_var( "SHOW TABLES LIKE '$t_ann'" ) !== $t_ann ) {
        return rmbz_api_ok( [ 'items' => [] ] );
    }

    $is_vip = rmbz_announcements_user_is_vip( $telemovel );
    $audience_match = $is_vip ? 'vip' : 'non_vip';

    // Comparamos datas em UTC. starts/ends_at são datetime sem tz no MySQL —
    // assumimos UTC (consistente com current_time('mysql', 1) que o resto
    // do plugin usa para gravar).
    $now_utc = gmdate( 'Y-m-d H:i:s' );

    $rows = $wpdb->get_results( $wpdb->prepare(
        "SELECT a.*
           FROM $t_ann a
           LEFT JOIN $t_dis d
                  ON d.announcement_id = a.id
                 AND d.user_telemovel = %s
          WHERE a.is_active = 1
            AND ( a.starts_at IS NULL OR a.starts_at <= %s )
            AND ( a.ends_at   IS NULL OR a.ends_at   >= %s )
            AND ( a.audience = 'all' OR a.audience = %s )
            AND ( a.dismissible <> 2 OR d.id IS NULL )
          ORDER BY a.sort_order ASC, a.id DESC
          LIMIT 50",
        $telemovel, $now_utc, $now_utc, $audience_match
    ) );

    $items = array_map( function ( $r ) {
        return [
            'id'           => (int) $r->id,
            'title'        => (string) $r->title,
            'message'      => (string) $r->message,
            'level'        => (string) $r->level,        // info|success|warning|error|promo
            'icon'         => $r->icon ?: null,
            'cta_label'    => $r->cta_label ?: null,
            'cta_url'      => $r->cta_url ?: null,
            'dismissible'  => (int) $r->dismissible,     // 0|1|2
            'animation'    => (string) $r->animation,    // none|slide|pulse
            'location'     => (string) $r->location,     // "home" | "all" | "home,wallet" ...
            'starts_at'    => $r->starts_at ? mysql_to_rfc3339( $r->starts_at ) : null,
            'ends_at'      => $r->ends_at   ? mysql_to_rfc3339( $r->ends_at )   : null,
            'sort_order'   => (int) $r->sort_order,
        ];
    }, $rows ?: [] );

    return rmbz_api_ok( [
        'items' => $items,
        'count' => count( $items ),
    ] );
}


/**
 * POST /announcements/{id}/dismiss — Marca o aviso como dispensado para sempre.
 *
 * Só faz sentido para dismissible = 2 (permanente). Para dismissible = 1
 * (sessão) a app guarda localmente. Para dismissible = 0 não devia chegar
 * aqui — devolvemos erro.
 */
function rmbz_api_handle_dismiss_announcement( WP_REST_Request $request ) {
    $telemovel = (string) $request->get_param( 'rmbz_telemovel' );
    $id        = (int) $request->get_param( 'id' );

    if ( $id <= 0 ) {
        return rmbz_api_error( 'ID inválido.', 400, 'bad_id' );
    }

    global $wpdb;
    $t_ann = $wpdb->prefix . 'rmbz_app_announcements';
    $t_dis = $wpdb->prefix . 'rmbz_app_announcement_dismissals';

    // Confirmar que o aviso existe e é permanente-dispensável
    $ann = $wpdb->get_row( $wpdb->prepare(
        "SELECT id, dismissible FROM $t_ann WHERE id = %d",
        $id
    ) );

    if ( ! $ann ) {
        return rmbz_api_error( 'Aviso não encontrado.', 404, 'not_found' );
    }

    if ( (int) $ann->dismissible !== 2 ) {
        return rmbz_api_error( 'Este aviso não permite dispensa permanente.', 400, 'not_dismissible' );
    }

    // Insert idempotente (UNIQUE KEY trata duplicados)
    $wpdb->query( $wpdb->prepare(
        "INSERT IGNORE INTO $t_dis (announcement_id, user_telemovel, dismissed_at)
         VALUES (%d, %s, %s)",
        $id, $telemovel, gmdate( 'Y-m-d H:i:s' )
    ) );

    return rmbz_api_ok( [
        'dismissed'       => true,
        'announcement_id' => $id,
    ] );
}


/**
 * [1.6.116.4] POST /announcements/{id}/event — Recolher impressões/dispensas/cliques.
 *
 * Body: { "event_type": "view" | "dismiss" | "cta_click" }
 *
 * Para `view`, deduplicamos por (user, ann, dia) — evita inflar com múltiplas
 * impressões no mesmo dia. Para `dismiss` e `cta_click` deixamos passar todos.
 */
function rmbz_api_handle_announcement_event( WP_REST_Request $request ) {
    $telemovel = (string) $request->get_param( 'rmbz_telemovel' );
    $id        = (int) $request->get_param( 'id' );
    $type      = sanitize_key( $request->get_param( 'event_type' ) ?? '' );

    if ( $id <= 0 ) {
        return rmbz_api_error( 'ID inválido.', 400, 'bad_id' );
    }
    $allowed = [ 'view', 'dismiss', 'cta_click' ];
    if ( ! in_array( $type, $allowed, true ) ) {
        return rmbz_api_error( 'event_type inválido.', 400, 'bad_event_type' );
    }

    global $wpdb;
    $t_events = $wpdb->prefix . 'rmbz_app_announcement_events';
    $t_ann    = $wpdb->prefix . 'rmbz_app_announcements';

    // Confirmar que o aviso existe (evita lixo na tabela)
    $exists = $wpdb->get_var( $wpdb->prepare(
        "SELECT id FROM $t_ann WHERE id = %d", $id
    ) );
    if ( ! $exists ) {
        return rmbz_api_error( 'Aviso não encontrado.', 404, 'not_found' );
    }

    // Dedup de views: só 1 por (user, ann, dia). Evita contar impressão
    // sempre que o user muda de tab/recompõe.
    if ( $type === 'view' ) {
        $today = gmdate( 'Y-m-d' );
        $already = $wpdb->get_var( $wpdb->prepare(
            "SELECT id FROM $t_events
              WHERE announcement_id = %d
                AND user_telemovel = %s
                AND event_type = 'view'
                AND DATE(created_at) = %s
              LIMIT 1",
            $id, $telemovel, $today
        ) );
        if ( $already ) {
            return rmbz_api_ok( [ 'recorded' => false, 'reason' => 'already_today' ] );
        }
    }

    $inserted = $wpdb->insert( $t_events, [
        'announcement_id' => $id,
        'user_telemovel'  => $telemovel,
        'event_type'      => $type,
        'created_at'      => gmdate( 'Y-m-d H:i:s' ),
    ], [ '%d', '%s', '%s', '%s' ] );

    if ( ! $inserted ) {
        return rmbz_api_error( 'Erro ao registar evento.', 500, 'insert_failed' );
    }

    return rmbz_api_ok( [
        'recorded' => true,
        'event_id' => (int) $wpdb->insert_id,
    ] );
}
