<?php
// includes/admin/admin-exclusive-services.php
//
// Página de admin para rever e decidir pedidos de serviços exclusivos
// (YouTube Content ID, Facebook Monetization, TikTok Monetization).
//
// [FEAT 1.5.14] Reforçada com:
//   - Leitor de áudio embebido para o admin ouvir a faixa antes de decidir
//   - Botões de pesquisa externa (YouTube, Spotify, TikTok, FB, Google)
//     pré-preenchidos com título + artista + ISRC para ajudar a detectar
//     conflitos com outros distribuidores
//   - Novo estado "conflict" além de approved/rejected — útil quando a
//     música já existe registada por outra conta no YT Content ID / FB
//     Rights Manager. Em vez de rejeitar (que é algo definitivo), o admin
//     pode marcar conflito com URL de evidência e nome do distribuidor
//     suspeito. O artista vê a informação detalhada na página da faixa.
//
// Aparece como sub-menu dentro de "Gestão de Distribuição Digital".
// Carregar no 1mz-for-artists.php depois de distribution-platforms.php.

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

/**
 * [1.5.159] REMOVIDO o registo de add_submenu_page para Serviços Exclusivos.
 *
 * Causa do bug: este ficheiro registava
 *   add_submenu_page('rmbz-admin-distribution', ..., 'rmbz-admin-exclusive-services', ...)
 *
 * Mas `rmbz-admin-distribution` NÃO é um menu top-level — é em si um submenu
 * de `rmbz-dashboard`. Quando registas um submenu cujo parent é também um
 * submenu, o WordPress:
 *   1) Adiciona-o ao parent top-level (rmbz-dashboard) sem o ligar visualmente
 *   2) Quando o utilizador clica nele, o WP não consegue determinar o item
 *      "active" correcto e oculta/fecha o menu inteiro de Distribuição.
 *
 * SOLUÇÃO: o controller `admin-distribution-controller.php` já tem
 * `case 'exclusives'` que renderiza a mesma função (rmbz_render_exclusive_services_page).
 * Logo o sítio correcto para aceder é:
 *   ?page=rmbz-admin-distribution&tab=exclusives
 *
 * O acesso continua a funcionar via tab no admin de Distribuição (item lateral
 * quebrado removido).
 */
// Bloco add_submenu_page removido. Tab 'exclusives' do controller cobre a mesma função.

/**
 * [BUGFIX 1.5.13] Handler de limpeza de órfãos registado em admin_init,
 * NÃO dentro da função de render (senão dava "headers already sent").
 *
 * [1.5.159] URL ajustada: agora a página é acedida via
 *   ?page=rmbz-admin-distribution&tab=exclusives
 * (em vez do antigo ?page=rmbz-admin-exclusive-services que foi removido).
 * Aceitamos AMBAS as URLs para retro-compatibilidade com bookmarks antigos.
 */
add_action( 'admin_init', function () {
    if ( ! isset($_GET['page']) ) return;
    $is_old_url = ( $_GET['page'] === 'rmbz-admin-exclusive-services' );
    $is_new_url = ( $_GET['page'] === 'rmbz-admin-distribution'
                    && isset($_GET['tab']) && $_GET['tab'] === 'exclusives' );
    if ( ! $is_old_url && ! $is_new_url ) return;

    if ( ! isset($_GET['rmbz_cleanup_orphans']) ) return;
    if ( ! current_user_can('manage_options') ) wp_die('Sem permissão.');
    if ( ! isset($_GET['_wpnonce']) || ! wp_verify_nonce($_GET['_wpnonce'], 'rmbz_cleanup_orphan_platforms') ) {
        wp_die('Falha de segurança (nonce inválido).');
    }

    global $wpdb;
    $table_p = $wpdb->prefix . 'rmbz_distro_release_platforms';
    $table_r = $wpdb->prefix . 'rmbz_distro_releases';

    $deleted = $wpdb->query(
        "DELETE p FROM $table_p p
         LEFT JOIN $table_r r ON p.release_id = r.id
         WHERE r.id IS NULL"
    );

    wp_safe_redirect( add_query_arg(
        [
            'page'    => 'rmbz-admin-distribution',
            'tab'     => 'exclusives',
            'msg'     => 'orphans_cleaned',
            'deleted' => (int) $deleted,
        ],
        admin_url('admin.php')
    ) );
    exit;
});

/**
 * [FEAT 1.5.14] Monta os URLs de pesquisa externa para detectar conflitos.
 * Devolve array assoc com label => URL, pronto a iterar no HTML.
 */
function rmbz_exclusive_build_search_links( $title, $artist_name, $isrc = '' ) {
    $q_title_artist = trim( $title . ' ' . $artist_name );
    $q_title_only   = trim( $title );

    $links = [
        'youtube' => [
            'label' => '🔎 YouTube',
            'url'   => 'https://www.youtube.com/results?search_query=' . rawurlencode( $q_title_artist ),
            'hint'  => 'UGC uploads que podem já ter Content ID',
        ],
        'youtube_music' => [
            'label' => '🎵 YouTube Music',
            'url'   => 'https://music.youtube.com/search?q=' . rawurlencode( $q_title_artist ),
            'hint'  => 'Art Tracks oficiais de outros distribuidores',
        ],
        'youtube_shorts' => [
            'label' => '🎬 YouTube Shorts',
            'url'   => 'https://www.youtube.com/results?search_query=' . rawurlencode( $q_title_artist . ' #shorts' ),
            'hint'  => 'Uso em formato short',
        ],
        'spotify' => [
            'label' => '🎧 Spotify',
            'url'   => 'https://open.spotify.com/search/' . rawurlencode( $q_title_artist ),
            'hint'  => 'Indica se outro distribuidor já publicou',
        ],
        'tiktok' => [
            'label' => '📱 TikTok',
            'url'   => 'https://www.tiktok.com/search?q=' . rawurlencode( $q_title_artist ),
            'hint'  => 'Vídeos a usar a música',
        ],
        'facebook' => [
            'label' => '📘 Facebook',
            'url'   => 'https://www.facebook.com/search/posts/?q=' . rawurlencode( $q_title_artist ),
            'hint'  => 'Posts que podem conter a música',
        ],
        'instagram' => [
            'label' => '📸 Instagram',
            'url'   => 'https://www.google.com/search?q=' . rawurlencode( $q_title_artist . ' site:instagram.com' ),
            'hint'  => 'Google restringido a Instagram',
        ],
        'google_yt' => [
            'label' => '🌐 Google + YouTube',
            'url'   => 'https://www.google.com/search?q=' . rawurlencode( '"' . $q_title_only . '" "' . $artist_name . '" site:youtube.com' ),
            'hint'  => 'Pesquisa restrita e exacta',
        ],
    ];

    // Se tiver ISRC, adicionar uma pesquisa específica (o ISRC é único, se aparecer
    // noutro sítio é sinal vermelho imediato).
    if ( ! empty($isrc) ) {
        $links['isrc'] = [
            'label' => '🆔 Google ISRC: ' . esc_html($isrc),
            'url'   => 'https://www.google.com/search?q=' . rawurlencode( $isrc ),
            'hint'  => 'Se este ISRC aparece noutro lado, há conflito quase certo',
        ];
    }

    return $links;
}

function rmbz_render_exclusive_services_page() {
    if ( ! current_user_can('manage_options') ) wp_die('Sem permissão.');

    global $wpdb;
    $table_p = $wpdb->prefix . 'rmbz_distro_release_platforms';
    $table_r = $wpdb->prefix . 'rmbz_distro_releases';
    $table_t = $wpdb->prefix . 'rmbz_distro_tracks';
    $table_w = $wpdb->prefix . 'rmbz_wallets';

    // Detectar órfãos (para o banner de aviso)
    $orphan_count = (int) $wpdb->get_var(
        "SELECT COUNT(*) FROM $table_p p
         LEFT JOIN $table_r r ON p.release_id = r.id
         WHERE r.id IS NULL"
    );

    // Filtro por estado
    $filter = isset($_GET['filter']) ? sanitize_key($_GET['filter']) : 'requested';
    // [FEAT 1.5.14] Adicionado 'conflict' aos filtros válidos.
    // [FEAT 1.6.0] Adicionado 'analytics' — nova aba de análise & pesquisa.
    // [REMOVIDO 1.6.1] 'all' removido — a aba Analítico cobre o caso de "ver
    // tudo" através do seu filtro interno de estado em "Qualquer".
    $allowed_filters = ['requested','approved','rejected','conflict','analytics'];
    if ( ! in_array($filter, $allowed_filters, true) ) $filter = 'requested';

    // Aba "Analítico" tem renderização própria (separa por completo da listagem).
    if ( $filter === 'analytics' ) {
        rmbz_render_exclusive_analytics_page( $table_p, $table_r, $table_t, $table_w );
        return;
    }

    // Filtro sempre aplica um estado específico (a opção "Todos" foi
    // removida — quem quer ver tudo vai à aba "Análise & Pesquisa").
    $where_parts = [ $wpdb->prepare(
        "(p.yt_content_id_status = %s OR p.fb_monet_status = %s OR p.tt_monet_status = %s)",
        $filter, $filter, $filter
    ) ];

    // [ESCALA 50k] Pesquisa server-side por título, artista, telemóvel ou ISRC.
    // Sem isto, a aba Aprovados ficaria com um LIMIT cego — inútil quando o
    // catálogo cresce para dezenas de milhares de músicas aprovadas.
    $exc_search = isset($_GET['exc_s']) ? trim( sanitize_text_field( wp_unslash($_GET['exc_s']) ) ) : '';
    if ( $exc_search !== '' ) {
        $like = '%' . $wpdb->esc_like($exc_search) . '%';
        // ISRC vai às faixas reais (EXISTS) — não há coluna primary_isrc na
        // tabela de plataformas; a pesquisa por ISRC procura em rmbz_distro_tracks.
        $where_parts[] = $wpdb->prepare(
            "(r.title LIKE %s OR w.user_nome LIKE %s OR r.artist_telemovel LIKE %s
              OR EXISTS (SELECT 1 FROM $table_t tk WHERE tk.release_id = r.id AND tk.isrc_code LIKE %s))",
            $like, $like, $like, $like
        );
    }
    $where = implode( ' AND ', $where_parts );

    // [ESCALA 50k] Paginação server-side (50 por página).
    $exc_per_page = 50;
    $exc_paged    = max( 1, (int) ( $_GET['exc_paged'] ?? 1 ) );
    $exc_offset   = ( $exc_paged - 1 ) * $exc_per_page;

    $exc_total = (int) $wpdb->get_var(
        "SELECT COUNT(*) FROM $table_p p
         JOIN $table_r r ON p.release_id = r.id
         LEFT JOIN $table_w w ON r.artist_telemovel = w.user_telemovel
         WHERE $where"
    );
    $exc_total_pages = max( 1, (int) ceil( $exc_total / $exc_per_page ) );

    $rows = $wpdb->get_results( $wpdb->prepare(
        "SELECT p.*, r.title AS release_title, r.artist_telemovel, r.cover_image, w.user_nome
         FROM $table_p p
         JOIN $table_r r ON p.release_id = r.id
         LEFT JOIN $table_w w ON r.artist_telemovel = w.user_telemovel
         WHERE $where
         ORDER BY p.updated_at DESC
         LIMIT %d OFFSET %d",
        $exc_per_page, $exc_offset
    ) );

    // [BUGFIX 1.5.12 + FEAT 1.5.14] Contadores fazem o mesmo JOIN que a listagem
    // e agora incluem também o estado 'conflict'.
    $counts = $wpdb->get_row("
        SELECT
            SUM(CASE WHEN p.yt_content_id_status = 'requested' THEN 1 ELSE 0 END) +
            SUM(CASE WHEN p.fb_monet_status = 'requested' THEN 1 ELSE 0 END) +
            SUM(CASE WHEN p.tt_monet_status = 'requested' THEN 1 ELSE 0 END) AS pending,
            SUM(CASE WHEN p.yt_content_id_status = 'approved' THEN 1 ELSE 0 END) +
            SUM(CASE WHEN p.fb_monet_status = 'approved' THEN 1 ELSE 0 END) +
            SUM(CASE WHEN p.tt_monet_status = 'approved' THEN 1 ELSE 0 END) AS approved,
            SUM(CASE WHEN p.yt_content_id_status = 'rejected' THEN 1 ELSE 0 END) +
            SUM(CASE WHEN p.fb_monet_status = 'rejected' THEN 1 ELSE 0 END) +
            SUM(CASE WHEN p.tt_monet_status = 'rejected' THEN 1 ELSE 0 END) AS rejected,
            SUM(CASE WHEN p.yt_content_id_status = 'conflict' THEN 1 ELSE 0 END) +
            SUM(CASE WHEN p.fb_monet_status = 'conflict' THEN 1 ELSE 0 END) +
            SUM(CASE WHEN p.tt_monet_status = 'conflict' THEN 1 ELSE 0 END) AS conflict
        FROM $table_p p
        JOIN $table_r r ON p.release_id = r.id
    ");

    $service_labels = [
        'yt_content_id' => [
            'label' => 'YouTube Content ID',
            'col' => 'yt_content_id_status',
            'note_col' => 'yt_content_id_decision_note',
            'conflict_url_col' => 'yt_content_id_conflict_url',
            'conflict_source_col' => 'yt_content_id_conflict_source',
            'color' => '#FF0000',
        ],
        'fb_monet' => [
            'label' => 'Facebook / Instagram',
            'col' => 'fb_monet_status',
            'note_col' => 'fb_monet_decision_note',
            'conflict_url_col' => 'fb_monet_conflict_url',
            'conflict_source_col' => 'fb_monet_conflict_source',
            'color' => '#1877F2',
        ],
        'tt_monet' => [
            'label' => 'TikTok',
            'col' => 'tt_monet_status',
            'note_col' => 'tt_monet_decision_note',
            'conflict_url_col' => 'tt_monet_conflict_url',
            'conflict_source_col' => 'tt_monet_conflict_source',
            'color' => '#010101',
        ],
    ];
    ?>

    <style>
    .rmbz-exc-card { background:#fff; border:1px solid #ccd0d4; border-radius:6px; padding:16px; margin-bottom:18px; box-shadow:0 1px 3px rgba(0,0,0,0.04); }
    .rmbz-exc-head { display:grid; grid-template-columns:90px 1fr; gap:15px; margin-bottom:14px; }
    .rmbz-exc-cover { width:90px; height:90px; border-radius:6px; object-fit:cover; background:#f0f0f0; display:flex; align-items:center; justify-content:center; font-size:32px; color:#bbb; }
    .rmbz-exc-meta { font-size:13px; color:#555; line-height:1.6; }
    .rmbz-exc-meta strong { color:#111; font-size:16px; display:block; margin-bottom:4px; }
    .rmbz-exc-meta code { background:#f6f7f7; padding:1px 6px; border-radius:3px; font-size:12px; }
    .rmbz-exc-search { background:#fafafa; border:1px solid #e5e5e5; border-radius:4px; padding:10px 12px; margin:10px 0; }
    .rmbz-exc-search h4 { margin:0 0 8px 0; font-size:12px; text-transform:uppercase; letter-spacing:0.5px; color:#666; }
    .rmbz-exc-search-btns { display:flex; flex-wrap:wrap; gap:6px; }
    .rmbz-exc-search-btn { display:inline-flex; align-items:center; gap:4px; padding:4px 10px; background:#fff; border:1px solid #ccc; border-radius:14px; font-size:12px; color:var(--wp-admin-theme-color, #2271b1); text-decoration:none; transition:all 0.15s; }
    .rmbz-exc-search-btn:hover { background:var(--wp-admin-theme-color, #2271b1); color:#fff; border-color:var(--wp-admin-theme-color, #2271b1); }
    .rmbz-exc-audio { margin:10px 0 14px 0; }
    .rmbz-exc-audio audio { width:100%; height:36px; }
    .rmbz-exc-audio-none { color:#999; font-style:italic; font-size:12px; padding:8px; background:#f6f7f7; border-radius:4px; }
    .rmbz-exc-tracks-list { margin:8px 0 14px 0; background:#f6f7f7; border:1px solid #e5e5e5; border-radius:4px; }
    .rmbz-exc-tracks-list .rmbz-exc-track-row { display:grid; grid-template-columns:30px 1fr 1fr; gap:10px; padding:8px 12px; border-bottom:1px solid #e5e5e5; align-items:center; font-size:13px; }
    .rmbz-exc-tracks-list .rmbz-exc-track-row:last-child { border-bottom:none; }
    .rmbz-exc-tracks-list .rmbz-exc-track-num { color:#888; font-weight:bold; }
    .rmbz-exc-service-row { border-top:1px solid #eee; padding:12px 0; display:grid; grid-template-columns:200px 1fr auto; gap:15px; align-items:flex-start; }
    .rmbz-exc-svc-dot { display:inline-block; width:10px; height:10px; border-radius:50%; margin-right:6px; vertical-align:middle; }
    .rmbz-badge { display:inline-block; padding:3px 10px; border-radius:10px; font-size:12px; font-weight:600; }
    .rmbz-badge-requested { background:#fff3cd; color:#856404; }
    .rmbz-badge-approved  { background:#d4edda; color:#155724; }
    .rmbz-badge-rejected  { background:#f8d7da; color:#721c24; }
    .rmbz-badge-conflict  { background:#ffeaa7; color:#8b6914; border:1px solid #f0b90b; }
    .rmbz-decision-box { margin-top:10px; padding:12px; background:#f6f7f7; border:1px solid #ddd; border-radius:4px; min-width:380px; }
    .rmbz-decision-box h5 { margin:0 0 8px 0; font-size:11px; text-transform:uppercase; letter-spacing:0.5px; color:#888; }
    .rmbz-decision-box form { margin:0 0 10px 0; padding-bottom:10px; border-bottom:1px dashed #ddd; }
    .rmbz-decision-box form:last-child { border-bottom:none; padding-bottom:0; margin-bottom:0; }
    .rmbz-decision-box input[type="url"], .rmbz-decision-box input[type="text"], .rmbz-decision-box textarea { width:100%; box-sizing:border-box; margin-bottom:5px; }
    .rmbz-conflict-details { margin-top:6px; padding:8px; background:#fffaf0; border-left:3px solid #f0b90b; border-radius:3px; font-size:12px; }
    .rmbz-conflict-details a { word-break:break-all; }

    /* ════════ Barra de pesquisa + contador + paginação [ESCALA 50k] ════════ */
    .rmbz-exc-toolbar {
        display:flex; flex-wrap:wrap; align-items:center; gap:12px;
        background:#fff; border:1px solid #e6e8eb; border-radius:12px;
        padding:12px 14px; margin-bottom:16px;
        box-shadow:0 1px 2px rgba(16,24,40,0.04);
    }
    .rmbz-exc-searchbox {
        flex:1; min-width:260px; display:flex; align-items:center; gap:8px;
        background:#f6f7f9; border:1px solid #e2e5e9; border-radius:9px;
        padding:0 12px; height:42px; transition:border-color .15s, box-shadow .15s;
    }
    .rmbz-exc-searchbox:focus-within {
        border-color:var(--wp-admin-theme-color, #2271b1);
        box-shadow:0 0 0 3px rgba(34,113,177,0.12); background:#fff;
    }
    .rmbz-exc-searchbox svg { flex-shrink:0; color:#8a909a; }
    .rmbz-exc-searchbox input {
        flex:1; border:none; background:transparent; outline:none; box-shadow:none;
        font-size:14px; color:#1a1a1a; padding:0; height:40px;
    }
    .rmbz-exc-searchbox input:focus { border:none; box-shadow:none; outline:none; }
    .rmbz-exc-search-clear {
        flex-shrink:0; text-decoration:none; color:#8a909a; font-size:18px;
        line-height:1; padding:2px 4px; border-radius:50%;
    }
    .rmbz-exc-search-clear:hover { background:#e2e5e9; color:#555; }
    .rmbz-exc-toolbar .button { height:42px; display:inline-flex; align-items:center; border-radius:9px; }
    .rmbz-exc-count {
        font-size:13px; color:#6b7280; font-weight:600; white-space:nowrap;
    }
    .rmbz-exc-count strong { color:#1a1a1a; }
    .rmbz-exc-count .rmbz-exc-count-search { color:var(--wp-admin-theme-color, #2271b1); }

    .rmbz-exc-pagination {
        display:flex; justify-content:center; align-items:center; gap:6px;
        margin-top:20px; flex-wrap:wrap;
    }
    .rmbz-exc-pagination a, .rmbz-exc-pagination span {
        min-width:36px; height:36px; padding:0 10px; border-radius:9px;
        display:inline-flex; align-items:center; justify-content:center;
        font-size:13px; font-weight:600; text-decoration:none;
        border:1px solid #e2e5e9; background:#fff; color:#374151;
        transition:all .12s;
    }
    .rmbz-exc-pagination a:hover { border-color:var(--wp-admin-theme-color, #2271b1); color:var(--wp-admin-theme-color, #2271b1); }
    .rmbz-exc-pagination .is-current {
        background:var(--wp-admin-theme-color, #2271b1); border-color:var(--wp-admin-theme-color, #2271b1); color:#fff;
    }
    .rmbz-exc-pagination .is-disabled { opacity:.4; pointer-events:none; }
    .rmbz-exc-pagination .rmbz-exc-pg-gap { border:none; background:transparent; min-width:auto; padding:0 2px; color:#9ca3af; }
    </style>

    <div class="wrap">
        <h1 class="wp-heading-inline">⭐ Serviços Exclusivos</h1>
        <p style="color:#666; max-width:800px;">
            Gestão de pedidos de artistas para YouTube Content ID, Facebook/Instagram Rights Manager e TikTok Monetization.
            <strong>Estes serviços exigem revisão manual</strong> porque um erro causa conflitos de propriedade com outros
            distribuidores e pode resultar em bloqueio da conta CMS.
        </p>

        <?php if ( isset($_GET['msg']) && $_GET['msg'] === 'exclusive_decided' ): ?>
            <div class="notice notice-success is-dismissible"><p>Decisão guardada e artista notificado.</p></div>
        <?php endif; ?>

        <?php if ( isset($_GET['msg']) && $_GET['msg'] === 'orphans_cleaned' ): ?>
            <div class="notice notice-success is-dismissible"><p>🧹 Limpos <?php echo (int) ($_GET['deleted'] ?? 0); ?> registos órfãos.</p></div>
        <?php endif; ?>

        <?php if ( $orphan_count > 0 ): ?>
            <div class="notice notice-warning">
                <p>
                    ⚠️ Detectados <strong><?php echo $orphan_count; ?></strong> registos órfãos em <code><?php echo $wpdb->prefix; ?>rmbz_distro_release_platforms</code>.
                    <?php $cleanup_url = wp_nonce_url( add_query_arg('rmbz_cleanup_orphans', '1'), 'rmbz_cleanup_orphan_platforms' ); ?>
                    <a href="<?php echo esc_url($cleanup_url); ?>" class="button button-small" style="margin-left:10px;"
                       onclick="return confirm('Apagar <?php echo $orphan_count; ?> registos órfãos? Irreversível.');">
                        🧹 Limpar órfãos
                    </a>
                </p>
            </div>
        <?php endif; ?>

        <?php
        /* [1.5.159] URLs ajustadas para o slug correcto:
           ?page=rmbz-admin-distribution&tab=exclusives&filter=...
           Antes apontavam para `rmbz-admin-exclusive-services` que foi
           removido por causar bug de menu pai a esconder. */
        $base_url = '?page=rmbz-admin-distribution&tab=exclusives';
        // Preserva a pesquisa ao trocar de estado (procurar a mesma música
        // em Pendentes/Aprovados/etc. sem reescrever o termo).
        $exc_search_qs = $exc_search !== '' ? '&exc_s=' . urlencode($exc_search) : '';
        ?>
        <h2 class="nav-tab-wrapper" style="margin-bottom:0;">
            <a href="<?php echo esc_attr($base_url . '&filter=requested' . $exc_search_qs); ?>"
               class="nav-tab <?php echo $filter === 'requested' ? 'nav-tab-active' : ''; ?>">
                ⏳ Pendentes <span style="background:var(--rmbz-warning, #f59e0b); color:#fff; padding:1px 8px; border-radius:10px; font-size:11px; margin-left:4px;"><?php echo (int)$counts->pending; ?></span>
            </a>
            <a href="<?php echo esc_attr($base_url . '&filter=approved' . $exc_search_qs); ?>"
               class="nav-tab <?php echo $filter === 'approved' ? 'nav-tab-active' : ''; ?>">
                ✅ Aprovados <span style="background:var(--rmbz-success, #10b981); color:#fff; padding:1px 8px; border-radius:10px; font-size:11px; margin-left:4px;"><?php echo (int)$counts->approved; ?></span>
            </a>
            <a href="<?php echo esc_attr($base_url . '&filter=conflict' . $exc_search_qs); ?>"
               class="nav-tab <?php echo $filter === 'conflict' ? 'nav-tab-active' : ''; ?>">
                ⚠️ Conflitos <span style="background:var(--rmbz-warning-strong, #d97706); color:#fff; padding:1px 8px; border-radius:10px; font-size:11px; margin-left:4px;"><?php echo (int)$counts->conflict; ?></span>
            </a>
            <a href="<?php echo esc_attr($base_url . '&filter=rejected' . $exc_search_qs); ?>"
               class="nav-tab <?php echo $filter === 'rejected' ? 'nav-tab-active' : ''; ?>">
                ❌ Rejeitados <span style="background:var(--rmbz-danger, #ef4444); color:#fff; padding:1px 8px; border-radius:10px; font-size:11px; margin-left:4px;"><?php echo (int)$counts->rejected; ?></span>
            </a>
            <a href="<?php echo esc_attr($base_url); ?>&filter=analytics"
               class="nav-tab <?php echo $filter === 'analytics' ? 'nav-tab-active' : ''; ?>"
               style="margin-left:auto;">
                📊 Análise &amp; Pesquisa
            </a>
        </h2>

        <div style="padding-top:20px;">

        <?php
        // [FEAT 1.6.2] Modo de vista: 'compact' (default) ou 'cards'.
        // Persiste em user_meta para o admin não ter de escolher sempre.
        $view_mode_meta = get_user_meta( get_current_user_id(), 'rmbz_exc_view_mode', true );
        $view_mode = isset($_GET['view_mode'])
            ? sanitize_key($_GET['view_mode'])
            : ( $view_mode_meta ?: 'compact' );
        if ( ! in_array($view_mode, ['compact','cards'], true) ) $view_mode = 'compact';
        // Persistir escolha do utilizador
        if ( isset($_GET['view_mode']) && $_GET['view_mode'] !== $view_mode_meta ) {
            update_user_meta( get_current_user_id(), 'rmbz_exc_view_mode', $view_mode );
        }

        // Toggle visual
        $base_filter_url = $base_url . '&filter=' . esc_attr($filter);
        ?>
        <div class="rmbz-exc-view-toggle">
            <span>Vista:</span>
            <a href="<?php echo esc_url( $base_filter_url . '&view_mode=compact' ); ?>"
               class="<?php echo $view_mode === 'compact' ? 'is-active' : ''; ?>"
               title="Uma linha por música — ideal para processar muitas rapidamente">
                ☰ Compacta
            </a>
            <a href="<?php echo esc_url( $base_filter_url . '&view_mode=cards' ); ?>"
               class="<?php echo $view_mode === 'cards' ? 'is-active' : ''; ?>"
               title="Cards grandes com player e pesquisa externa">
                🗂 Cards
            </a>
            <span class="rmbz-exc-view-tip">
                Atalhos: <kbd>↑</kbd>/<kbd>↓</kbd> navegar · <kbd>A</kbd> aprovar · <kbd>R</kbd> rejeitar · <kbd>C</kbd> conflito · <kbd>Espaço</kbd> play
            </span>
        </div>

        <?php
        // Sumário de URL para a paginação (preserva filtro, vista e pesquisa).
        $exc_page_base = $base_url . '&filter=' . esc_attr($filter)
            . '&view_mode=' . esc_attr($view_mode)
            . ( $exc_search !== '' ? '&exc_s=' . urlencode($exc_search) : '' );
        ?>
        <form method="get" class="rmbz-exc-toolbar" action="">
            <input type="hidden" name="page" value="rmbz-admin-distribution">
            <input type="hidden" name="tab" value="exclusives">
            <input type="hidden" name="filter" value="<?php echo esc_attr($filter); ?>">
            <input type="hidden" name="view_mode" value="<?php echo esc_attr($view_mode); ?>">
            <label class="rmbz-exc-searchbox">
                <svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"><circle cx="11" cy="11" r="7"></circle><line x1="21" y1="21" x2="16.5" y2="16.5"></line></svg>
                <input type="search" name="exc_s" value="<?php echo esc_attr($exc_search); ?>"
                       placeholder="Pesquisar por música, artista, telemóvel ou ISRC…" autocomplete="off">
                <?php if ( $exc_search !== '' ): ?>
                    <a href="<?php echo esc_url( $base_url . '&filter=' . esc_attr($filter) . '&view_mode=' . esc_attr($view_mode) ); ?>"
                       class="rmbz-exc-search-clear" title="Limpar pesquisa">×</a>
                <?php endif; ?>
            </label>
            <button type="submit" class="button button-primary">Pesquisar</button>
            <span class="rmbz-exc-count">
                <?php if ( $exc_search !== '' ): ?>
                    <strong><?php echo (int) $exc_total; ?></strong> resultado<?php echo $exc_total === 1 ? '' : 's'; ?>
                    para “<span class="rmbz-exc-count-search"><?php echo esc_html($exc_search); ?></span>”
                <?php else: ?>
                    <strong><?php echo (int) $exc_total; ?></strong> registo<?php echo $exc_total === 1 ? '' : 's'; ?>
                <?php endif; ?>
            </span>
        </form>

        <?php if ( empty($rows) ): ?>
            <div style="background:#fff; border:1px solid #ccd0d4; border-radius:12px; padding:40px 30px; text-align:center; color:#666;">
                <?php if ( $exc_search !== '' ): ?>
                    <p style="font-size:16px; margin:0 0 6px;">Nenhum resultado para “<strong><?php echo esc_html($exc_search); ?></strong>” neste estado.</p>
                    <p style="margin:0; font-size:13px; color:#999;">Tenta noutro separador ou limpa a pesquisa.</p>
                <?php else: ?>
                    <p style="font-size:16px; margin:0;">Sem pedidos neste filtro.</p>
                <?php endif; ?>
            </div>
        <?php elseif ( $view_mode === 'compact' ): ?>

            <?php rmbz_render_exclusive_compact_rows( $rows, $filter, $service_labels, $wpdb, $table_t ); ?>

        <?php else: ?>

            <?php foreach ( $rows as $row ):
                // Carregar faixas do release para mostrar leitor + ISRC.
                $tracks = $wpdb->get_results( $wpdb->prepare(
                    "SELECT id, track_title, audio_url, isrc_code, track_order
                     FROM $table_t
                     WHERE release_id = %d
                     ORDER BY track_order ASC, id ASC
                     LIMIT 20",
                    $row->release_id
                ) );

                // Primeira faixa — é esta que o admin vai ouvir e pesquisar
                // (assumindo que um release é normalmente um single; se é EP/álbum
                // o admin pode abrir o release completo para ver o resto).
                $primary_track = $tracks[0] ?? null;
                $primary_title = $primary_track->track_title ?? $row->release_title;
                $primary_isrc  = $primary_track->isrc_code ?? '';
                $primary_audio = $primary_track->audio_url ?? '';
                $artist_name   = $row->user_nome ?: $row->artist_telemovel;

                $search_links = rmbz_exclusive_build_search_links( $primary_title, $artist_name, $primary_isrc );
            ?>
            <div class="rmbz-exc-card">
                <div class="rmbz-exc-head">
                    <?php if ( $row->cover_image ): ?>
                        <img src="<?php echo esc_url($row->cover_image); ?>" class="rmbz-exc-cover" alt="">
                    <?php else: ?>
                        <div class="rmbz-exc-cover">🎵</div>
                    <?php endif; ?>
                    <div class="rmbz-exc-meta">
                        <strong><?php echo esc_html($row->release_title); ?></strong>
                        👤 <?php echo esc_html($artist_name); ?> &middot;
                        📞 <code><?php echo esc_html($row->artist_telemovel); ?></code> &middot;
                        Release <code>#<?php echo (int)$row->release_id; ?></code>
                        <?php if ($primary_isrc): ?> &middot; ISRC <code><?php echo esc_html($primary_isrc); ?></code><?php endif; ?>
                        <br>
                        <?php /* [1.5.125] URL corrigida: antes apontava para
                            ?tab=dashboard&release=ID, mas o roteamento canónico
                            de detalhe de release é ?tab=releases&view=detail&id=ID
                            (como em admin-distribution-controller.php:399 e
                            outros 7 sítios). O parâmetro 'release' não era
                            lido por ninguém — daí o link parecer levar
                            para o sítio errado. */ ?>
                        <a href="<?php echo esc_url( admin_url('admin.php?page=rmbz-admin-distribution&tab=releases&view=detail&id=' . (int) $row->release_id) ); ?>"
                           class="button button-small" style="margin-top:6px;">Ver release completo →</a>
                    </div>
                </div>

                <div class="rmbz-exc-audio">
                    <?php if ( $primary_audio ): ?>
                        <audio controls preload="none" src="<?php echo esc_url($primary_audio); ?>"></audio>
                    <?php else: ?>
                        <div class="rmbz-exc-audio-none">⚠ Sem ficheiro de áudio disponível para esta faixa.</div>
                    <?php endif; ?>
                </div>

                <?php if ( count($tracks) > 1 ): ?>
                    <div class="rmbz-exc-tracks-list">
                        <?php foreach ( $tracks as $i => $t ): ?>
                        <div class="rmbz-exc-track-row">
                            <span class="rmbz-exc-track-num"><?php echo (int)($t->track_order ?: ($i+1)); ?>.</span>
                            <span>
                                <strong><?php echo esc_html($t->track_title); ?></strong>
                                <?php if ($t->isrc_code): ?><br><small style="color:#888;">ISRC: <code><?php echo esc_html($t->isrc_code); ?></code></small><?php endif; ?>
                            </span>
                            <span>
                                <?php if ($t->audio_url): ?>
                                    <audio controls preload="none" style="width:100%; height:28px;" src="<?php echo esc_url($t->audio_url); ?>"></audio>
                                <?php else: ?>
                                    <small style="color:#aaa;">— sem áudio —</small>
                                <?php endif; ?>
                            </span>
                        </div>
                        <?php endforeach; ?>
                    </div>
                <?php endif; ?>

                <div class="rmbz-exc-search">
                    <h4>🔎 Pesquisa externa — verificar se a música já está noutro distribuidor</h4>
                    <div class="rmbz-exc-search-btns">
                        <?php foreach ( $search_links as $k => $link ): ?>
                            <a href="<?php echo esc_url($link['url']); ?>" target="_blank" rel="noopener noreferrer"
                               class="rmbz-exc-search-btn" title="<?php echo esc_attr($link['hint']); ?>">
                                <?php echo $link['label']; // label já contém emoji, sem escape pra emoji renderizar ?>
                                <span style="font-size:10px; opacity:0.6;">↗</span>
                            </a>
                        <?php endforeach; ?>
                    </div>
                    <p style="margin:8px 0 0 0; font-size:11px; color:#888;">
                        💡 Se encontrares a música em YouTube Music/Spotify publicada por outro distribuidor ou vires UGC com Content ID ativo de outro titular, é um conflito — <strong>não aprovar</strong>, marcar conflito.
                    </p>
                </div>

                <?php foreach ( $service_labels as $key => $svc ):
                    $status = $row->{$svc['col']};
                    if ( $status === 'not_requested' ) continue;

                    $conflict_url    = $row->{$svc['conflict_url_col']}    ?? '';
                    $conflict_source = $row->{$svc['conflict_source_col']} ?? '';
                    $note            = $row->{$svc['note_col']}             ?? '';
                ?>
                <div class="rmbz-exc-service-row">
                    <div>
                        <span class="rmbz-exc-svc-dot" style="background:<?php echo esc_attr($svc['color']); ?>;"></span>
                        <strong style="font-size:13px;"><?php echo esc_html($svc['label']); ?></strong>
                    </div>

                    <div>
                        <?php
                        $badge_map = [
                            'requested' => [ 'class' => 'rmbz-badge-requested', 'txt' => '⏳ Aguarda decisão' ],
                            'approved'  => [ 'class' => 'rmbz-badge-approved',  'txt' => '✅ Aprovado' ],
                            'rejected'  => [ 'class' => 'rmbz-badge-rejected',  'txt' => '❌ Rejeitado' ],
                            'conflict'  => [ 'class' => 'rmbz-badge-conflict',  'txt' => '⚠️ Conflito' ],
                        ];
                        $b = $badge_map[$status] ?? null;
                        if ( $b ): ?>
                            <span class="rmbz-badge <?php echo $b['class']; ?>"><?php echo $b['txt']; ?></span>
                        <?php endif; ?>

                        <?php if ( $note ): ?>
                            <div style="margin-top:5px; font-size:12px; color:#555;">
                                <strong>Nota:</strong> <?php echo esc_html($note); ?>
                            </div>
                        <?php endif; ?>

                        <?php if ( $status === 'conflict' && ($conflict_url || $conflict_source) ): ?>
                            <div class="rmbz-conflict-details">
                                <?php if ($conflict_source): ?>
                                    <div><strong>Fonte suspeita:</strong> <?php echo esc_html($conflict_source); ?></div>
                                <?php endif; ?>
                                <?php if ($conflict_url): ?>
                                    <div><strong>Evidência:</strong> <a href="<?php echo esc_url($conflict_url); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html($conflict_url); ?></a></div>
                                <?php endif; ?>
                            </div>
                        <?php endif; ?>
                    </div>

                    <div>
                        <?php if ( in_array( $status, ['requested','conflict','rejected'], true ) ): ?>
                            <details <?php echo $status === 'requested' ? '' : ''; ?>>
                                <summary style="cursor:pointer; color:var(--wp-admin-theme-color, #2271b1); font-size:13px; white-space:nowrap;">
                                    <?php echo $status === 'requested' ? 'Decidir' : 'Alterar decisão'; ?>
                                </summary>
                                <div class="rmbz-decision-box">

                                    <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
                                        <h5>✅ Aprovar</h5>
                                        <?php wp_nonce_field('rmbz_decide_exclusive'); ?>
                                        <input type="hidden" name="action" value="rmbz_decide_exclusive">
                                        <input type="hidden" name="release_id" value="<?php echo (int)$row->release_id; ?>">
                                        <input type="hidden" name="service" value="<?php echo esc_attr($key); ?>">
                                        <input type="hidden" name="decision" value="approved">
                                        <textarea name="note" rows="2" placeholder="Nota opcional (visível ao artista)"></textarea>
                                        <button type="submit" class="button button-primary" style="width:100%;">✅ Aprovar</button>
                                    </form>

                                    <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
                                        <h5>⚠️ Marcar conflito</h5>
                                        <?php wp_nonce_field('rmbz_decide_exclusive'); ?>
                                        <input type="hidden" name="action" value="rmbz_decide_exclusive">
                                        <input type="hidden" name="release_id" value="<?php echo (int)$row->release_id; ?>">
                                        <input type="hidden" name="service" value="<?php echo esc_attr($key); ?>">
                                        <input type="hidden" name="decision" value="conflict">
                                        <input type="url" name="conflict_url"
                                               placeholder="URL da evidência (ex: vídeo YouTube, página Spotify)"
                                               value="<?php echo esc_attr($conflict_url); ?>">
                                        <input type="text" name="conflict_source"
                                               placeholder="Distribuidor / titular suspeito (ex: DistroKid, Nome Label, etc.)"
                                               value="<?php echo esc_attr($conflict_source); ?>">
                                        <textarea name="note" rows="2" required
                                                  placeholder="Descrição do conflito (obrigatório — visível ao artista)"><?php echo esc_textarea($note); ?></textarea>
                                        <button type="submit" class="button" style="width:100%; background:#ffeaa7; color:#8b6914; border-color:#f0b90b; font-weight:bold;">⚠️ Marcar conflito</button>
                                    </form>

                                    <form method="post" action="<?php echo esc_url(admin_url('admin-post.php')); ?>">
                                        <h5>❌ Rejeitar</h5>
                                        <?php wp_nonce_field('rmbz_decide_exclusive'); ?>
                                        <input type="hidden" name="action" value="rmbz_decide_exclusive">
                                        <input type="hidden" name="release_id" value="<?php echo (int)$row->release_id; ?>">
                                        <input type="hidden" name="service" value="<?php echo esc_attr($key); ?>">
                                        <input type="hidden" name="decision" value="rejected">
                                        <textarea name="note" rows="2" required placeholder="Motivo da rejeição (obrigatório)"></textarea>
                                        <button type="submit" class="button" style="width:100%; color:#b32d2e; border-color:#b32d2e;">❌ Rejeitar</button>
                                    </form>

                                </div>
                            </details>
                        <?php endif; ?>

                        <?php if ( in_array($status, ['approved','rejected','conflict'], true) && $row->decided_by ): ?>
                            <div style="color:#999; font-size:11px; margin-top:6px; text-align:right;">
                                por <?php echo esc_html($row->decided_by); ?><br>
                                <?php echo esc_html( mysql2date('d/m/Y H:i', $row->decided_at) ); ?>
                            </div>
                        <?php endif; ?>
                    </div>
                </div>
                <?php endforeach; ?>

            </div>
            <?php endforeach; ?>

        <?php endif; ?>

        <?php
        // ── Paginação server-side [ESCALA 50k] ──────────────────────────
        if ( $exc_total_pages > 1 ):
            $pg_link = function( $n ) use ( $exc_page_base ) {
                return esc_url( $exc_page_base . '&exc_paged=' . (int) $n );
            };
            // Janela de páginas em torno da atual.
            $win_start = max( 1, $exc_paged - 2 );
            $win_end   = min( $exc_total_pages, $exc_paged + 2 );
        ?>
            <div class="rmbz-exc-pagination">
                <?php if ( $exc_paged > 1 ): ?>
                    <a href="<?php echo $pg_link( $exc_paged - 1 ); ?>">‹ Anterior</a>
                <?php else: ?>
                    <span class="is-disabled">‹ Anterior</span>
                <?php endif; ?>

                <?php if ( $win_start > 1 ): ?>
                    <a href="<?php echo $pg_link(1); ?>">1</a>
                    <?php if ( $win_start > 2 ): ?><span class="rmbz-exc-pg-gap">…</span><?php endif; ?>
                <?php endif; ?>

                <?php for ( $i = $win_start; $i <= $win_end; $i++ ): ?>
                    <?php if ( $i === $exc_paged ): ?>
                        <span class="is-current"><?php echo $i; ?></span>
                    <?php else: ?>
                        <a href="<?php echo $pg_link($i); ?>"><?php echo $i; ?></a>
                    <?php endif; ?>
                <?php endfor; ?>

                <?php if ( $win_end < $exc_total_pages ): ?>
                    <?php if ( $win_end < $exc_total_pages - 1 ): ?><span class="rmbz-exc-pg-gap">…</span><?php endif; ?>
                    <a href="<?php echo $pg_link($exc_total_pages); ?>"><?php echo $exc_total_pages; ?></a>
                <?php endif; ?>

                <?php if ( $exc_paged < $exc_total_pages ): ?>
                    <a href="<?php echo $pg_link( $exc_paged + 1 ); ?>">Seguinte ›</a>
                <?php else: ?>
                    <span class="is-disabled">Seguinte ›</span>
                <?php endif; ?>
            </div>
        <?php endif; ?>
        </div>

        <div style="background:#fff; padding:15px; margin-top:30px; border:1px solid #ccd0d4; border-left:4px solid #f0b90b;">
            <h3 style="margin-top:0;">💡 Como funciona o workflow</h3>
            <ol style="margin:0; line-height:1.8;">
                <li>No wizard (passo 2), o artista pode pedir opt-in para os 3 serviços exclusivos.</li>
                <li>O pedido fica com status <code>requested</code> até aqui decidires.</li>
                <li><strong>Antes de aprovar:</strong> ouve a faixa, faz as pesquisas externas (YouTube Music, Spotify, TikTok, etc.) e verifica se a mesma música já está publicada por outro distribuidor. Se estiver → conflito.</li>
                <li><strong>✅ Aprovar:</strong> o serviço fica ativo para esse release — o importador capta royalties desse canal.</li>
                <li><strong>⚠️ Marcar conflito:</strong> a música parece já estar registada por outro titular. O artista recebe notificação com evidência. Não é rejeição definitiva — pode ser resolvida se o artista clarificar que tem os direitos exclusivos.</li>
                <li><strong>❌ Rejeitar:</strong> pedido negado por motivo não-conflito (ex: música não cumpre critérios, samples não-limpos, beat licenciado não-exclusivo).</li>
                <li>Uma decisão pode sempre ser revertida clicando em "Alterar decisão" num card já decidido.</li>
            </ol>
        </div>

    </div>
    <?php
}

/* ============================================================================
 * [FEAT 1.6.0] ABA ANALÍTICO — vista completa de gestão pós-aprovação
 *
 * Esta aba é diferente das outras 5 que servem para WORKFLOW de aprovação.
 * Aqui o admin CONSULTA o estado das músicas em cada um dos 3 serviços
 * (YouTube Content ID, Facebook/Instagram, TikTok), filtra por artista,
 * vê evolução mensal, e pode desactivar uma música de um serviço específico
 * quando aparece um conflito posterior.
 *
 * Estrutura:
 *   1. KPIs no topo (4 cards: total activos + 1 por serviço)
 *   2. Gráfico SVG inline de evolução mensal (aprovações por mês, por serviço)
 *   3. Filtros (pesquisa + data + género + serviço + estado)
 *   4. Tabela cruzada artista × serviço × estado (resumo)
 *   5. Lista compacta de músicas (cada linha = uma release com badges)
 *   6. Modal de detalhe ao clicar "Ver" (com botão Desactivar)
 *   7. Export CSV via ?export=csv
 * ============================================================================ */

/**
 * Handler do export CSV. Tem de correr ANTES de qualquer output.
 * Hookado em 'admin_init' com prioridade alta.
 */
add_action( 'admin_init', function () {
    if ( ! isset( $_GET['page'], $_GET['tab'], $_GET['filter'], $_GET['export'] ) ) return;
    if ( $_GET['page'] !== 'rmbz-admin-distribution' ) return;
    if ( $_GET['tab'] !== 'exclusives' ) return;
    if ( $_GET['filter'] !== 'analytics' ) return;
    if ( $_GET['export'] !== 'csv' ) return;
    if ( ! current_user_can( 'manage_options' ) ) wp_die( 'Sem permissão.' );

    global $wpdb;
    $rows = rmbz_exclusive_analytics_query_rows( $wpdb, $_GET, 5000 );

    header( 'Content-Type: text/csv; charset=utf-8' );
    header( 'Content-Disposition: attachment; filename=servicos-exclusivos-' . date('Y-m-d-Hi') . '.csv' );
    $out = fopen( 'php://output', 'w' );
    // BOM para Excel reconhecer UTF-8
    fwrite( $out, "\xEF\xBB\xBF" );
    fputcsv( $out, ['Release', 'Artista', 'Telemovel', 'ISRC', 'YouTube Content ID', 'Facebook/IG', 'TikTok', 'Actualizado em'] );
    foreach ( $rows as $r ) {
        fputcsv( $out, [
            $r->release_title,
            $r->user_nome ?: '(sem nome)',
            $r->artist_telemovel,
            $r->primary_isrc ?? '',
            $r->yt_content_id_status,
            $r->fb_monet_status,
            $r->tt_monet_status,
            $r->updated_at,
        ] );
    }
    fclose( $out );
    exit;
}, 9 );


/**
 * Query reutilizada pelo render e pelo export.
 * Aplica todos os filtros do _GET aos rows.
 */
function rmbz_exclusive_analytics_query_rows( $wpdb, $params, $limit = 200 ) {
    $table_p = $wpdb->prefix . 'rmbz_distro_release_platforms';
    $table_r = $wpdb->prefix . 'rmbz_distro_releases';
    $table_t = $wpdb->prefix . 'rmbz_distro_tracks';
    $table_w = $wpdb->prefix . 'rmbz_wallets';

    // Pesquisa (artista, título, ISRC, telemóvel)
    $search = isset($params['s']) ? trim( sanitize_text_field( wp_unslash($params['s']) ) ) : '';
    // Filtro por serviço (yt|fb|tt|any)
    $svc = isset($params['svc']) ? sanitize_key($params['svc']) : 'any';
    if ( ! in_array($svc, ['yt','fb','tt','any'], true) ) $svc = 'any';
    // Filtro por estado (approved|rejected|conflict|requested|any)
    $st = isset($params['st']) ? sanitize_key($params['st']) : 'any';
    if ( ! in_array($st, ['approved','rejected','conflict','requested','any'], true) ) $st = 'any';

    $where_parts = [
        "(p.yt_content_id_status != 'not_requested' OR p.fb_monet_status != 'not_requested' OR p.tt_monet_status != 'not_requested')",
    ];

    // Combinar serviço + estado em cláusulas SQL
    if ( $st !== 'any' ) {
        if ( $svc === 'yt' ) {
            $where_parts[] = $wpdb->prepare( "p.yt_content_id_status = %s", $st );
        } elseif ( $svc === 'fb' ) {
            $where_parts[] = $wpdb->prepare( "p.fb_monet_status = %s", $st );
        } elseif ( $svc === 'tt' ) {
            $where_parts[] = $wpdb->prepare( "p.tt_monet_status = %s", $st );
        } else {
            // qualquer serviço com este estado
            $where_parts[] = $wpdb->prepare(
                "(p.yt_content_id_status = %s OR p.fb_monet_status = %s OR p.tt_monet_status = %s)",
                $st, $st, $st
            );
        }
    } elseif ( $svc !== 'any' ) {
        // só serviço definido, sem estado — exige que esse serviço tenha alguma actividade
        $col = ['yt'=>'yt_content_id_status', 'fb'=>'fb_monet_status', 'tt'=>'tt_monet_status'][$svc];
        $where_parts[] = "p.$col != 'not_requested'";
    }

    if ( $search !== '' ) {
        $like = '%' . $wpdb->esc_like($search) . '%';
        // ISRC procura nas faixas reais — não existe coluna primary_isrc.
        $where_parts[] = $wpdb->prepare(
            "(r.title LIKE %s OR w.user_nome LIKE %s OR r.artist_telemovel LIKE %s
              OR EXISTS (SELECT 1 FROM $table_t tk WHERE tk.release_id = r.id AND tk.isrc_code LIKE %s))",
            $like, $like, $like, $like
        );
    }

    // Data desde
    $date_from = isset($params['from']) ? sanitize_text_field( wp_unslash($params['from']) ) : '';
    if ( $date_from && preg_match('/^\d{4}-\d{2}-\d{2}$/', $date_from) ) {
        $where_parts[] = $wpdb->prepare( "p.updated_at >= %s", $date_from . ' 00:00:00' );
    }
    $date_to = isset($params['to']) ? sanitize_text_field( wp_unslash($params['to']) ) : '';
    if ( $date_to && preg_match('/^\d{4}-\d{2}-\d{2}$/', $date_to) ) {
        $where_parts[] = $wpdb->prepare( "p.updated_at <= %s", $date_to . ' 23:59:59' );
    }

    $where = implode( ' AND ', $where_parts );
    $limit = (int) $limit;

    // primary_isrc vem da 1ª faixa do release (subquery) — não há coluna
    // dedicada na tabela de plataformas. Resolve o ISRC vazio na lista,
    // no modal e no export CSV.
    return $wpdb->get_results(
        "SELECT p.*, r.title AS release_title, r.artist_telemovel, r.cover_image, w.user_nome,
                (SELECT tk.isrc_code FROM $table_t tk
                  WHERE tk.release_id = r.id AND tk.isrc_code IS NOT NULL AND tk.isrc_code != ''
                  ORDER BY tk.track_order ASC, tk.id ASC LIMIT 1) AS primary_isrc
         FROM $table_p p
         JOIN $table_r r ON p.release_id = r.id
         LEFT JOIN $table_w w ON r.artist_telemovel = w.user_telemovel
         WHERE $where
         ORDER BY p.updated_at DESC
         LIMIT $limit"
    );
}


/**
 * Função principal de render da aba Analítico.
 */
function rmbz_render_exclusive_analytics_page( $table_p, $table_r, $table_t, $table_w ) {
    global $wpdb;

    // ── 1. KPIs ──────────────────────────────────────────────────────────
    // Totais por serviço por estado
    $kpi = $wpdb->get_row("
        SELECT
            SUM(CASE WHEN p.yt_content_id_status = 'approved' THEN 1 ELSE 0 END) AS yt_ok,
            SUM(CASE WHEN p.yt_content_id_status = 'requested' THEN 1 ELSE 0 END) AS yt_pend,
            SUM(CASE WHEN p.yt_content_id_status = 'conflict' THEN 1 ELSE 0 END) AS yt_conf,
            SUM(CASE WHEN p.yt_content_id_status = 'rejected' THEN 1 ELSE 0 END) AS yt_rej,

            SUM(CASE WHEN p.fb_monet_status = 'approved' THEN 1 ELSE 0 END) AS fb_ok,
            SUM(CASE WHEN p.fb_monet_status = 'requested' THEN 1 ELSE 0 END) AS fb_pend,
            SUM(CASE WHEN p.fb_monet_status = 'conflict' THEN 1 ELSE 0 END) AS fb_conf,
            SUM(CASE WHEN p.fb_monet_status = 'rejected' THEN 1 ELSE 0 END) AS fb_rej,

            SUM(CASE WHEN p.tt_monet_status = 'approved' THEN 1 ELSE 0 END) AS tt_ok,
            SUM(CASE WHEN p.tt_monet_status = 'requested' THEN 1 ELSE 0 END) AS tt_pend,
            SUM(CASE WHEN p.tt_monet_status = 'conflict' THEN 1 ELSE 0 END) AS tt_conf,
            SUM(CASE WHEN p.tt_monet_status = 'rejected' THEN 1 ELSE 0 END) AS tt_rej
        FROM $table_p p
        JOIN $table_r r ON p.release_id = r.id
    ");

    $total_active = (int) $kpi->yt_ok + (int) $kpi->fb_ok + (int) $kpi->tt_ok;

    // ── 2. Evolução mensal (últimos 6 meses) ─────────────────────────────
    $monthly = $wpdb->get_results("
        SELECT
            DATE_FORMAT(p.updated_at, '%Y-%m') AS m,
            SUM(CASE WHEN p.yt_content_id_status = 'approved' THEN 1 ELSE 0 END) AS yt,
            SUM(CASE WHEN p.fb_monet_status = 'approved' THEN 1 ELSE 0 END) AS fb,
            SUM(CASE WHEN p.tt_monet_status = 'approved' THEN 1 ELSE 0 END) AS tt
        FROM $table_p p
        JOIN $table_r r ON p.release_id = r.id
        WHERE p.updated_at >= DATE_SUB(NOW(), INTERVAL 6 MONTH)
        GROUP BY m
        ORDER BY m ASC
    ");

    // ── 3. Tabela cruzada por artista (top 20 por nº de aprovações) ──────
    $top_artists = $wpdb->get_results("
        SELECT
            r.artist_telemovel,
            w.user_nome,
            SUM(CASE WHEN p.yt_content_id_status = 'approved' THEN 1 ELSE 0 END) AS yt_ok,
            SUM(CASE WHEN p.fb_monet_status = 'approved' THEN 1 ELSE 0 END) AS fb_ok,
            SUM(CASE WHEN p.tt_monet_status = 'approved' THEN 1 ELSE 0 END) AS tt_ok,
            SUM(CASE WHEN p.yt_content_id_status = 'conflict' OR p.fb_monet_status = 'conflict' OR p.tt_monet_status = 'conflict' THEN 1 ELSE 0 END) AS conf,
            COUNT(*) AS total
        FROM $table_p p
        JOIN $table_r r ON p.release_id = r.id
        LEFT JOIN $table_w w ON r.artist_telemovel = w.user_telemovel
        WHERE (p.yt_content_id_status != 'not_requested' OR p.fb_monet_status != 'not_requested' OR p.tt_monet_status != 'not_requested')
        GROUP BY r.artist_telemovel
        ORDER BY (yt_ok + fb_ok + tt_ok) DESC
        LIMIT 20
    ");

    // ── 4. Lista detalhada (com filtros aplicados) ───────────────────────
    // [ESCALA 50k] Pede 1 a mais do que o limite para detetar truncamento.
    $an_limit = 200;
    $rows = rmbz_exclusive_analytics_query_rows( $wpdb, $_GET, $an_limit + 1 );
    $an_truncated = count( $rows ) > $an_limit;
    if ( $an_truncated ) {
        $rows = array_slice( $rows, 0, $an_limit );
    }

    // URL base preservando os filtros (para export CSV)
    $export_url = add_query_arg( array_merge( $_GET, ['export' => 'csv'] ) );
    ?>
    <div class="rmbz-excl-analytics">
        <h2 style="margin:18px 0 6px;">📊 Análise &amp; Pesquisa</h2>

        <?php
        $an_msg = isset($_GET['msg']) ? sanitize_key($_GET['msg']) : '';
        if ( $an_msg === 'deact_ok' ): ?>
            <div class="notice notice-success is-dismissible"><p>⊘ Serviço desactivado e artista notificado.</p></div>
        <?php elseif ( $an_msg === 'deact_invalid' ): ?>
            <div class="notice notice-error is-dismissible"><p>Não foi possível desactivar: o serviço não estava activo ou o motivo é demasiado curto (mín. 10 caracteres).</p></div>
        <?php elseif ( $an_msg === 'deact_error' ): ?>
            <div class="notice notice-error is-dismissible"><p>Erro ao desactivar o serviço. Tenta novamente.</p></div>
        <?php endif; ?>
        <p style="color:#666; margin:0 0 18px;">
            Vista completa de gestão pós-aprovação. Consulta o estado das músicas
            em cada um dos 3 serviços, vê evolução mensal, pesquisa por artista
            ou música, e desactiva uma música de um serviço específico quando
            aparece conflito posterior.
            <br>
            <strong style="color:#1a1a1a;">Vê tudo aqui</strong> — usa o filtro
            "Estado" abaixo para restringir (Aprovados, Pendentes, Conflitos,
            Rejeitados ou Qualquer).
        </p>

        <!-- ════════════════════ KPIs ════════════════════ -->
        <div class="rmbz-an-kpi-grid">
            <div class="rmbz-an-kpi rmbz-an-kpi-total">
                <span class="rmbz-an-kpi-label">Activos no total</span>
                <span class="rmbz-an-kpi-value"><?php echo number_format_i18n($total_active); ?></span>
                <span class="rmbz-an-kpi-sub">músicas × serviços</span>
            </div>
            <div class="rmbz-an-kpi rmbz-an-kpi-yt">
                <span class="rmbz-an-kpi-icon"><?php echo rmbz_exc_platform_svg('yt', 22); ?></span>
                <span class="rmbz-an-kpi-label">YouTube Content ID</span>
                <span class="rmbz-an-kpi-value"><?php echo (int)$kpi->yt_ok; ?></span>
                <div class="rmbz-an-kpi-breakdown">
                    <?php if ((int)$kpi->yt_pend): ?><span title="Pendentes">⏳ <?php echo (int)$kpi->yt_pend; ?></span><?php endif; ?>
                    <?php if ((int)$kpi->yt_conf): ?><span title="Conflitos" class="conf">⚠ <?php echo (int)$kpi->yt_conf; ?></span><?php endif; ?>
                    <?php if ((int)$kpi->yt_rej): ?><span title="Rejeitados" class="rej">✗ <?php echo (int)$kpi->yt_rej; ?></span><?php endif; ?>
                </div>
            </div>
            <div class="rmbz-an-kpi rmbz-an-kpi-fb">
                <span class="rmbz-an-kpi-icon"><?php echo rmbz_exc_platform_svg('fb', 22); ?></span>
                <span class="rmbz-an-kpi-label">Facebook/Instagram</span>
                <span class="rmbz-an-kpi-value"><?php echo (int)$kpi->fb_ok; ?></span>
                <div class="rmbz-an-kpi-breakdown">
                    <?php if ((int)$kpi->fb_pend): ?><span title="Pendentes">⏳ <?php echo (int)$kpi->fb_pend; ?></span><?php endif; ?>
                    <?php if ((int)$kpi->fb_conf): ?><span title="Conflitos" class="conf">⚠ <?php echo (int)$kpi->fb_conf; ?></span><?php endif; ?>
                    <?php if ((int)$kpi->fb_rej): ?><span title="Rejeitados" class="rej">✗ <?php echo (int)$kpi->fb_rej; ?></span><?php endif; ?>
                </div>
            </div>
            <div class="rmbz-an-kpi rmbz-an-kpi-tt">
                <span class="rmbz-an-kpi-icon"><?php echo rmbz_exc_platform_svg('tt', 22); ?></span>
                <span class="rmbz-an-kpi-label">TikTok</span>
                <span class="rmbz-an-kpi-value"><?php echo (int)$kpi->tt_ok; ?></span>
                <div class="rmbz-an-kpi-breakdown">
                    <?php if ((int)$kpi->tt_pend): ?><span title="Pendentes">⏳ <?php echo (int)$kpi->tt_pend; ?></span><?php endif; ?>
                    <?php if ((int)$kpi->tt_conf): ?><span title="Conflitos" class="conf">⚠ <?php echo (int)$kpi->tt_conf; ?></span><?php endif; ?>
                    <?php if ((int)$kpi->tt_rej): ?><span title="Rejeitados" class="rej">✗ <?php echo (int)$kpi->tt_rej; ?></span><?php endif; ?>
                </div>
            </div>
        </div>

        <!-- ════════════════════ GRÁFICO DE EVOLUÇÃO ════════════════════ -->
        <?php if ( ! empty($monthly) ): ?>
        <div class="rmbz-an-card">
            <h3>📈 Evolução de aprovações (últimos 6 meses)</h3>
            <?php
            $max = 1;
            foreach ($monthly as $m) {
                $max = max($max, (int)$m->yt + (int)$m->fb + (int)$m->tt);
            }
            $count = count($monthly);
            $svg_w = 760;
            $svg_h = 220;
            $pad_l = 40; $pad_b = 30; $pad_t = 10; $pad_r = 10;
            $chart_w = $svg_w - $pad_l - $pad_r;
            $chart_h = $svg_h - $pad_t - $pad_b;
            $bar_group_w = $chart_w / max(1, $count);
            $bar_w = $bar_group_w * 0.22;
            ?>
            <svg viewBox="0 0 <?php echo $svg_w; ?> <?php echo $svg_h; ?>" class="rmbz-an-chart" preserveAspectRatio="xMidYMid meet">
                <!-- Eixo Y (4 ticks) -->
                <?php for ($i = 0; $i <= 4; $i++):
                    $y = $pad_t + ($chart_h * $i / 4);
                    $val = round($max * (4 - $i) / 4);
                ?>
                <line x1="<?php echo $pad_l; ?>" y1="<?php echo $y; ?>" x2="<?php echo $svg_w - $pad_r; ?>" y2="<?php echo $y; ?>" stroke="#eee" stroke-width="1"/>
                <text x="<?php echo $pad_l - 6; ?>" y="<?php echo $y + 4; ?>" text-anchor="end" font-size="10" fill="#999"><?php echo $val; ?></text>
                <?php endfor; ?>

                <!-- Barras agrupadas (YT, FB, TT por mês) -->
                <?php foreach ($monthly as $i => $m):
                    $cx = $pad_l + $bar_group_w * ($i + 0.5);
                    $yt = (int)$m->yt; $fb = (int)$m->fb; $tt = (int)$m->tt;
                    $yt_h = $max > 0 ? ($yt / $max) * $chart_h : 0;
                    $fb_h = $max > 0 ? ($fb / $max) * $chart_h : 0;
                    $tt_h = $max > 0 ? ($tt / $max) * $chart_h : 0;
                ?>
                <rect x="<?php echo $cx - $bar_w * 1.6; ?>" y="<?php echo $pad_t + $chart_h - $yt_h; ?>"
                      width="<?php echo $bar_w; ?>" height="<?php echo $yt_h; ?>"
                      fill="#ff4757" rx="2">
                    <title>YT: <?php echo $yt; ?> (<?php echo esc_attr($m->m); ?>)</title>
                </rect>
                <rect x="<?php echo $cx - $bar_w * 0.5; ?>" y="<?php echo $pad_t + $chart_h - $fb_h; ?>"
                      width="<?php echo $bar_w; ?>" height="<?php echo $fb_h; ?>"
                      fill="#3b5998" rx="2">
                    <title>FB: <?php echo $fb; ?> (<?php echo esc_attr($m->m); ?>)</title>
                </rect>
                <rect x="<?php echo $cx + $bar_w * 0.6; ?>" y="<?php echo $pad_t + $chart_h - $tt_h; ?>"
                      width="<?php echo $bar_w; ?>" height="<?php echo $tt_h; ?>"
                      fill="#000" rx="2">
                    <title>TT: <?php echo $tt; ?> (<?php echo esc_attr($m->m); ?>)</title>
                </rect>
                <text x="<?php echo $cx; ?>" y="<?php echo $svg_h - 10; ?>" text-anchor="middle" font-size="10" fill="#666">
                    <?php echo esc_html( substr($m->m, 5) . '/' . substr($m->m, 2, 2) ); ?>
                </text>
                <?php endforeach; ?>
            </svg>
            <div class="rmbz-an-chart-legend">
                <span><span class="dot" style="background:#ff4757;"></span> YouTube Content ID</span>
                <span><span class="dot" style="background:#3b5998;"></span> Facebook/Instagram</span>
                <span><span class="dot" style="background:#000;"></span> TikTok</span>
            </div>
        </div>
        <?php endif; ?>

        <!-- ════════════════════ FILTROS + EXPORT ════════════════════ -->
        <div class="rmbz-an-card">
            <form method="get" class="rmbz-an-filters">
                <input type="hidden" name="page" value="rmbz-admin-distribution">
                <input type="hidden" name="tab" value="exclusives">
                <input type="hidden" name="filter" value="analytics">

                <div class="rmbz-an-filter">
                    <label>Pesquisar</label>
                    <input type="search" name="s" value="<?php echo esc_attr( $_GET['s'] ?? '' ); ?>"
                           placeholder="Artista, música, ISRC, telemóvel…">
                </div>
                <div class="rmbz-an-filter">
                    <label>Serviço</label>
                    <select name="svc">
                        <?php
                        $cur_svc = $_GET['svc'] ?? 'any';
                        foreach ([
                            'any' => 'Qualquer serviço',
                            'yt'  => 'YouTube Content ID',
                            'fb'  => 'Facebook / Instagram',
                            'tt'  => 'TikTok',
                        ] as $k => $v) {
                            echo '<option value="' . esc_attr($k) . '"' . selected($cur_svc, $k, false) . '>' . esc_html($v) . '</option>';
                        }
                        ?>
                    </select>
                </div>
                <div class="rmbz-an-filter">
                    <label>Estado</label>
                    <select name="st">
                        <?php
                        $cur_st = $_GET['st'] ?? 'any';
                        foreach ([
                            'any'       => 'Qualquer estado',
                            'approved'  => '✓ Aprovado',
                            'requested' => '⏳ Pendente',
                            'conflict'  => '⚠ Conflito',
                            'rejected'  => '✗ Rejeitado',
                        ] as $k => $v) {
                            echo '<option value="' . esc_attr($k) . '"' . selected($cur_st, $k, false) . '>' . esc_html($v) . '</option>';
                        }
                        ?>
                    </select>
                </div>
                <div class="rmbz-an-filter">
                    <label>De</label>
                    <input type="date" name="from" value="<?php echo esc_attr( $_GET['from'] ?? '' ); ?>">
                </div>
                <div class="rmbz-an-filter">
                    <label>Até</label>
                    <input type="date" name="to" value="<?php echo esc_attr( $_GET['to'] ?? '' ); ?>">
                </div>
                <div class="rmbz-an-filter rmbz-an-filter-actions">
                    <button type="submit" class="button button-primary">Filtrar</button>
                    <a href="?page=rmbz-admin-distribution&tab=exclusives&filter=analytics" class="button">Limpar</a>
                    <a href="<?php echo esc_url($export_url); ?>" class="button"
                       title="Exportar os resultados filtrados como CSV">
                        ⬇ Exportar CSV
                    </a>
                </div>
            </form>
        </div>

        <!-- ════════════════════ TABELA CRUZADA (top artistas) ════════════════════ -->
        <?php if ( ! empty($top_artists) ): ?>
        <div class="rmbz-an-card">
            <h3>🎤 Top artistas por nº de aprovações</h3>
            <div style="overflow-x:auto;">
            <table class="rmbz-an-cross">
                <thead>
                    <tr>
                        <th>Artista</th>
                        <th style="text-align:center;"><span class="rmbz-an-th-icon"><?php echo rmbz_exc_platform_svg('yt', 12); ?></span> YT</th>
                        <th style="text-align:center;"><span class="rmbz-an-th-icon"><?php echo rmbz_exc_platform_svg('fb', 12); ?></span> FB/IG</th>
                        <th style="text-align:center;"><span class="rmbz-an-th-icon"><?php echo rmbz_exc_platform_svg('tt', 12); ?></span> TT</th>
                        <th style="text-align:center;">Total ✓</th>
                        <th style="text-align:center;">⚠ Conf.</th>
                        <th style="text-align:center;">Pedidos</th>
                    </tr>
                </thead>
                <tbody>
                    <?php foreach ( $top_artists as $a ):
                        $name = $a->user_nome ?: '(sem nome — ' . $a->artist_telemovel . ')';
                        $sum = (int)$a->yt_ok + (int)$a->fb_ok + (int)$a->tt_ok;
                    ?>
                    <tr>
                        <td>
                            <strong><?php echo esc_html($name); ?></strong>
                            <?php if ($a->user_nome): ?>
                                <br><small style="color:#999;"><?php echo esc_html($a->artist_telemovel); ?></small>
                            <?php endif; ?>
                        </td>
                        <td style="text-align:center;"><?php echo (int)$a->yt_ok > 0 ? '<strong>' . (int)$a->yt_ok . '</strong>' : '—'; ?></td>
                        <td style="text-align:center;"><?php echo (int)$a->fb_ok > 0 ? '<strong>' . (int)$a->fb_ok . '</strong>' : '—'; ?></td>
                        <td style="text-align:center;"><?php echo (int)$a->tt_ok > 0 ? '<strong>' . (int)$a->tt_ok . '</strong>' : '—'; ?></td>
                        <td style="text-align:center;"><span style="background:#d4edda; color:#166534; padding:2px 9px; border-radius:10px; font-weight:700;"><?php echo $sum; ?></span></td>
                        <td style="text-align:center;"><?php echo (int)$a->conf > 0 ? '<span style="color:#d97706; font-weight:700;">' . (int)$a->conf . '</span>' : '—'; ?></td>
                        <td style="text-align:center; color:#666;"><?php echo (int)$a->total; ?></td>
                    </tr>
                    <?php endforeach; ?>
                </tbody>
            </table>
            </div>
        </div>
        <?php endif; ?>

        <!-- ════════════════════ LISTA DETALHADA ════════════════════ -->
        <div class="rmbz-an-card">
            <h3>🎵 Músicas (<?php echo count($rows); ?><?php echo $an_truncated ? '+' : ''; ?>)</h3>
            <?php if ( $an_truncated ): ?>
                <div class="notice notice-warning inline" style="margin:0 0 14px;">
                    <p style="margin:6px 0;">
                        A mostrar os <strong><?php echo $an_limit; ?></strong> resultados mais recentes.
                        Há mais — refina com a pesquisa, serviço, estado ou datas, ou usa
                        <strong>⬇ Exportar CSV</strong> para obteres tudo (até 5000).
                    </p>
                </div>
            <?php endif; ?>
            <?php if ( empty($rows) ): ?>
                <p style="color:#999; padding:20px; text-align:center;">
                    Sem resultados com os filtros actuais. Tenta limpar a pesquisa.
                </p>
            <?php else: ?>
                <div class="rmbz-an-list">
                    <?php foreach ( $rows as $row ):
                        $modal_data = wp_json_encode([
                            'release_id'  => (int)$row->release_id,
                            'title'       => $row->release_title,
                            'artist'      => $row->user_nome ?: '(sem nome)',
                            'telefone'    => $row->artist_telemovel,
                            'isrc'        => $row->primary_isrc ?? '',
                            'cover'       => $row->cover_image,
                            'yt'          => $row->yt_content_id_status,
                            'fb'          => $row->fb_monet_status,
                            'tt'          => $row->tt_monet_status,
                            'updated_at'  => $row->updated_at,
                            'yt_notes'    => $row->yt_content_id_decision_note ?? '',
                            'fb_notes'    => $row->fb_monet_decision_note ?? '',
                            'tt_notes'    => $row->tt_monet_decision_note ?? '',
                        ]);
                    ?>
                    <div class="rmbz-an-row">
                        <?php if ($row->cover_image): ?>
                            <img src="<?php echo esc_url($row->cover_image); ?>" class="rmbz-an-cover" alt="">
                        <?php else: ?>
                            <div class="rmbz-an-cover rmbz-an-cover-empty">🎵</div>
                        <?php endif; ?>

                        <div class="rmbz-an-info">
                            <div class="rmbz-an-title"><?php echo esc_html($row->release_title); ?></div>
                            <div class="rmbz-an-meta">
                                <span><?php echo esc_html($row->user_nome ?: '(sem nome)'); ?></span>
                                · <span><?php echo esc_html($row->artist_telemovel); ?></span>
                                <?php if ( ! empty($row->primary_isrc) ): ?>
                                    · ISRC <code><?php echo esc_html($row->primary_isrc); ?></code>
                                <?php endif; ?>
                            </div>
                        </div>

                        <div class="rmbz-an-services">
                            <span class="rmbz-an-svc-pill rmbz-an-svc-<?php echo esc_attr($row->yt_content_id_status); ?>" title="YouTube Content ID">
                                <?php echo rmbz_exc_platform_svg('yt', 12); ?> <?php echo rmbz_an_status_short($row->yt_content_id_status); ?>
                            </span>
                            <span class="rmbz-an-svc-pill rmbz-an-svc-<?php echo esc_attr($row->fb_monet_status); ?>" title="Facebook/Instagram">
                                <?php echo rmbz_exc_platform_svg('fb', 12); ?> <?php echo rmbz_an_status_short($row->fb_monet_status); ?>
                            </span>
                            <span class="rmbz-an-svc-pill rmbz-an-svc-<?php echo esc_attr($row->tt_monet_status); ?>" title="TikTok">
                                <?php echo rmbz_exc_platform_svg('tt', 12); ?> <?php echo rmbz_an_status_short($row->tt_monet_status); ?>
                            </span>
                        </div>

                        <button type="button" class="rmbz-an-view-btn rmbz-an-detail-btn"
                                data-music='<?php echo esc_attr($modal_data); ?>'>
                            Ver detalhe
                        </button>
                    </div>
                    <?php endforeach; ?>
                </div>
            <?php endif; ?>
        </div>

        <!-- ════════════════════ MODAL DE DETALHE ════════════════════ -->
        <div id="rmbz-an-modal" class="rmbz-an-modal" aria-hidden="true">
            <div class="rmbz-an-modal-backdrop" data-close-an-modal></div>
            <div class="rmbz-an-modal-dialog" role="dialog" aria-modal="true">
                <div class="rmbz-an-modal-header">
                    <div>
                        <h3 id="an-title">—</h3>
                        <div class="rmbz-an-modal-sub" id="an-sub">—</div>
                    </div>
                    <button type="button" class="rmbz-an-modal-close" data-close-an-modal>&times;</button>
                </div>
                <div class="rmbz-an-modal-body">
                    <div class="rmbz-an-modal-services">
                        <div class="rmbz-an-modal-svc" id="an-svc-yt">
                            <h4><?php echo rmbz_exc_platform_svg('yt', 16); ?> YouTube Content ID</h4>
                            <div class="rmbz-an-modal-status" id="an-yt-status">—</div>
                            <div class="rmbz-an-modal-notes" id="an-yt-notes" hidden></div>
                            <a href="#" class="button rmbz-an-deact-btn" data-svc="yt" id="an-yt-deact" hidden>
                                ⊘ Desactivar deste serviço
                            </a>
                        </div>
                        <div class="rmbz-an-modal-svc" id="an-svc-fb">
                            <h4><?php echo rmbz_exc_platform_svg('fb', 16); ?> Facebook / Instagram</h4>
                            <div class="rmbz-an-modal-status" id="an-fb-status">—</div>
                            <div class="rmbz-an-modal-notes" id="an-fb-notes" hidden></div>
                            <a href="#" class="button rmbz-an-deact-btn" data-svc="fb" id="an-fb-deact" hidden>
                                ⊘ Desactivar deste serviço
                            </a>
                        </div>
                        <div class="rmbz-an-modal-svc" id="an-svc-tt">
                            <h4><?php echo rmbz_exc_platform_svg('tt', 16); ?> TikTok</h4>
                            <div class="rmbz-an-modal-status" id="an-tt-status">—</div>
                            <div class="rmbz-an-modal-notes" id="an-tt-notes" hidden></div>
                            <a href="#" class="button rmbz-an-deact-btn" data-svc="tt" id="an-tt-deact" hidden>
                                ⊘ Desactivar deste serviço
                            </a>
                        </div>
                    </div>
                    <div class="rmbz-an-modal-footer">
                        <a href="#" id="an-release-link" target="_blank" class="button">
                            Ver release completo →
                        </a>
                        <span style="color:#999; font-size:12px;">
                            Última actualização: <span id="an-updated">—</span>
                        </span>
                    </div>
                </div>
            </div>
        </div>

        <?php rmbz_render_exclusive_analytics_assets(); ?>
    </div>
    <?php
}

/**
 * Label curto para badge de serviço.
 */
function rmbz_an_status_short( $status ) {
    return match($status) {
        'approved'      => '✓ Activo',
        'requested'     => '⏳ Pendente',
        'conflict'      => '⚠ Conflito',
        'rejected'      => '✗ Rejeitado',
        default         => '—',
    };
}


/**
 * Handler de desactivação: muda status de approved → rejected num serviço.
 * Requer nonce e motivo (mínimo 10 chars guardado nas _notes da coluna).
 */
add_action( 'admin_post_rmbz_an_deactivate_service', function () {
    if ( ! current_user_can( 'manage_options' ) ) wp_die( 'Sem permissão.' );
    check_admin_referer( 'rmbz_an_deactivate' );

    $release_id = isset($_POST['release_id']) ? absint($_POST['release_id']) : 0;
    $svc = isset($_POST['svc']) ? sanitize_key($_POST['svc']) : '';
    $reason = isset($_POST['reason']) ? trim( wp_unslash( sanitize_textarea_field( $_POST['reason'] ) ) ) : '';

    // Colunas reais na tabela rmbz_distro_release_platforms (o sufixo é
    // _decision_note, não _notes — este era o bug que fazia a desactivação
    // falhar silenciosamente).
    $svc_map = [
        'yt' => ['col' => 'yt_content_id_status', 'notes' => 'yt_content_id_decision_note'],
        'fb' => ['col' => 'fb_monet_status',      'notes' => 'fb_monet_decision_note'],
        'tt' => ['col' => 'tt_monet_status',      'notes' => 'tt_monet_decision_note'],
    ];
    if ( ! $release_id || ! isset($svc_map[$svc]) || strlen($reason) < 10 ) {
        wp_safe_redirect( add_query_arg( 'msg', 'deact_invalid', wp_get_referer() ) );
        exit;
    }

    global $wpdb;
    $table_p = $wpdb->prefix . 'rmbz_distro_release_platforms';
    $col = $svc_map[$svc]['col'];
    $notes_col = $svc_map[$svc]['notes'];

    // Só faz sentido desactivar um serviço que esteja aprovado.
    $current = $wpdb->get_var( $wpdb->prepare(
        "SELECT $col FROM $table_p WHERE release_id = %d", $release_id
    ) );
    if ( $current !== 'approved' ) {
        wp_safe_redirect( add_query_arg( 'msg', 'deact_invalid', wp_get_referer() ) );
        exit;
    }

    $admin_label = wp_get_current_user()->user_login ?: 'admin';
    $stamp = current_time( 'mysql' );
    $append = "\n\n[DESACTIVADO {$stamp} por {$admin_label}]\n{$reason}";

    $result = $wpdb->query( $wpdb->prepare(
        "UPDATE $table_p
            SET $col = 'rejected',
                $notes_col = CONCAT(COALESCE($notes_col, ''), %s),
                updated_at = NOW()
          WHERE release_id = %d",
        $append, $release_id
    ) );

    // Verifica o resultado em vez de presumir sucesso.
    if ( $result === false ) {
        wp_safe_redirect( add_query_arg( 'msg', 'deact_error', wp_get_referer() ) );
        exit;
    }

    // Notifica o artista (paridade com as decisões de workflow).
    if ( function_exists( 'rmbz_add_notification' ) ) {
        $owner = $wpdb->get_row( $wpdb->prepare(
            "SELECT r.artist_telemovel, r.title FROM {$wpdb->prefix}rmbz_distro_releases r WHERE r.id = %d",
            $release_id
        ) );
        $svc_label = ['yt'=>'YouTube Content ID','fb'=>'Facebook/Instagram','tt'=>'TikTok'][$svc] ?? $svc;
        if ( $owner && $owner->artist_telemovel ) {
            rmbz_add_notification(
                $owner->artist_telemovel,
                sprintf( '⊘ O serviço %s foi desactivado para "%s". Motivo: %s', $svc_label, $owner->title ?: 'Lançamento', $reason )
            );
        }
    }

    wp_safe_redirect( add_query_arg( 'msg', 'deact_ok', wp_get_referer() ) );
    exit;
} );


/**
 * CSS + JS da aba Analítico.
 * Inline para não exigir enqueue de ficheiros novos.
 */
function rmbz_render_exclusive_analytics_assets() {
    ?>
    <style>
    /* ════════════════════ KPI GRID ════════════════════ */
    .rmbz-excl-analytics { max-width: 100%; }
    .rmbz-an-kpi-grid {
        display: grid;
        grid-template-columns: 1.2fr 1fr 1fr 1fr;
        gap: 14px;
        margin-bottom: 22px;
    }
    @media (max-width: 900px) {
        .rmbz-an-kpi-grid { grid-template-columns: 1fr 1fr; }
    }
    .rmbz-an-kpi {
        background: #fff;
        border: 1px solid #e6e8eb;
        border-radius: 12px;
        padding: 16px 18px;
        position: relative;
        box-shadow: 0 1px 3px rgba(0,0,0,0.04);
        display: flex; flex-direction: column;
        gap: 4px;
    }
    .rmbz-an-kpi-total {
        background: linear-gradient(135deg, #1a1a1a, #2a2a2a);
        color: #fff;
        border: 0;
    }
    .rmbz-an-kpi-total .rmbz-an-kpi-label { color: rgba(255,255,255,0.7); }
    .rmbz-an-kpi-total .rmbz-an-kpi-value { color: #f0b90b; }
    .rmbz-an-kpi-total .rmbz-an-kpi-sub { color: rgba(255,255,255,0.5); }
    .rmbz-an-kpi-icon {
        position: absolute; top: 12px; right: 14px;
        opacity: 0.6;
        color: #1a1a1a;
        display: inline-flex;
        align-items: center;
    }
    .rmbz-an-kpi-icon svg {
        display: block;
    }
    /* Ícone SVG nos headers da tabela cruzada */
    .rmbz-an-th-icon {
        display: inline-block;
        vertical-align: -2px;
        opacity: 0.65;
    }
    /* SVG dentro das pills da lista de músicas */
    .rmbz-an-svc-pill svg {
        vertical-align: -2px;
        margin-right: 2px;
    }
    /* SVG dentro dos h4 da modal (3 colunas de serviços) */
    .rmbz-an-modal-svc h4 {
        display: inline-flex;
        align-items: center;
        gap: 6px;
    }
    .rmbz-an-modal-svc h4 svg {
        opacity: 0.75;
    }
    .rmbz-an-kpi-label {
        font-size: 11px;
        text-transform: uppercase;
        letter-spacing: 0.04em;
        color: #6b7280;
        font-weight: 600;
    }
    .rmbz-an-kpi-value {
        font-size: 34px;
        font-weight: 800;
        line-height: 1;
        color: #1a1a1a;
        letter-spacing: -0.02em;
    }
    .rmbz-an-kpi-sub { font-size: 11px; color: #9ca3af; }
    .rmbz-an-kpi-breakdown {
        display: flex; gap: 10px;
        font-size: 11px;
        margin-top: 4px;
        color: #6b7280;
    }
    .rmbz-an-kpi-breakdown .conf { color: #d97706; }
    .rmbz-an-kpi-breakdown .rej { color: #dc2626; }

    /* ════════════════════ CARDS ════════════════════ */
    .rmbz-an-card {
        background: #fff;
        border: 1px solid #e6e8eb;
        border-radius: 12px;
        padding: 18px 20px;
        margin-bottom: 18px;
        box-shadow: 0 1px 3px rgba(0,0,0,0.04);
    }
    .rmbz-an-card h3 {
        margin: 0 0 14px;
        font-size: 14px;
        color: #1a1a1a;
        padding-bottom: 10px;
        border-bottom: 1px solid #f0f1f3;
        padding-left: 10px;
        position: relative;
    }
    .rmbz-an-card h3::before {
        content: ''; position: absolute;
        left: 0; top: 2px; bottom: 12px;
        width: 3px;
        background: linear-gradient(180deg, #f0b90b, #d4a000);
        border-radius: 2px;
    }

    /* ════════════════════ GRÁFICO ════════════════════ */
    .rmbz-an-chart { width: 100%; height: auto; max-height: 240px; }
    .rmbz-an-chart-legend {
        display: flex; gap: 18px;
        justify-content: center;
        font-size: 12px;
        color: #4b5563;
        margin-top: 8px;
    }
    .rmbz-an-chart-legend .dot {
        display: inline-block; width: 10px; height: 10px;
        border-radius: 50%; margin-right: 6px;
        vertical-align: middle;
    }

    /* ════════════════════ FILTROS ════════════════════ */
    .rmbz-an-filters {
        display: grid;
        grid-template-columns: 2fr 1fr 1fr 1fr 1fr auto;
        gap: 12px;
        align-items: end;
    }
    @media (max-width: 900px) {
        .rmbz-an-filters { grid-template-columns: 1fr 1fr; }
        .rmbz-an-filter-actions { grid-column: 1 / -1; }
    }
    .rmbz-an-filter label {
        display: block;
        font-size: 11px;
        font-weight: 600;
        color: #6b7280;
        text-transform: uppercase;
        letter-spacing: 0.04em;
        margin-bottom: 4px;
    }
    .rmbz-an-filter input,
    .rmbz-an-filter select {
        width: 100%;
        padding: 7px 10px;
        border: 1px solid #d1d5db;
        border-radius: 7px;
        font-size: 13px;
        transition: border-color .15s, box-shadow .15s;
    }
    .rmbz-an-filter input:focus,
    .rmbz-an-filter select:focus {
        border-color: var(--wp-admin-theme-color, #2271b1);
        box-shadow: 0 0 0 3px rgba(34,113,177,0.12);
        outline: none;
    }
    .rmbz-an-filter-actions {
        display: flex; gap: 8px; flex-wrap: wrap;
    }

    /* ════════════════════ TABELA CRUZADA ════════════════════ */
    .rmbz-an-cross {
        width: 100%;
        border-collapse: collapse;
        font-size: 13px;
    }
    .rmbz-an-cross thead th {
        background: #fafbfc;
        padding: 9px 12px;
        text-align: left;
        font-size: 11px;
        text-transform: uppercase;
        letter-spacing: 0.04em;
        color: #6b7280;
        border-bottom: 2px solid #e6e8eb;
    }
    .rmbz-an-cross tbody td {
        padding: 10px 12px;
        border-bottom: 1px solid #f3f4f6;
        color: #1f2937;
    }
    .rmbz-an-cross tbody tr:hover td { background: #fafbfc; }

    /* ════════════════════ LISTA DE MÚSICAS ════════════════════ */
    .rmbz-an-list {
        display: flex; flex-direction: column;
        gap: 8px;
    }
    .rmbz-an-row {
        display: grid;
        grid-template-columns: 56px 1fr auto auto;
        gap: 14px;
        align-items: center;
        padding: 10px 14px;
        background: #fafbfc;
        border: 1px solid #e6e8eb;
        border-radius: 9px;
        transition: all 0.15s ease;
    }
    .rmbz-an-row:hover {
        background: #fff;
        border-color: #f0b90b;
        transform: translateY(-1px);
        box-shadow: 0 3px 8px rgba(0,0,0,0.06);
    }
    @media (max-width: 720px) {
        .rmbz-an-row {
            grid-template-columns: 56px 1fr;
            grid-template-areas:
                "cover info"
                "svc svc"
                "btn btn";
        }
        .rmbz-an-row > .rmbz-an-cover { grid-area: cover; }
        .rmbz-an-row > .rmbz-an-info { grid-area: info; }
        .rmbz-an-row > .rmbz-an-services { grid-area: svc; }
        .rmbz-an-row > .rmbz-an-view-btn { grid-area: btn; justify-self: stretch; }
    }
    .rmbz-an-cover {
        width: 56px; height: 56px;
        border-radius: 8px;
        object-fit: cover;
        background: #e5e7eb;
    }
    .rmbz-an-cover-empty {
        display: flex; align-items: center; justify-content: center;
        font-size: 24px;
        color: #9ca3af;
    }
    .rmbz-an-title {
        font-weight: 600;
        font-size: 14px;
        color: #1a1a1a;
        margin-bottom: 2px;
    }
    .rmbz-an-meta {
        font-size: 12px;
        color: #6b7280;
    }
    .rmbz-an-meta code {
        background: #f3f4f6;
        padding: 1px 6px;
        border-radius: 4px;
        font-size: 11px;
    }
    .rmbz-an-services { display: flex; gap: 6px; }
    .rmbz-an-svc-pill {
        display: inline-flex;
        align-items: center;
        gap: 4px;
        padding: 4px 9px;
        border-radius: 12px;
        font-size: 11px;
        font-weight: 600;
        white-space: nowrap;
    }
    .rmbz-an-svc-approved      { background: #d1fae5; color: #065f46; border: 1px solid #a7f3d0; }
    .rmbz-an-svc-requested     { background: #fef3c7; color: #92400e; border: 1px solid #fde68a; }
    .rmbz-an-svc-conflict      { background: #fed7aa; color: #9a3412; border: 1px solid #fdba74; }
    .rmbz-an-svc-rejected      { background: #fee2e2; color: #991b1b; border: 1px solid #fecaca; }
    .rmbz-an-svc-not_requested { background: #f3f4f6; color: #6b7280; border: 1px solid #e5e7eb; }

    .rmbz-an-view-btn {
        background: #1a1a1a;
        color: #f0b90b;
        border: 1px solid #f0b90b;
        padding: 7px 14px;
        border-radius: 8px;
        font-size: 12px;
        font-weight: 600;
        cursor: pointer;
        transition: all 0.18s ease;
        white-space: nowrap;
    }
    .rmbz-an-view-btn:hover {
        background: #f0b90b;
        color: #1a1a1a;
    }

    /* ════════════════════ MODAL ════════════════════ */
    .rmbz-an-modal {
        position: fixed; inset: 0; z-index: 100002;
        display: none; align-items: center; justify-content: center;
        padding: 20px;
    }
    .rmbz-an-modal.is-open { display: flex; }
    .rmbz-an-modal-backdrop {
        position: absolute; inset: 0;
        background: rgba(10,10,10,0.65);
        backdrop-filter: blur(2px);
    }
    .rmbz-an-modal-dialog {
        position: relative;
        background: #fff;
        border-radius: 14px;
        max-width: 720px;
        width: 100%;
        max-height: 90vh;
        overflow: hidden;
        display: flex; flex-direction: column;
        box-shadow: 0 20px 60px rgba(0,0,0,0.4);
    }
    .rmbz-an-modal-header {
        background: linear-gradient(135deg, #1a1a1a, #2a2a2a);
        color: #fff;
        padding: 16px 22px;
        display: flex; justify-content: space-between; align-items: flex-start;
    }
    .rmbz-an-modal-header h3 { margin: 0; color: #fff; font-size: 17px; }
    .rmbz-an-modal-sub { color: rgba(255,255,255,0.7); font-size: 12px; margin-top: 3px; }
    .rmbz-an-modal-close {
        background: transparent; border: 0; color: #fff;
        font-size: 26px; cursor: pointer; opacity: 0.8;
        padding: 0 6px; line-height: 1;
    }
    .rmbz-an-modal-close:hover { opacity: 1; }
    .rmbz-an-modal-body { padding: 20px 22px; overflow-y: auto; }
    .rmbz-an-modal-services {
        display: grid;
        grid-template-columns: 1fr 1fr 1fr;
        gap: 12px;
    }
    @media (max-width: 720px) {
        .rmbz-an-modal-services { grid-template-columns: 1fr; }
    }
    .rmbz-an-modal-svc {
        background: #fafbfc;
        border: 1px solid #e6e8eb;
        border-radius: 10px;
        padding: 12px 14px;
    }
    .rmbz-an-modal-svc h4 {
        margin: 0 0 8px;
        font-size: 13px;
        color: #1a1a1a;
    }
    .rmbz-an-modal-status {
        font-weight: 600;
        font-size: 14px;
        margin-bottom: 8px;
    }
    .rmbz-an-modal-notes {
        background: #fff;
        border: 1px solid #e6e8eb;
        border-left: 3px solid #f0b90b;
        padding: 8px 10px;
        border-radius: 6px;
        font-size: 11px;
        color: #4b5563;
        white-space: pre-wrap;
        max-height: 150px;
        overflow-y: auto;
        margin-bottom: 8px;
    }
    .rmbz-an-modal-notes[hidden] { display: none; }
    .rmbz-an-deact-btn[hidden] { display: none; }
    .rmbz-an-modal-footer {
        margin-top: 16px;
        padding-top: 14px;
        border-top: 1px dashed #e6e8eb;
        display: flex; justify-content: space-between; align-items: center;
        flex-wrap: wrap; gap: 10px;
    }
    </style>

    <script>
    (function () {
        var modal = document.getElementById('rmbz-an-modal');
        if (!modal) return;

        var statusLabel = {
            approved:      { txt: '✓ Activo',    cls: 'rmbz-an-svc-approved' },
            requested:     { txt: '⏳ Pendente',  cls: 'rmbz-an-svc-requested' },
            conflict:      { txt: '⚠ Conflito',  cls: 'rmbz-an-svc-conflict' },
            rejected:      { txt: '✗ Rejeitado', cls: 'rmbz-an-svc-rejected' },
            not_requested: { txt: '— Não pedido', cls: 'rmbz-an-svc-not_requested' },
        };

        function paintService(svc, status, notes) {
            var s = statusLabel[status] || statusLabel.not_requested;
            var statusEl = document.getElementById('an-' + svc + '-status');
            statusEl.textContent = s.txt;
            statusEl.className = 'rmbz-an-modal-status ' + s.cls;
            // Padding extra para parecer pill
            statusEl.style.padding = '4px 10px';
            statusEl.style.borderRadius = '12px';
            statusEl.style.display = 'inline-block';

            var notesEl = document.getElementById('an-' + svc + '-notes');
            if (notes && notes.trim() !== '') {
                notesEl.textContent = notes;
                notesEl.hidden = false;
            } else {
                notesEl.hidden = true;
            }

            // Só permite desactivar se está actualmente aprovado
            var deactBtn = document.getElementById('an-' + svc + '-deact');
            deactBtn.hidden = (status !== 'approved');
        }

        function openMusic(data) {
            document.getElementById('an-title').textContent = data.title || '—';
            var sub = (data.artist || '—') + ' · ' + (data.telefone || '');
            if (data.isrc) sub += ' · ISRC ' + data.isrc;
            document.getElementById('an-sub').textContent = sub;

            paintService('yt', data.yt, data.yt_notes);
            paintService('fb', data.fb, data.fb_notes);
            paintService('tt', data.tt, data.tt_notes);

            document.getElementById('an-updated').textContent = data.updated_at || '—';

            // Link para release detail
            var releaseLink = document.getElementById('an-release-link');
            releaseLink.href = '?page=rmbz-admin-distribution&tab=releases&view=detail&id=' + data.release_id;

            // Anexar handlers de desactivação com referência ao release atual
            document.querySelectorAll('.rmbz-an-deact-btn').forEach(function (btn) {
                btn.onclick = function (e) {
                    e.preventDefault();
                    var svc = btn.dataset.svc;
                    var svcLabel = { yt: 'YouTube Content ID', fb: 'Facebook/Instagram', tt: 'TikTok' }[svc];
                    var reason = prompt(
                        'Vais desactivar a música "' + data.title + '" do serviço ' + svcLabel + '.\n\n' +
                        'Descreve o motivo (mín. 10 caracteres) — fica registado para auditoria:'
                    );
                    if (!reason || reason.trim().length < 10) {
                        alert('Motivo é obrigatório e tem de ter pelo menos 10 caracteres.');
                        return;
                    }
                    // Submeter via form dinâmico (POST + nonce)
                    var form = document.createElement('form');
                    form.method = 'POST';
                    form.action = '<?php echo esc_js( admin_url('admin-post.php') ); ?>';
                    form.innerHTML =
                        '<input type="hidden" name="action" value="rmbz_an_deactivate_service">' +
                        '<input type="hidden" name="_wpnonce" value="<?php echo esc_js( wp_create_nonce('rmbz_an_deactivate') ); ?>">' +
                        '<input type="hidden" name="release_id" value="' + data.release_id + '">' +
                        '<input type="hidden" name="svc" value="' + svc + '">';
                    var ta = document.createElement('input');
                    ta.type = 'hidden'; ta.name = 'reason'; ta.value = reason;
                    form.appendChild(ta);
                    document.body.appendChild(form);
                    form.submit();
                };
            });

            modal.classList.add('is-open');
            modal.setAttribute('aria-hidden', 'false');
        }

        function closeModal() {
            modal.classList.remove('is-open');
            modal.setAttribute('aria-hidden', 'true');
        }

        document.addEventListener('click', function (e) {
            var btn = e.target.closest('.rmbz-an-detail-btn');
            if (btn) {
                try { openMusic(JSON.parse(btn.getAttribute('data-music'))); }
                catch (err) { console.error('1MZ: payload inválido', err); }
                return;
            }
            if (e.target.closest('[data-close-an-modal]')) closeModal();
        });
        document.addEventListener('keydown', function (e) {
            if (e.key === 'Escape' && modal.classList.contains('is-open')) closeModal();
        });
    })();
    </script>
    <?php
}


/* ============================================================================
 * [FEAT 1.6.2] BADGES AUTOMÁTICOS para vista compacta de pendentes
 *
 * Calcula sinais visuais que aparecem APENAS quando há algo a chamar a
 * atenção. Sem badges = música limpa, pode aprovar sem inspeccionar.
 *
 * Tipos:
 *   - no_isrc       : faixa primária sem ISRC
 *   - no_cover      : sem capa
 *   - low_cover     : capa em baixa qualidade (impossível verificar sem
 *                     download, assumimos OK se tem URL)
 *   - old_pending   : aguarda há mais de 7 dias
 *   - thin_metadata : metadata incompleta (sem letrista, produtor, etc.)
 *   - possible_dup  : título muito parecido com outra música do mesmo artista
 *   - odd_duration  : duração suspeita (<30s ou >10min)
 * ============================================================================ */
function rmbz_exclusive_compute_badges( $row, $primary_track, $wpdb, $table_t ) {
    $badges = [];

    // 1. Sem ISRC
    if ( empty( $primary_track ) || empty( $primary_track->isrc_code ) ) {
        $badges[] = [
            'icon' => '🚨',
            'label' => 'Sem ISRC',
            'severity' => 'high',
            'tip' => 'A faixa primária não tem código ISRC — necessário para Content ID.',
        ];
    }

    // 2. Sem capa
    if ( empty( $row->cover_image ) ) {
        $badges[] = [
            'icon' => '🖼️',
            'label' => 'Sem capa',
            'severity' => 'medium',
            'tip' => 'Release sem imagem de capa.',
        ];
    }

    // 3. Aguarda há muito tempo (>7 dias)
    if ( ! empty( $row->updated_at ) ) {
        $age_days = (int) ( ( time() - strtotime( $row->updated_at ) ) / 86400 );
        if ( $age_days >= 14 ) {
            $badges[] = [
                'icon' => '⏱️',
                'label' => $age_days . 'd em espera',
                'severity' => 'high',
                'tip' => "Pedido feito há $age_days dias — prioridade.",
            ];
        } elseif ( $age_days >= 7 ) {
            $badges[] = [
                'icon' => '⏱️',
                'label' => $age_days . 'd em espera',
                'severity' => 'medium',
                'tip' => "Pedido feito há $age_days dias.",
            ];
        }
    }

    // 4. Metadata incompleta (sem letrista/produtor numa das faixas)
    // [Verificar se a faixa primária tem metadata mínima]
    if ( $primary_track ) {
        $meta_missing = [];
        // Estes campos podem não existir na tabela em todas as instalações;
        // protegemos com isset.
        if ( isset($primary_track->lyricist) && empty($primary_track->lyricist) ) $meta_missing[] = 'letrista';
        if ( isset($primary_track->producer) && empty($primary_track->producer) ) $meta_missing[] = 'produtor';
        if ( count($meta_missing) >= 1 ) {
            $badges[] = [
                'icon' => '📦',
                'label' => 'Metadata incompleta',
                'severity' => 'low',
                'tip' => 'Em falta: ' . implode( ', ', $meta_missing ),
            ];
        }
    }

    // 5. Possível duplicado — título parecido com outra música do mesmo artista
    if ( $primary_track && ! empty( $primary_track->track_title ) ) {
        $similar = $wpdb->get_var( $wpdb->prepare(
            "SELECT COUNT(DISTINCT t.id)
               FROM $table_t t
               JOIN {$wpdb->prefix}rmbz_distro_releases r ON t.release_id = r.id
              WHERE r.artist_telemovel = %s
                AND r.id != %d
                AND SOUNDEX(t.track_title) = SOUNDEX(%s)
              LIMIT 1",
            $row->artist_telemovel,
            $row->release_id,
            $primary_track->track_title
        ) );
        if ( (int) $similar > 0 ) {
            $badges[] = [
                'icon' => '🔁',
                'label' => 'Possível duplicado',
                'severity' => 'high',
                'tip' => 'Encontrámos outra música deste artista com título parecido — verifica.',
            ];
        }
    }

    // 6. Duração suspeita (apenas se tivermos esse dado)
    if ( $primary_track && isset($primary_track->duration_seconds) && (int) $primary_track->duration_seconds > 0 ) {
        $dur = (int) $primary_track->duration_seconds;
        if ( $dur < 30 ) {
            $badges[] = [
                'icon' => '🎵',
                'label' => 'Duração curta',
                'severity' => 'medium',
                'tip' => "Apenas {$dur} segundos — Content ID pode rejeitar.",
            ];
        } elseif ( $dur > 600 ) {
            $mins = round( $dur / 60 );
            $badges[] = [
                'icon' => '🎵',
                'label' => "Longa ({$mins}min)",
                'severity' => 'low',
                'tip' => "Duração de {$mins} minutos — confirma que é o ficheiro correcto.",
            ];
        }
    }

    return $badges;
}


/**
 * Render HTML dos badges (chips coloridos compactos).
 */
function rmbz_exclusive_render_badges( $badges ) {
    if ( empty( $badges ) ) {
        return '<span class="rmbz-exc-clean">✓ Limpo</span>';
    }
    $out = '<div class="rmbz-exc-badges-row">';
    foreach ( $badges as $b ) {
        $out .= sprintf(
            '<span class="rmbz-exc-badge rmbz-exc-badge-%s" title="%s">%s %s</span>',
            esc_attr( $b['severity'] ),
            esc_attr( $b['tip'] ),
            esc_html( $b['icon'] ),
            esc_html( $b['label'] )
        );
    }
    return $out . '</div>';
}


/* ============================================================================
 * [FEAT 1.6.2] AJAX HANDLERS para vista compacta
 *
 * Permite aprovar/rejeitar/conflito sem reload da página, e devolve
 * estados actualizados para a UI marcar a linha como "decidida".
 *
 * Reutiliza a lógica do handler PHP existente (rmbz_decide_exclusive)
 * via curl-like internal call para garantir consistência.
 * ============================================================================ */
add_action( 'wp_ajax_rmbz_exc_quick_decide', function () {
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_send_json_error( ['message' => 'Sem permissão'], 403 );
    }
    check_ajax_referer( 'rmbz_exc_quick_decide', 'nonce' );

    $release_id = isset($_POST['release_id']) ? absint($_POST['release_id']) : 0;
    $service    = isset($_POST['service']) ? sanitize_key($_POST['service']) : '';
    $decision   = isset($_POST['decision']) ? sanitize_key($_POST['decision']) : '';
    $note       = isset($_POST['note']) ? sanitize_textarea_field( wp_unslash($_POST['note']) ) : '';

    // Validações iguais ao handler PHP existente
    if ( ! $release_id || ! in_array($service, ['yt_content_id','fb_monet','tt_monet'], true) ) {
        wp_send_json_error( ['message' => 'Parâmetros inválidos'], 400 );
    }
    if ( ! in_array($decision, ['approved','rejected','conflict'], true) ) {
        wp_send_json_error( ['message' => 'Decisão inválida'], 400 );
    }

    // Algumas decisões exigem nota
    if ( in_array($decision, ['rejected','conflict'], true) && strlen($note) < 5 ) {
        wp_send_json_error( ['message' => 'Nota é obrigatória para rejeitar ou marcar conflito (mín. 5 caracteres)'], 400 );
    }

    global $wpdb;
    $table_p = $wpdb->prefix . 'rmbz_distro_release_platforms';

    $svc_map = [
        'yt_content_id' => ['col' => 'yt_content_id_status', 'note_col' => 'yt_content_id_decision_note'],
        'fb_monet'      => ['col' => 'fb_monet_status',      'note_col' => 'fb_monet_decision_note'],
        'tt_monet'      => ['col' => 'tt_monet_status',      'note_col' => 'tt_monet_decision_note'],
    ];
    $col = $svc_map[$service]['col'];
    $note_col = $svc_map[$service]['note_col'];

    $admin = wp_get_current_user()->user_login ?: 'admin';
    $wpdb->query( $wpdb->prepare(
        "UPDATE $table_p
            SET $col = %s,
                $note_col = %s,
                decided_by = %s,
                decided_at = NOW(),
                updated_at = NOW()
          WHERE release_id = %d",
        $decision, $note, $admin, $release_id
    ) );

    wp_send_json_success([
        'release_id' => $release_id,
        'service'    => $service,
        'decision'   => $decision,
        'message'    => match($decision) {
            'approved' => '✓ Aprovado',
            'rejected' => '✗ Rejeitado',
            'conflict' => '⚠ Marcado como conflito',
        },
    ]);
} );


/**
 * AJAX: devolve o HTML expandido de um release (player + tracks + pesquisa
 * externa). Carregamento lazy — só pede quando o admin clica para expandir.
 */
add_action( 'wp_ajax_rmbz_exc_load_detail', function () {
    if ( ! current_user_can( 'manage_options' ) ) {
        wp_send_json_error( ['message' => 'Sem permissão'], 403 );
    }
    check_ajax_referer( 'rmbz_exc_load_detail', 'nonce' );

    $release_id = isset($_GET['release_id']) ? absint($_GET['release_id']) : 0;
    if ( ! $release_id ) wp_send_json_error( ['message' => 'Release inválido'], 400 );

    global $wpdb;
    $table_r = $wpdb->prefix . 'rmbz_distro_releases';
    $table_t = $wpdb->prefix . 'rmbz_distro_tracks';
    $table_w = $wpdb->prefix . 'rmbz_wallets';

    $row = $wpdb->get_row( $wpdb->prepare(
        "SELECT r.*, w.user_nome
           FROM $table_r r
           LEFT JOIN $table_w w ON r.artist_telemovel = w.user_telemovel
          WHERE r.id = %d",
        $release_id
    ) );
    if ( ! $row ) wp_send_json_error( ['message' => 'Release não encontrado'], 404 );

    $tracks = $wpdb->get_results( $wpdb->prepare(
        "SELECT id, track_title, audio_url, isrc_code, track_order
           FROM $table_t
          WHERE release_id = %d
          ORDER BY track_order ASC, id ASC
          LIMIT 20",
        $release_id
    ) );
    $primary_track = $tracks[0] ?? null;
    $primary_title = $primary_track->track_title ?? $row->title;
    $artist_name = $row->user_nome ?: $row->artist_telemovel;
    $search_links = rmbz_exclusive_build_search_links(
        $primary_title, $artist_name, $primary_track->isrc_code ?? ''
    );

    ob_start();
    ?>
    <div class="rmbz-exc-detail-inner">
        <?php /* [polimento 1.6.3] Player da faixa primária removido — o admin já
                 tem o botão ▶ na linha compacta. Aqui mostramos só o que
                 EXPLICA expandir: outras faixas + pesquisa externa. */ ?>

        <?php if ( count($tracks) > 1 ): ?>
            <div class="rmbz-exc-tracks-mini">
                <div class="rmbz-exc-detail-section-title">📑 Outras faixas do release</div>
                <?php foreach ( $tracks as $i => $t ): if ( $i === 0 ) continue; ?>
                <div class="rmbz-exc-track-mini-row">
                    <span class="rmbz-exc-track-num"><?php echo (int)( $t->track_order ?: ($i+1) ); ?></span>
                    <span class="rmbz-exc-track-title-mini"><?php echo esc_html( $t->track_title ); ?></span>
                    <?php if ( $t->isrc_code ): ?>
                        <code class="rmbz-exc-track-isrc"><?php echo esc_html( $t->isrc_code ); ?></code>
                    <?php else: ?>
                        <code class="rmbz-exc-track-isrc rmbz-exc-track-isrc-missing">— sem ISRC —</code>
                    <?php endif; ?>
                    <?php if ( $t->audio_url ): ?>
                        <button type="button" class="rmbz-exc-mini-play"
                                data-src="<?php echo esc_url( $t->audio_url ); ?>"
                                title="Tocar esta faixa">▶</button>
                    <?php else: ?>
                        <span class="rmbz-exc-no-audio">sem áudio</span>
                    <?php endif; ?>
                </div>
                <?php endforeach; ?>
            </div>
        <?php endif; ?>

        <div class="rmbz-exc-detail-search">
            <div class="rmbz-exc-detail-section-title">🔎 Pesquisa externa</div>
            <div class="rmbz-exc-detail-search-links">
                <?php foreach ( $search_links as $link ): ?>
                    <a href="<?php echo esc_url( $link['url'] ); ?>" target="_blank" rel="noopener" class="rmbz-exc-detail-srch-btn">
                        <?php echo esc_html( $link['icon'] . ' ' . $link['label'] ); ?>
                    </a>
                <?php endforeach; ?>
            </div>
        </div>

        <a href="<?php echo esc_url( admin_url('admin.php?page=rmbz-admin-distribution&tab=releases&view=detail&id=' . $release_id) ); ?>"
           class="rmbz-exc-detail-link">Ver release completo →</a>
    </div>
    <?php
    wp_send_json_success([ 'html' => ob_get_clean() ]);
} );


/* ============================================================================
 * [FEAT 1.6.2] VISTA COMPACTA — uma linha por release
 *
 * Cada linha: capa + título + artista + badges + status dos 3 serviços +
 * mini-player + botão expandir. Click na linha → expande inline com detalhes
 * carregados via AJAX (lazy load — não puxamos tudo de uma vez).
 *
 * As decisões (aprovar/rejeitar/conflito) abrem um popover por serviço
 * com nota opcional/obrigatória, e submetem via AJAX (sem reload).
 * ============================================================================ */
function rmbz_render_exclusive_compact_rows( $rows, $current_filter, $service_labels, $wpdb, $table_t ) {
    $ajax_nonce_decide = wp_create_nonce('rmbz_exc_quick_decide');
    $ajax_nonce_detail = wp_create_nonce('rmbz_exc_load_detail');
    ?>
    <div class="rmbz-exc-compact-wrap"
         data-nonce-decide="<?php echo esc_attr($ajax_nonce_decide); ?>"
         data-nonce-detail="<?php echo esc_attr($ajax_nonce_detail); ?>"
         data-ajax-url="<?php echo esc_url(admin_url('admin-ajax.php')); ?>">

        <?php foreach ( $rows as $idx => $row ):
            // Faixa primária (para badges e mini-player)
            $primary_track = $wpdb->get_row( $wpdb->prepare(
                "SELECT id, track_title, audio_url, isrc_code, track_order
                   FROM $table_t
                  WHERE release_id = %d
                  ORDER BY track_order ASC, id ASC
                  LIMIT 1",
                $row->release_id
            ) );
            $artist_name = $row->user_nome ?: $row->artist_telemovel;
            $age_days = isset($row->updated_at) ? (int)( ( time() - strtotime($row->updated_at) ) / 86400 ) : 0;
            $badges = rmbz_exclusive_compute_badges( $row, $primary_track, $wpdb, $table_t );
        ?>
        <div class="rmbz-exc-c-row"
             tabindex="0"
             data-release-id="<?php echo (int) $row->release_id; ?>"
             data-row-idx="<?php echo (int) $idx; ?>">

            <!-- Capa -->
            <div class="rmbz-exc-c-cover">
                <?php if ( $row->cover_image ): ?>
                    <img src="<?php echo esc_url($row->cover_image); ?>" alt="">
                <?php else: ?>
                    <span>🎵</span>
                <?php endif; ?>
            </div>

            <!-- Info -->
            <div class="rmbz-exc-c-info">
                <div class="rmbz-exc-c-title">
                    <?php echo esc_html($row->release_title); ?>
                    <?php if ( $age_days >= 7 ): ?>
                        <small class="rmbz-exc-c-age" title="Aguarda há <?php echo $age_days; ?> dias">
                            ⏱️ <?php echo $age_days; ?>d
                        </small>
                    <?php endif; ?>
                </div>
                <div class="rmbz-exc-c-meta">
                    <strong><?php echo esc_html($artist_name); ?></strong>
                    · <code><?php echo esc_html($row->artist_telemovel); ?></code>
                    <?php if ( $primary_track && $primary_track->isrc_code ): ?>
                        · ISRC <code><?php echo esc_html($primary_track->isrc_code); ?></code>
                    <?php endif; ?>
                </div>
                <?php if ( ! empty($badges) ): ?>
                    <?php echo rmbz_exclusive_render_badges($badges); ?>
                <?php endif; ?>
            </div>

            <!-- Mini-player -->
            <div class="rmbz-exc-c-audio">
                <?php if ( $primary_track && $primary_track->audio_url ): ?>
                    <audio preload="none" src="<?php echo esc_url($primary_track->audio_url); ?>"></audio>
                    <button type="button" class="rmbz-exc-c-play" title="Espaço para tocar">▶</button>
                <?php endif; ?>
            </div>

            <!-- Status dos 3 serviços (pills) -->
            <div class="rmbz-exc-c-services">
                <?php foreach ( $service_labels as $svc_key => $svc ):
                    $status = $row->{$svc['col']} ?? 'not_requested';
                    if ( $status === 'not_requested' ) continue;
                    $label_map = [
                        'requested' => ['cls' => 'pending',  'icon' => '⏳', 'txt' => 'Pend.'],
                        'approved'  => ['cls' => 'approved', 'icon' => '✓',  'txt' => 'Apr.'],
                        'rejected'  => ['cls' => 'rejected', 'icon' => '✗',  'txt' => 'Rej.'],
                        'conflict'  => ['cls' => 'conflict', 'icon' => '⚠',  'txt' => 'Conf.'],
                    ];
                    $lab = $label_map[$status] ?? null;
                    if ( ! $lab ) continue;
                ?>
                <span class="rmbz-exc-c-svc rmbz-exc-c-svc-<?php echo esc_attr($lab['cls']); ?>"
                      data-svc="<?php echo esc_attr($svc_key); ?>"
                      data-status="<?php echo esc_attr($status); ?>"
                      title="<?php echo esc_attr($svc['label'] . ' — ' . $status); ?>">
                    <?php echo rmbz_exc_platform_svg( $svc_key ); ?>
                    <span class="rmbz-exc-c-svc-status"><?php echo $lab['icon']; ?></span>
                </span>
                <?php endforeach; ?>
            </div>

            <!-- Botões de decisão -->
            <div class="rmbz-exc-c-actions">
                <?php
                // Detectar quais serviços estão pendentes (precisam de decisão)
                $pending_services = [];
                foreach ( $service_labels as $svc_key => $svc ) {
                    $status = $row->{$svc['col']} ?? 'not_requested';
                    if ( $status === 'requested' ) {
                        $pending_services[$svc_key] = $svc['label'];
                    }
                }
                if ( ! empty($pending_services) ):
                ?>
                <button type="button" class="rmbz-exc-c-btn rmbz-exc-c-btn-approve"
                        data-decision="approved"
                        title="Aprovar (tecla A)">
                    ✓ Aprovar
                </button>
                <button type="button" class="rmbz-exc-c-btn rmbz-exc-c-btn-conflict"
                        data-decision="conflict"
                        title="Marcar conflito (tecla C)">
                    ⚠
                </button>
                <button type="button" class="rmbz-exc-c-btn rmbz-exc-c-btn-reject"
                        data-decision="rejected"
                        title="Rejeitar (tecla R)">
                    ✗
                </button>
                <?php else: ?>
                <span style="color:#999; font-size:11px; padding:6px 10px;">Sem pendentes</span>
                <?php endif; ?>
                <button type="button" class="rmbz-exc-c-btn rmbz-exc-c-btn-expand"
                        title="Ver detalhes (player completo + pesquisa externa)">
                    ⌄
                </button>
            </div>

            <!-- Painel de detalhe (vazio até expandir; carregado via AJAX) -->
            <div class="rmbz-exc-c-detail" hidden></div>

            <!-- Painel de decisão por serviço (oculto até clicar num botão) -->
            <div class="rmbz-exc-c-decision-panel" hidden>
                <div class="rmbz-exc-c-decision-svc-picker">
                    <strong>Qual serviço?</strong>
                    <?php foreach ( $pending_services as $sk => $sl ): ?>
                        <label>
                            <input type="checkbox" name="svc[]" value="<?php echo esc_attr($sk); ?>" checked>
                            <?php echo esc_html($sl); ?>
                        </label>
                    <?php endforeach; ?>
                </div>
                <textarea class="rmbz-exc-c-decision-note" rows="2"
                          placeholder="Nota (obrigatória para rejeitar / conflito; opcional para aprovar)"></textarea>
                <div class="rmbz-exc-c-decision-actions">
                    <button type="button" class="button button-primary rmbz-exc-c-decision-submit">Confirmar</button>
                    <button type="button" class="button rmbz-exc-c-decision-cancel">Cancelar</button>
                </div>
            </div>
        </div>
        <?php endforeach; ?>
    </div>

    <?php rmbz_exclusive_render_compact_assets(); ?>
    <?php
}


/**
 * CSS + JS da vista compacta. Inline para auto-contenção.
 * Inclui handlers de atalhos de teclado, AJAX e expansão.
 */
function rmbz_exclusive_render_compact_assets() {
    static $rendered = false;
    if ( $rendered ) return; // só uma vez por página
    $rendered = true;
    ?>
    <style>
    /* ════════════════════ TOGGLE DE VISTA ════════════════════ */
    .rmbz-exc-view-toggle {
        display: flex; align-items: center; gap: 8px;
        padding: 10px 14px;
        background: #fafbfc;
        border: 1px solid #e6e8eb;
        border-radius: 8px;
        margin-bottom: 14px;
        font-size: 12px;
        flex-wrap: wrap;
    }
    .rmbz-exc-view-toggle > span:first-child {
        color: #6b7280; font-weight: 600; text-transform: uppercase;
        letter-spacing: 0.04em; font-size: 11px;
    }
    .rmbz-exc-view-toggle a {
        text-decoration: none;
        padding: 5px 11px;
        border: 1px solid #d1d5db;
        border-radius: 6px;
        color: #1a1a1a;
        background: #fff;
        font-weight: 500;
        transition: all 0.15s;
    }
    .rmbz-exc-view-toggle a:hover {
        border-color: #f0b90b;
        color: #f0b90b;
    }
    .rmbz-exc-view-toggle a.is-active {
        background: #1a1a1a;
        color: #f0b90b;
        border-color: #f0b90b;
    }
    .rmbz-exc-view-tip {
        margin-left: auto; color: #9ca3af; font-size: 11px;
    }
    .rmbz-exc-view-tip kbd {
        background: #fff; border: 1px solid #d1d5db; border-radius: 4px;
        padding: 1px 5px; font-size: 10px; font-family: ui-monospace, monospace;
        color: #1a1a1a;
    }

    /* ════════════════════ LINHA COMPACTA ════════════════════ */
    .rmbz-exc-compact-wrap {
        display: flex; flex-direction: column; gap: 6px;
    }
    .rmbz-exc-c-row {
        display: grid;
        grid-template-columns: 48px 1fr auto auto auto;
        gap: 12px;
        align-items: center;
        padding: 8px 12px;
        background: #fff;
        border: 1px solid #e6e8eb;
        border-radius: 9px;
        transition: all 0.15s ease;
        outline: none;
    }
    .rmbz-exc-c-row:hover {
        border-color: #d1d5db;
        box-shadow: 0 2px 6px rgba(0,0,0,0.05);
    }
    .rmbz-exc-c-row:focus,
    .rmbz-exc-c-row.is-focused {
        border-color: #f0b90b;
        box-shadow: 0 0 0 3px rgba(240, 185, 11, 0.18);
    }
    .rmbz-exc-c-row.is-decided {
        opacity: 0.5;
        background: #fafbfc;
    }
    .rmbz-exc-c-row.is-just-decided {
        animation: rmbz-exc-flash 0.5s ease;
    }
    @keyframes rmbz-exc-flash {
        0%   { background: #d1fae5; }
        100% { background: #fff; }
    }

    /* ────── Capa ────── */
    .rmbz-exc-c-cover {
        width: 48px; height: 48px;
        border-radius: 6px;
        background: #e5e7eb;
        overflow: hidden;
        display: flex; align-items: center; justify-content: center;
        flex-shrink: 0;
    }
    .rmbz-exc-c-cover img {
        width: 100%; height: 100%; object-fit: cover;
    }
    .rmbz-exc-c-cover span { font-size: 20px; color: #9ca3af; }

    /* ────── Info ────── */
    .rmbz-exc-c-info { min-width: 0; }
    .rmbz-exc-c-title {
        font-weight: 600; font-size: 13.5px; color: #1a1a1a;
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
        display: flex; align-items: center; gap: 8px;
    }
    .rmbz-exc-c-age {
        color: #d97706; font-weight: 500; font-size: 10px;
        background: #fef3c7; padding: 1px 6px; border-radius: 8px;
    }
    .rmbz-exc-c-meta {
        font-size: 11px; color: #6b7280; margin-top: 1px;
        white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
    }
    .rmbz-exc-c-meta code {
        background: #f3f4f6; padding: 1px 5px; border-radius: 3px;
        font-size: 10px;
    }

    /* ────── Badges automáticos ────── */
    .rmbz-exc-badges-row {
        display: flex; gap: 4px; flex-wrap: wrap; margin-top: 4px;
    }
    .rmbz-exc-badge {
        display: inline-flex; align-items: center; gap: 3px;
        padding: 1px 6px; border-radius: 8px;
        font-size: 10px; font-weight: 600;
        white-space: nowrap;
    }
    .rmbz-exc-badge-high   { background: #fee2e2; color: #991b1b; border: 1px solid #fecaca; }
    .rmbz-exc-badge-medium { background: #fef3c7; color: #92400e; border: 1px solid #fde68a; }
    .rmbz-exc-badge-low    { background: #f3f4f6; color: #4b5563; border: 1px solid #e5e7eb; }
    .rmbz-exc-clean {
        display: inline-block; padding: 1px 8px; border-radius: 8px;
        background: #d1fae5; color: #065f46; font-size: 10px;
        font-weight: 600; margin-top: 4px;
    }

    /* ────── Mini-player ────── */
    .rmbz-exc-c-audio {
        position: relative;
    }
    .rmbz-exc-c-audio audio { display: none; }
    .rmbz-exc-c-play {
        width: 32px; height: 32px;
        border-radius: 50%;
        background: #1a1a1a;
        color: #f0b90b;
        border: 1px solid #f0b90b;
        cursor: pointer;
        font-size: 12px;
        display: flex; align-items: center; justify-content: center;
        transition: all 0.15s;
    }
    .rmbz-exc-c-play:hover { background: #f0b90b; color: #1a1a1a; transform: scale(1.05); }
    .rmbz-exc-c-play.is-playing { background: #dc2626; color: #fff; border-color: #dc2626; }

    /* ────── Pills de serviços ────── */
    .rmbz-exc-c-services { display: flex; gap: 4px; }
    .rmbz-exc-c-svc {
        display: inline-flex; align-items: center; gap: 4px;
        padding: 3px 8px; border-radius: 12px;
        font-size: 11px; font-weight: 700;
        line-height: 1;
    }
    .rmbz-exc-c-svc svg {
        flex-shrink: 0;
        vertical-align: middle;
    }
    .rmbz-exc-c-svc-status {
        font-size: 10px;
        opacity: 0.9;
    }
    .rmbz-exc-c-svc-pending   { background: #fef3c7; color: #92400e; border: 1px solid #fde68a; }
    .rmbz-exc-c-svc-approved  { background: #d1fae5; color: #065f46; border: 1px solid #a7f3d0; }
    .rmbz-exc-c-svc-rejected  { background: #fee2e2; color: #991b1b; border: 1px solid #fecaca; }
    .rmbz-exc-c-svc-conflict  { background: #fed7aa; color: #9a3412; border: 1px solid #fdba74; }

    /* ────── Botões de acção ────── */
    .rmbz-exc-c-actions {
        display: flex; gap: 4px; align-items: center;
    }
    .rmbz-exc-c-btn {
        padding: 6px 10px;
        border-radius: 6px;
        font-size: 11px;
        font-weight: 600;
        cursor: pointer;
        border: 1px solid;
        transition: all 0.15s;
        white-space: nowrap;
    }
    .rmbz-exc-c-btn-approve {
        background: #10b981; color: #fff; border-color: #10b981;
    }
    .rmbz-exc-c-btn-approve:hover { background: #059669; }
    .rmbz-exc-c-btn-conflict {
        background: #fff; color: #d97706; border-color: #fdba74;
        padding: 6px 8px;
    }
    .rmbz-exc-c-btn-conflict:hover { background: #fed7aa; }
    .rmbz-exc-c-btn-reject {
        background: #fff; color: #dc2626; border-color: #fecaca;
        padding: 6px 8px;
    }
    .rmbz-exc-c-btn-reject:hover { background: #fee2e2; }
    .rmbz-exc-c-btn-expand {
        background: #fff; color: #6b7280; border-color: #e5e7eb;
        padding: 6px 8px;
    }
    .rmbz-exc-c-btn-expand:hover { background: #f3f4f6; }
    .rmbz-exc-c-row.is-expanded .rmbz-exc-c-btn-expand {
        background: #1a1a1a; color: #f0b90b; border-color: #f0b90b;
        transform: rotate(180deg);
    }

    /* ────── Painel de detalhe expandido ────── */
    .rmbz-exc-c-detail {
        grid-column: 1 / -1;
        padding: 16px 18px;
        background: linear-gradient(180deg, #fafbfc 0%, #f3f4f6 100%);
        border-top: 1px dashed #e6e8eb;
        margin-top: 6px;
        border-radius: 0 0 8px 8px;
    }
    .rmbz-exc-c-detail[hidden] { display: none; }
    .rmbz-exc-detail-inner {
        display: flex; flex-direction: column; gap: 14px;
    }
    .rmbz-exc-detail-section-title {
        font-size: 10px; color: #6b7280;
        text-transform: uppercase; letter-spacing: 0.05em;
        font-weight: 700;
        margin-bottom: 8px;
        display: flex; align-items: center; gap: 6px;
    }

    /* Outras faixas */
    .rmbz-exc-tracks-mini {
        background: #fff;
        border: 1px solid #e6e8eb;
        border-radius: 8px;
        padding: 10px 14px;
    }
    .rmbz-exc-track-mini-row {
        display: grid;
        grid-template-columns: 22px 1fr auto auto;
        align-items: center;
        gap: 10px;
        padding: 6px 0;
        font-size: 12.5px;
        border-bottom: 1px solid #f3f4f6;
    }
    .rmbz-exc-track-mini-row:last-child { border-bottom: none; }
    .rmbz-exc-track-num {
        width: 22px; height: 22px;
        display: inline-flex; align-items: center; justify-content: center;
        background: #f3f4f6; color: #6b7280;
        border-radius: 50%;
        font-size: 10px; font-weight: 700;
    }
    .rmbz-exc-track-title-mini {
        color: #1a1a1a; font-weight: 500;
    }
    .rmbz-exc-track-isrc {
        background: #f3f4f6; color: #1a1a1a;
        padding: 2px 7px; border-radius: 4px;
        font-size: 10px; font-family: ui-monospace, monospace;
    }
    .rmbz-exc-track-isrc-missing {
        background: #fee2e2; color: #991b1b; font-style: italic;
    }
    .rmbz-exc-no-audio {
        color: #9ca3af; font-style: italic; font-size: 11px;
        padding: 0 8px;
    }

    /* Mini-player das outras faixas — dourado/preto 1MZ */
    .rmbz-exc-mini-play {
        width: 26px; height: 26px;
        border-radius: 50%;
        background: #1a1a1a;
        color: #f0b90b;
        border: 1px solid #f0b90b;
        cursor: pointer;
        font-size: 10px;
        display: flex; align-items: center; justify-content: center;
        transition: all 0.15s;
        padding: 0;
    }
    .rmbz-exc-mini-play:hover {
        background: #f0b90b; color: #1a1a1a;
        transform: scale(1.08);
    }
    .rmbz-exc-mini-play.is-playing {
        background: #dc2626; color: #fff; border-color: #dc2626;
    }

    /* Pesquisa externa */
    .rmbz-exc-detail-search {
        background: #fff;
        border: 1px solid #e6e8eb;
        border-radius: 8px;
        padding: 10px 14px;
    }
    .rmbz-exc-detail-search-links {
        display: flex; flex-wrap: wrap; gap: 6px;
    }
    .rmbz-exc-detail-srch-btn {
        background: #1a1a1a; color: #f0b90b;
        border: 1px solid #f0b90b;
        padding: 5px 12px; border-radius: 6px;
        font-size: 11px; font-weight: 500;
        text-decoration: none;
        transition: all 0.15s;
        display: inline-flex; align-items: center; gap: 4px;
    }
    .rmbz-exc-detail-srch-btn:hover {
        background: #f0b90b; color: #1a1a1a;
        transform: translateY(-1px);
        box-shadow: 0 2px 6px rgba(240, 185, 11, 0.3);
    }

    /* Link ver release completo */
    .rmbz-exc-detail-link {
        align-self: flex-start;
        background: #fff;
        color: #1a1a1a;
        border: 1px solid #d1d5db;
        padding: 6px 14px;
        border-radius: 6px;
        font-size: 12px;
        font-weight: 500;
        text-decoration: none;
        transition: all 0.15s;
    }
    .rmbz-exc-detail-link:hover {
        border-color: #f0b90b;
        color: #f0b90b;
    }

    /* ────── Painel de decisão (popover por linha) ────── */
    .rmbz-exc-c-decision-panel {
        grid-column: 1 / -1;
        padding: 12px;
        background: #fff;
        border: 2px solid #f0b90b;
        border-radius: 8px;
        margin-top: 6px;
        box-shadow: 0 4px 12px rgba(0,0,0,0.08);
    }
    .rmbz-exc-c-decision-panel[hidden] { display: none; }
    .rmbz-exc-c-decision-svc-picker {
        margin-bottom: 10px;
        font-size: 12px;
    }
    .rmbz-exc-c-decision-svc-picker label {
        display: inline-flex; align-items: center; gap: 4px;
        margin-right: 12px;
        font-weight: 500;
    }
    .rmbz-exc-c-decision-note {
        width: 100%;
        padding: 8px 10px;
        border: 1px solid #d1d5db;
        border-radius: 6px;
        font-size: 13px;
        font-family: inherit;
        resize: vertical;
        margin-bottom: 8px;
    }
    .rmbz-exc-c-decision-actions {
        display: flex; gap: 8px; justify-content: flex-end;
    }

    /* ────── Responsivo ────── */
    @media (max-width: 900px) {
        .rmbz-exc-c-row {
            grid-template-columns: 48px 1fr;
            grid-template-areas:
                "cov info"
                "aud svc"
                "act act";
        }
        .rmbz-exc-c-cover { grid-area: cov; }
        .rmbz-exc-c-info { grid-area: info; }
        .rmbz-exc-c-audio { grid-area: aud; }
        .rmbz-exc-c-services { grid-area: svc; justify-content: flex-end; }
        .rmbz-exc-c-actions { grid-area: act; justify-content: stretch; }
        .rmbz-exc-c-actions .rmbz-exc-c-btn { flex: 1; }
        .rmbz-exc-view-tip { display: none; }
    }
    </style>

    <script>
    (function () {
        var wrap = document.querySelector('.rmbz-exc-compact-wrap');
        if (!wrap) return;

        var ajaxUrl = wrap.dataset.ajaxUrl;
        var nonceDecide = wrap.dataset.nonceDecide;
        var nonceDetail = wrap.dataset.nonceDetail;

        // Áudio em reprodução actual (só um por vez)
        var currentAudio = null;
        var currentPlayBtn = null;

        function stopCurrent() {
            if (currentAudio) {
                currentAudio.pause();
                if (currentPlayBtn) {
                    currentPlayBtn.textContent = '▶';
                    currentPlayBtn.classList.remove('is-playing');
                }
                currentAudio = null;
                currentPlayBtn = null;
            }
        }

        function togglePlay(row) {
            var btn = row.querySelector('.rmbz-exc-c-play');
            var audio = row.querySelector('.rmbz-exc-c-audio audio');
            if (!btn || !audio) return;
            if (currentAudio === audio) {
                // já está a tocar → pausar
                stopCurrent();
                return;
            }
            stopCurrent();
            audio.play().then(function () {
                currentAudio = audio;
                currentPlayBtn = btn;
                btn.textContent = '⏸';
                btn.classList.add('is-playing');
                audio.onended = stopCurrent;
            }).catch(function () { /* autoplay bloqueado */ });
        }

        // ═══════════════════════ Mini-players de outras faixas ═══════════════════════
        // Usados dentro do detalhe expandido. Diferente do play da linha
        // principal — estes criam um <audio> em runtime a partir do data-src
        // do botão, e partilham o "currentAudio" para garantir só um a tocar.
        document.addEventListener('click', function (e) {
            var btn = e.target.closest('.rmbz-exc-mini-play');
            if (!btn) return;
            e.stopPropagation();
            // Se este botão já está a tocar → pausar
            if (btn.classList.contains('is-playing')) {
                stopCurrent();
                return;
            }
            stopCurrent();
            var audio = new Audio(btn.dataset.src);
            audio.play().then(function () {
                currentAudio = audio;
                currentPlayBtn = btn;
                btn.textContent = '⏸';
                btn.classList.add('is-playing');
                audio.onended = stopCurrent;
            }).catch(function () { /* silêncio */ });
        });

        // ═══════════════════════ AJAX: expandir linha ═══════════════════════
        function expandRow(row) {
            var detail = row.querySelector('.rmbz-exc-c-detail');
            if (!detail) return;
            if (row.classList.contains('is-expanded')) {
                detail.hidden = true;
                row.classList.remove('is-expanded');
                return;
            }
            row.classList.add('is-expanded');
            detail.hidden = false;
            if (detail.dataset.loaded) return; // cache do conteúdo carregado
            detail.innerHTML = '<div style="padding:14px; text-align:center; color:#999;">A carregar…</div>';
            var rid = row.dataset.releaseId;
            fetch(ajaxUrl + '?action=rmbz_exc_load_detail&release_id=' + rid + '&nonce=' + nonceDetail)
                .then(function (r) { return r.json(); })
                .then(function (resp) {
                    if (resp && resp.success && resp.data && resp.data.html) {
                        detail.innerHTML = resp.data.html;
                        detail.dataset.loaded = '1';
                    } else {
                        detail.innerHTML = '<div style="padding:14px; color:#dc2626;">Erro ao carregar.</div>';
                    }
                })
                .catch(function () {
                    detail.innerHTML = '<div style="padding:14px; color:#dc2626;">Erro de rede.</div>';
                });
        }

        // ═══════════════════════ Painel de decisão ═══════════════════════
        var openDecisionPanel = null;
        var openDecisionMode = null;

        function showDecisionPanel(row, decision) {
            // Fechar qualquer painel aberto
            if (openDecisionPanel && openDecisionPanel !== row.querySelector('.rmbz-exc-c-decision-panel')) {
                openDecisionPanel.hidden = true;
            }
            var panel = row.querySelector('.rmbz-exc-c-decision-panel');
            if (!panel) return;
            panel.hidden = false;
            panel.dataset.decision = decision;
            openDecisionPanel = panel;
            openDecisionMode = decision;
            // Focar textarea
            var ta = panel.querySelector('.rmbz-exc-c-decision-note');
            if (ta) {
                ta.placeholder = (decision === 'approved')
                    ? 'Nota opcional (visível ao artista)'
                    : 'Motivo (obrigatório, mín. 5 caracteres)';
                setTimeout(function () { ta.focus(); }, 50);
            }
        }

        function hideDecisionPanel(row) {
            var panel = row.querySelector('.rmbz-exc-c-decision-panel');
            if (panel) { panel.hidden = true; openDecisionPanel = null; openDecisionMode = null; }
        }

        // ═══════════════════════ AJAX: decidir ═══════════════════════
        function submitDecision(row, decision, selectedSvcs, note) {
            var rid = row.dataset.releaseId;
            var promises = selectedSvcs.map(function (svc) {
                var fd = new FormData();
                fd.append('action', 'rmbz_exc_quick_decide');
                fd.append('nonce', nonceDecide);
                fd.append('release_id', rid);
                fd.append('service', svc);
                fd.append('decision', decision);
                fd.append('note', note);
                return fetch(ajaxUrl, { method: 'POST', body: fd })
                    .then(function (r) { return r.json(); });
            });
            return Promise.all(promises);
        }

        // ═══════════════════════ Listeners ═══════════════════════
        wrap.addEventListener('click', function (e) {
            var row = e.target.closest('.rmbz-exc-c-row');
            if (!row) return;

            // Botão Play
            if (e.target.closest('.rmbz-exc-c-play')) {
                e.stopPropagation();
                togglePlay(row);
                return;
            }
            // Botão Expandir
            if (e.target.closest('.rmbz-exc-c-btn-expand')) {
                e.stopPropagation();
                expandRow(row);
                return;
            }
            // Botões de decisão (abrir painel)
            var decisionBtn = e.target.closest('.rmbz-exc-c-btn-approve, .rmbz-exc-c-btn-reject, .rmbz-exc-c-btn-conflict');
            if (decisionBtn) {
                e.stopPropagation();
                showDecisionPanel(row, decisionBtn.dataset.decision);
                return;
            }
            // Cancelar
            if (e.target.closest('.rmbz-exc-c-decision-cancel')) {
                e.stopPropagation();
                hideDecisionPanel(row);
                return;
            }
            // Confirmar
            if (e.target.closest('.rmbz-exc-c-decision-submit')) {
                e.stopPropagation();
                var panel = row.querySelector('.rmbz-exc-c-decision-panel');
                var decision = panel.dataset.decision;
                var note = panel.querySelector('.rmbz-exc-c-decision-note').value.trim();
                var selectedSvcs = Array.from(panel.querySelectorAll('input[name="svc[]"]:checked')).map(function (i) { return i.value; });

                if (selectedSvcs.length === 0) {
                    alert('Escolhe pelo menos um serviço.');
                    return;
                }
                if ((decision === 'rejected' || decision === 'conflict') && note.length < 5) {
                    alert('Nota é obrigatória (mín. 5 caracteres) para rejeitar ou marcar conflito.');
                    return;
                }
                var submitBtn = panel.querySelector('.rmbz-exc-c-decision-submit');
                submitBtn.textContent = 'A processar…';
                submitBtn.disabled = true;
                submitDecision(row, decision, selectedSvcs, note).then(function (results) {
                    var allOk = results.every(function (r) { return r && r.success; });
                    if (allOk) {
                        hideDecisionPanel(row);
                        row.classList.add('is-decided', 'is-just-decided');
                        setTimeout(function () { row.classList.remove('is-just-decided'); }, 600);
                        // Focar próxima linha não-decidida
                        focusNextRow(row);
                    } else {
                        var first = results.find(function (r) { return r && !r.success; });
                        alert('Erro: ' + (first && first.data ? first.data.message : 'desconhecido'));
                        submitBtn.textContent = 'Confirmar';
                        submitBtn.disabled = false;
                    }
                });
                return;
            }

            // Clique geral na linha → expande (mas não na zona de pills)
            if (!e.target.closest('.rmbz-exc-c-services') &&
                !e.target.closest('.rmbz-exc-c-decision-panel') &&
                !e.target.closest('.rmbz-exc-c-detail')) {
                row.focus();
            }
        });

        // ═══════════════════════ Atalhos de teclado ═══════════════════════
        function getFocusedRow() {
            return document.activeElement && document.activeElement.classList.contains('rmbz-exc-c-row')
                ? document.activeElement : null;
        }
        function focusNextRow(fromRow) {
            var rows = Array.from(wrap.querySelectorAll('.rmbz-exc-c-row:not(.is-decided)'));
            var idx = rows.indexOf(fromRow);
            if (idx >= 0 && idx + 1 < rows.length) {
                rows[idx + 1].focus();
                rows[idx + 1].scrollIntoView({ block: 'nearest', behavior: 'smooth' });
            }
        }
        function focusPrevRow(fromRow) {
            var rows = Array.from(wrap.querySelectorAll('.rmbz-exc-c-row'));
            var idx = rows.indexOf(fromRow);
            if (idx > 0) {
                rows[idx - 1].focus();
                rows[idx - 1].scrollIntoView({ block: 'nearest', behavior: 'smooth' });
            }
        }

        document.addEventListener('keydown', function (e) {
            // Não interceptar se estamos a digitar num input/textarea
            var tag = (e.target.tagName || '').toLowerCase();
            if (tag === 'input' || tag === 'textarea' || tag === 'select') return;

            var row = getFocusedRow();
            if (!row) return;

            switch (e.key) {
                case 'ArrowDown':
                    e.preventDefault();
                    focusNextRow(row);
                    break;
                case 'ArrowUp':
                    e.preventDefault();
                    focusPrevRow(row);
                    break;
                case 'a': case 'A':
                    e.preventDefault();
                    var btnA = row.querySelector('.rmbz-exc-c-btn-approve');
                    if (btnA) btnA.click();
                    break;
                case 'r': case 'R':
                    e.preventDefault();
                    var btnR = row.querySelector('.rmbz-exc-c-btn-reject');
                    if (btnR) btnR.click();
                    break;
                case 'c': case 'C':
                    e.preventDefault();
                    var btnC = row.querySelector('.rmbz-exc-c-btn-conflict');
                    if (btnC) btnC.click();
                    break;
                case ' ':
                    e.preventDefault();
                    togglePlay(row);
                    break;
                case 'Enter':
                    e.preventDefault();
                    expandRow(row);
                    break;
                case 'Escape':
                    var panel = row.querySelector('.rmbz-exc-c-decision-panel');
                    if (panel && !panel.hidden) {
                        hideDecisionPanel(row);
                    } else {
                        var detail = row.querySelector('.rmbz-exc-c-detail');
                        if (detail && !detail.hidden) {
                            expandRow(row); // fecha
                        }
                    }
                    break;
            }
        });

        // Foco na primeira linha quando a página carrega
        var firstRow = wrap.querySelector('.rmbz-exc-c-row');
        if (firstRow) setTimeout(function () { firstRow.focus(); }, 100);
    })();
    </script>
    <?php
}


/* ============================================================================
 * [FEAT 1.6.3] Logos SVG das plataformas — para pills dos serviços
 *
 * SVG inline = sempre nítido, ~200 bytes cada, herda cor via `currentColor`.
 * Cada logo simplificado: forma reconhecível mas glyph genérico para evitar
 * problemas de trademark (não copia exactamente o branding oficial).
 * ============================================================================ */
function rmbz_exc_platform_svg( $svc_key, $size = 14 ) {
    // Normalizar chaves curtas (usadas na Análise & Pesquisa) para longas
    $normalize = [
        'yt' => 'yt_content_id',
        'fb' => 'fb_monet',
        'tt' => 'tt_monet',
    ];
    if ( isset( $normalize[ $svc_key ] ) ) {
        $svc_key = $normalize[ $svc_key ];
    }
    $svgs = [
        // YouTube Content ID — rectângulo arredondado com play
        'yt_content_id' =>
            '<svg viewBox="0 0 24 24" width="' . $size . '" height="' . $size . '" fill="currentColor" aria-hidden="true">'
            . '<path d="M21.6 7.2c-.2-1.1-1.1-1.9-2.2-2.1C17.5 4.7 12 4.7 12 4.7s-5.5 0-7.4.4c-1.1.2-2 1-2.2 2.1C2 9.2 2 12 2 12s0 2.8.4 4.8c.2 1.1 1.1 1.9 2.2 2.1 1.9.4 7.4.4 7.4.4s5.5 0 7.4-.4c1.1-.2 2-1 2.2-2.1.4-2 .4-4.8.4-4.8s0-2.8-.4-4.8z"/>'
            . '<polygon points="10,15.5 15.5,12 10,8.5" fill="#fff"/>'
            . '</svg>',

        // Facebook / Instagram (combinado: "f" estilizado)
        'fb_monet' =>
            '<svg viewBox="0 0 24 24" width="' . $size . '" height="' . $size . '" fill="currentColor" aria-hidden="true">'
            . '<path d="M12 2C6.5 2 2 6.5 2 12c0 5 3.7 9.1 8.4 9.9v-7H7.9V12h2.5V9.8c0-2.5 1.5-3.9 3.8-3.9 1.1 0 2.2.2 2.2.2v2.5h-1.3c-1.2 0-1.6.8-1.6 1.6V12h2.8l-.4 2.9h-2.3v7C18.3 21.1 22 17 22 12c0-5.5-4.5-10-10-10z"/>'
            . '</svg>',

        // TikTok — nota musical estilizada (sem trademark)
        'tt_monet' =>
            '<svg viewBox="0 0 24 24" width="' . $size . '" height="' . $size . '" fill="currentColor" aria-hidden="true">'
            . '<path d="M16.6 5.8c-1.1-.7-1.9-1.9-2.1-3.3h-3.3v13.5c0 1.5-1.2 2.7-2.7 2.7s-2.7-1.2-2.7-2.7 1.2-2.7 2.7-2.7c.3 0 .6.1.9.2v-3.4c-.3-.1-.6-.1-.9-.1-3.3 0-6 2.7-6 6s2.7 6 6 6 6-2.7 6-6V9.4c1.3.9 2.9 1.5 4.5 1.5V7.6c-.9 0-1.7-.3-2.4-.8z"/>'
            . '</svg>',
    ];
    return $svgs[$svc_key] ?? '';
}
