<?php
// includes/admin/admin-distribution-releases.php
//
// Tabs "Lançamentos", "Fila de Aprovação" e vista de detalhe.
// Inclui acções server-side: aprovar, rejeitar, takedown, editar metadata,
// forçar mudança de status.

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

/* ============================================================================
 * HANDLER: ROUTING interno (lista vs detalhe)
 * ============================================================================ */
function rmbz_admin_render_releases_tab() {
    $view = isset($_GET['view']) ? sanitize_key($_GET['view']) : 'list';

    if ( $view === 'detail' && ! empty($_GET['id']) ) {
        rmbz_admin_render_release_detail( (int) $_GET['id'] );
    } else {
        rmbz_admin_render_releases_list();
    }
}

/* ============================================================================
 * TAB 1 — Lista de Lançamentos
 * ============================================================================ */
function rmbz_admin_render_releases_list() {
    global $wpdb;

    $t_releases = $wpdb->prefix . 'rmbz_distro_releases';
    $t_tracks   = $wpdb->prefix . 'rmbz_distro_tracks';
    $t_wallets  = $wpdb->prefix . 'rmbz_wallets';

    // Filtros
    $f_status = isset($_GET['f_status']) ? sanitize_key($_GET['f_status']) : '';
    $f_search = isset($_GET['f_search']) ? sanitize_text_field($_GET['f_search']) : '';
    $f_genre  = isset($_GET['f_genre'])  ? sanitize_text_field($_GET['f_genre']) : '';
    $f_from   = isset($_GET['f_from'])   ? sanitize_text_field($_GET['f_from']) : '';
    $f_to     = isset($_GET['f_to'])     ? sanitize_text_field($_GET['f_to']) : '';

    $orderby = isset($_GET['orderby']) ? sanitize_key($_GET['orderby']) : 'created_at';
    $order   = isset($_GET['order']) && $_GET['order'] === 'asc' ? 'ASC' : 'DESC';
    $allowed_order = ['id','title','status','created_at','release_date'];
    if ( ! in_array($orderby, $allowed_order, true) ) $orderby = 'created_at';

    $per_page = 25;
    $paged = max(1, (int) ($_GET['paged'] ?? 1));
    $offset = ($paged - 1) * $per_page;

    // Construir WHERE
    $where = ['1=1'];
    $params = [];
    if ( $f_status ) {
        $where[] = 'r.status = %s';
        $params[] = $f_status;
    }
    if ( $f_search ) {
        $where[] = '(r.title LIKE %s OR w.user_nome LIKE %s OR EXISTS (SELECT 1 FROM '.$t_tracks.' t WHERE t.release_id = r.id AND t.isrc_code LIKE %s))';
        $like = '%' . $wpdb->esc_like($f_search) . '%';
        $params[] = $like; $params[] = $like; $params[] = $like;
    }
    if ( $f_genre ) {
        $where[] = 'r.primary_genre = %s';
        $params[] = $f_genre;
    }
    if ( $f_from ) {
        $where[] = 'r.created_at >= %s';
        $params[] = $f_from . ' 00:00:00';
    }
    if ( $f_to ) {
        $where[] = 'r.created_at <= %s';
        $params[] = $f_to . ' 23:59:59';
    }
    $where_sql = implode(' AND ', $where);

    $sql_total = "SELECT COUNT(*) FROM $t_releases r LEFT JOIN $t_wallets w ON r.artist_telemovel = w.user_telemovel WHERE $where_sql";
    $total = $params ? (int) $wpdb->get_var( $wpdb->prepare($sql_total, $params) ) : (int) $wpdb->get_var($sql_total);

    $sql_list = "SELECT r.*, w.user_nome AS artist_name,
                        (SELECT COUNT(*) FROM $t_tracks t WHERE t.release_id = r.id) AS tracks_count
                 FROM $t_releases r
                 LEFT JOIN $t_wallets w ON r.artist_telemovel = w.user_telemovel
                 WHERE $where_sql
                 ORDER BY r.$orderby $order
                 LIMIT %d OFFSET %d";
    $params_list = array_merge($params, [$per_page, $offset]);
    $releases = $wpdb->get_results( $wpdb->prepare($sql_list, $params_list) );

    // Lista de géneros disponíveis (para filtro)
    $genres = $wpdb->get_col( "SELECT DISTINCT primary_genre FROM $t_releases WHERE primary_genre != '' ORDER BY primary_genre ASC" );

    $all_statuses = ['incomplete' => 'Incompleto', 'pendente' => 'Pendente', 'pending' => 'Pendente', 'submitted' => 'Submetido',
                     'returned' => 'Devolvido',
                     'live' => 'Live', 'distribuido' => 'Distribuído', 'rejected' => 'Rejeitado', 'rejeitado' => 'Rejeitado',
                     'takedown_requested' => 'Takedown pedido', 'taken_down' => 'Takedown feito'];

    // Cor semântica de cada estado (para o badge sobre a capa).
    $status_color = function( $st ) {
        $st = (string) $st;
        if ( in_array($st, ['live','distribuido'], true) )            return '#16a34a';
        if ( in_array($st, ['pendente','pending','submitted'], true) ) return '#d97706';
        if ( $st === 'returned' )                                      return '#dc2626';
        if ( in_array($st, ['rejected','rejeitado'], true) )          return '#b91c1c';
        if ( in_array($st, ['takedown_requested','taken_down'], true) ) return '#6b7280';
        if ( $st === 'incomplete' )                                    return '#9ca3af';
        return '#6356E5';
    };

    // [DESIGN 2.0] Modo de vista: galeria de capas (grid) ou tabela densa.
    // Persiste em user_meta para o admin não escolher sempre.
    $vm_meta = get_user_meta( get_current_user_id(), 'rmbz_releases_view_mode', true );
    $view_mode = isset($_GET['vm']) ? sanitize_key($_GET['vm']) : ( $vm_meta ?: 'grid' );
    if ( ! in_array($view_mode, ['grid','table'], true) ) $view_mode = 'grid';
    if ( isset($_GET['vm']) && $_GET['vm'] !== $vm_meta ) {
        update_user_meta( get_current_user_id(), 'rmbz_releases_view_mode', $view_mode );
    }
    $vm_base = remove_query_arg( 'vm', add_query_arg( null, null ) );

    ?>
    <form method="get" class="rmbz-filters">
        <input type="hidden" name="page" value="rmbz-admin-distribution">
        <input type="hidden" name="tab" value="releases">

        <div class="filter-group">
            <label>Pesquisar</label>
            <input type="text" name="f_search" value="<?php echo esc_attr($f_search); ?>" placeholder="Título, artista, ISRC..." style="min-width:220px;">
        </div>
        <div class="filter-group">
            <label>Status</label>
            <select name="f_status">
                <option value="">Todos</option>
                <?php foreach ( $all_statuses as $k => $v ): ?>
                    <option value="<?php echo esc_attr($k); ?>" <?php selected($f_status, $k); ?>><?php echo esc_html($v); ?></option>
                <?php endforeach; ?>
            </select>
        </div>
        <div class="filter-group">
            <label>Género</label>
            <select name="f_genre">
                <option value="">Todos</option>
                <?php foreach ( $genres as $g ): ?>
                    <option value="<?php echo esc_attr($g); ?>" <?php selected($f_genre, $g); ?>><?php echo esc_html($g); ?></option>
                <?php endforeach; ?>
            </select>
        </div>
        <div class="filter-group">
            <label>De</label>
            <input type="date" name="f_from" value="<?php echo esc_attr($f_from); ?>">
        </div>
        <div class="filter-group">
            <label>Até</label>
            <input type="date" name="f_to" value="<?php echo esc_attr($f_to); ?>">
        </div>
        <div class="filter-actions">
            <button type="submit" class="button button-primary">🔍 Filtrar</button>
            <a href="?page=rmbz-admin-distribution&tab=releases" class="button">Limpar</a>
        </div>
    </form>

    <div class="rmbz-rl-bar">
        <p class="rmbz-rl-count">
            <strong><?php echo $total; ?></strong> lançamento<?php echo $total === 1 ? '' : 's'; ?>
            <?php if ( $f_search || $f_status || $f_genre || $f_from || $f_to ): ?>
                · <a href="?page=rmbz-admin-distribution&tab=releases">mostrar todos</a>
            <?php endif; ?>
        </p>
        <div class="rmbz-rl-viewtoggle">
            <a href="<?php echo esc_url( add_query_arg('vm','grid',$vm_base) ); ?>" class="<?php echo $view_mode==='grid'?'is-active':''; ?>" title="Galeria de capas">▦ Galeria</a>
            <a href="<?php echo esc_url( add_query_arg('vm','table',$vm_base) ); ?>" class="<?php echo $view_mode==='table'?'is-active':''; ?>" title="Tabela compacta">☰ Tabela</a>
        </div>
    </div>

    <?php if ( empty($releases) ): ?>
        <div class="rmbz-rl-empty">
            <span class="rmbz-rl-empty-ico">🎵</span>
            <p>Nenhum lançamento encontrado<?php echo ( $f_search || $f_status || $f_genre ) ? ' com estes filtros.' : '.'; ?></p>
        </div>
    <?php elseif ( $view_mode === 'grid' ): ?>

        <div class="rmbz-rl-grid">
            <?php foreach ( $releases as $i => $r ):
                $st_color = $status_color( $r->status );
                $st_label = $all_statuses[$r->status] ?? $r->status;
                $detail_url = '?page=rmbz-admin-distribution&tab=releases&view=detail&id=' . (int) $r->id;
            ?>
                <a class="rmbz-rl-card" href="<?php echo esc_attr($detail_url); ?>" style="animation-delay: <?php echo ($i % 12) * 35; ?>ms;">
                    <span class="rmbz-rl-cover">
                        <?php if ( ! empty($r->cover_image) ): ?>
                            <img src="<?php echo esc_url($r->cover_image); ?>" alt="" loading="lazy">
                        <?php else: ?>
                            <span class="rmbz-rl-cover-empty">🎵</span>
                        <?php endif; ?>
                        <span class="rmbz-rl-status" style="background: <?php echo $st_color; ?>;"><?php echo esc_html($st_label); ?></span>
                        <span class="rmbz-rl-play">▸ Ver detalhe</span>
                    </span>
                    <span class="rmbz-rl-body">
                        <span class="rmbz-rl-title" title="<?php echo esc_attr($r->title); ?>"><?php echo esc_html($r->title ?: '(sem título)'); ?></span>
                        <span class="rmbz-rl-artist"><?php echo esc_html($r->artist_name ?: '—'); ?></span>
                        <span class="rmbz-rl-meta">
                            <?php echo (int) $r->tracks_count; ?> faixa<?php echo (int)$r->tracks_count === 1 ? '' : 's'; ?>
                            <?php if ( $r->primary_genre ): ?> · <?php echo esc_html($r->primary_genre); ?><?php endif; ?>
                            <?php if ( $r->release_date ): ?> · <?php echo esc_html( date('Y', strtotime($r->release_date)) ); ?><?php endif; ?>
                        </span>
                    </span>
                </a>
            <?php endforeach; ?>
        </div>

    <?php else: ?>

    <div class="rmbz-table-wrap">
        <table class="rmbz-table">
            <thead>
                <tr>
                    <th style="width:40px;">Capa</th>
                    <th><?php echo rmbz_sort_link('Título', 'title', $orderby, $order); ?></th>
                    <th>Artista</th>
                    <th>Género</th>
                    <th>Faixas</th>
                    <th><?php echo rmbz_sort_link('Data lanç.', 'release_date', $orderby, $order); ?></th>
                    <th>Status</th>
                    <th style="width:140px;">Acções</th>
                </tr>
            </thead>
            <tbody>
                <?php foreach ( $releases as $r ): ?>
                    <tr>
                        <td>
                            <?php if ( ! empty($r->cover_image) ): ?>
                                <img src="<?php echo esc_url($r->cover_image); ?>" class="mini-cover">
                            <?php else: ?>
                                <div class="placeholder-cover">🎵</div>
                            <?php endif; ?>
                        </td>
                        <td>
                            <a href="?page=rmbz-admin-distribution&tab=releases&view=detail&id=<?php echo (int) $r->id; ?>" style="font-weight:600; text-decoration:none;">
                                <?php echo esc_html($r->title ?: '(sem título)'); ?>
                            </a>
                            <div style="font-size:11px; color:var(--rmbz-text-faint, #888);">#<?php echo (int) $r->id; ?></div>
                        </td>
                        <td><?php echo esc_html($r->artist_name ?: '—'); ?></td>
                        <td><?php echo esc_html($r->primary_genre ?: '—'); ?></td>
                        <td><?php echo (int) $r->tracks_count; ?></td>
                        <td><?php echo $r->release_date ? esc_html( date('d/m/Y', strtotime($r->release_date)) ) : '—'; ?></td>
                        <td><span class="rmbz-status-pill rmbz-status-<?php echo esc_attr($r->status); ?>"><?php echo esc_html( $all_statuses[$r->status] ?? $r->status ); ?></span></td>
                        <td>
                            <a href="?page=rmbz-admin-distribution&tab=releases&view=detail&id=<?php echo (int) $r->id; ?>" class="button button-small">Ver</a>
                        </td>
                    </tr>
                <?php endforeach; ?>
            </tbody>
        </table>
    </div>

    <?php endif; ?>

    <?php
    $total_pages = (int) ceil( $total / $per_page );
    if ( $total_pages > 1 ) {
        echo '<div class="tablenav" style="margin-top:15px;"><div class="tablenav-pages">';
        $base = add_query_arg( array_diff_key($_GET, ['paged'=>1]), '?' );
        echo paginate_links([
            'base'    => $base . '%_%',
            'format'  => '&paged=%#%',
            'current' => $paged,
            'total'   => $total_pages,
            'prev_text' => '‹ anterior',
            'next_text' => 'próxima ›',
        ]);
        echo '</div></div>';
    }
    ?>
    <style>
    /* ════════ LANÇAMENTOS — barra + galeria de capas ════════ */
    .rmbz-rl-bar { display: flex; align-items: center; justify-content: space-between; gap: 14px; margin: 4px 0 14px; flex-wrap: wrap; }
    .rmbz-rl-count { margin: 0; font-size: 13px; color: #6b7280; }
    .rmbz-rl-count strong { color: #16181d; }
    .rmbz-rl-viewtoggle { display: inline-flex; background: #eef0f3; border-radius: 10px; padding: 3px; gap: 2px; }
    .rmbz-rl-viewtoggle a {
        text-decoration: none; font-size: 12px; font-weight: 700; color: #6b7280;
        padding: 5px 12px; border-radius: 8px; transition: all .15s cubic-bezier(.4,0,.2,1);
    }
    .rmbz-rl-viewtoggle a:hover { color: #16181d; }
    .rmbz-rl-viewtoggle a.is-active { background: #fff; color: #6356E5; box-shadow: 0 1px 3px rgba(16,24,40,.1); }

    .rmbz-rl-grid {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
        gap: 16px;
    }
    .rmbz-rl-card {
        display: flex; flex-direction: column; text-decoration: none;
        background: #fff; border: 1px solid #e6e8eb; border-radius: 16px; overflow: hidden;
        box-shadow: 0 1px 3px rgba(16,24,40,.05);
        animation: rmbz-rl-rise .45s cubic-bezier(.4,0,.2,1) both;
        transition: transform .2s cubic-bezier(.4,0,.2,1), box-shadow .2s cubic-bezier(.4,0,.2,1), border-color .2s;
    }
    @keyframes rmbz-rl-rise { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
    .rmbz-rl-card:hover { transform: translateY(-4px); box-shadow: 0 16px 34px rgba(16,24,40,.14); border-color: #d6d9de; }

    .rmbz-rl-cover { position: relative; display: block; aspect-ratio: 1/1; background: #f1f3f5; overflow: hidden; }
    .rmbz-rl-cover img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .35s cubic-bezier(.4,0,.2,1); }
    .rmbz-rl-card:hover .rmbz-rl-cover img { transform: scale(1.06); }
    .rmbz-rl-cover-empty { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 44px; color: #c2c7cf; }
    .rmbz-rl-status {
        position: absolute; top: 9px; left: 9px; z-index: 2;
        color: #fff; font-size: 10px; font-weight: 800; letter-spacing: .02em;
        padding: 3px 9px; border-radius: 999px; box-shadow: 0 2px 6px rgba(0,0,0,.22);
        backdrop-filter: saturate(1.2);
    }
    .rmbz-rl-play {
        position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
        padding: 18px 12px 10px; color: #fff; font-size: 12px; font-weight: 700;
        background: linear-gradient(to top, rgba(0,0,0,.62), transparent);
        opacity: 0; transform: translateY(6px); transition: opacity .2s, transform .2s;
    }
    .rmbz-rl-card:hover .rmbz-rl-play { opacity: 1; transform: none; }

    .rmbz-rl-body { display: flex; flex-direction: column; gap: 1px; padding: 11px 13px 13px; min-width: 0; }
    .rmbz-rl-title { font-size: 13.5px; font-weight: 800; color: #16181d; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .rmbz-rl-artist { font-size: 12px; color: #4b5563; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
    .rmbz-rl-meta { font-size: 11px; color: #9aa1ad; margin-top: 4px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

    .rmbz-rl-empty { text-align: center; padding: 50px 20px; color: #9aa1ad; background: #fff; border: 1px solid #e6e8eb; border-radius: 16px; }
    .rmbz-rl-empty-ico { font-size: 34px; opacity: .55; display: block; margin-bottom: 8px; }
    .rmbz-rl-empty p { margin: 0; font-size: 14px; }
    </style>
    <?php
}

function rmbz_sort_link( $label, $col, $current_orderby, $current_order ) {
    $new_order = ($current_orderby === $col && $current_order === 'ASC') ? 'desc' : 'asc';
    $arrow = '';
    if ( $current_orderby === $col ) {
        $arrow = $current_order === 'ASC' ? ' ▲' : ' ▼';
    }
    $args = array_merge($_GET, ['orderby' => $col, 'order' => $new_order]);
    $url = '?' . http_build_query($args);
    return '<a href="' . esc_url($url) . '" style="text-decoration:none; color:inherit;">' . esc_html($label) . $arrow . '</a>';
}

/* ============================================================================
 * TAB 1b — Detalhe do Lançamento
 * ============================================================================ */
function rmbz_admin_render_release_detail( $release_id ) {
    global $wpdb;

    $t_releases  = $wpdb->prefix . 'rmbz_distro_releases';
    $t_tracks    = $wpdb->prefix . 'rmbz_distro_tracks';
    $t_wallets   = $wpdb->prefix . 'rmbz_wallets';
    $t_history   = $wpdb->prefix . 'rmbz_distro_status_history';
    $t_splits    = $wpdb->prefix . 'rmbz_track_splits';

    $release = $wpdb->get_row( $wpdb->prepare(
        "SELECT r.*, w.user_nome AS artist_name, w.user_telemovel AS artist_tel
         FROM $t_releases r
         LEFT JOIN $t_wallets w ON r.artist_telemovel = w.user_telemovel
         WHERE r.id = %d",
        $release_id
    ) );

    if ( ! $release ) {
        echo '<div class="notice notice-error"><p>Lançamento #' . (int) $release_id . ' não encontrado.</p></div>';
        echo '<a href="?page=rmbz-admin-distribution&tab=releases" class="button">← Voltar à lista</a>';
        return;
    }

    $tracks = $wpdb->get_results( $wpdb->prepare(
        "SELECT * FROM $t_tracks WHERE release_id = %d ORDER BY track_order ASC, id ASC",
        $release_id
    ) ) ?: [];

    // [1.5.191] Calcular resumo de saúde dos relatórios da release
    //
    // Para cada faixa: olha last_seen_in_csv (NULL se nunca recebeu).
    // Resumo da release:
    //   - reporting_oldest_date: data mais antiga entre as faixas (a "saúde"
    //     da release é determinada pela faixa que está há mais tempo sem
    //     reportar — qualquer atraso é problema)
    //   - reporting_newest_date: data mais recente (último import a tocar
    //     em alguma faixa)
    //   - reporting_total_tracks: total de faixas
    //   - reporting_with_data: quantas tiveram pelo menos um relatório
    //   - reporting_never: quantas nunca receberam
    //
    // [1.5.209] Estado intermédio: faixas com matches PENDENTES em "Matches a
    // Rever". Quando o ISRC do CSV não bate com o registado, os dados vão
    // para match_review em vez de daily_stats. Card mostrava "Nunca reportou"
    // mesmo com dados existentes — UX confusa. Agora detectamos:
    //   - pending_matches: count de linhas em match_review pending para esta release
    //   - pending_matches_amount: $ total pendente
    $reporting_summary = [
        'oldest_date'           => null,
        'newest_date'           => null,
        'total'                 => count($tracks),
        'with_data'             => 0,
        'never'                 => 0,
        'pending_matches'       => 0,
        'pending_matches_amount'=> 0.0,
    ];
    foreach ( $tracks as $tk ) {
        if ( ! empty( $tk->last_seen_in_csv ) ) {
            $reporting_summary['with_data']++;
            if ( $reporting_summary['oldest_date'] === null || $tk->last_seen_in_csv < $reporting_summary['oldest_date'] ) {
                $reporting_summary['oldest_date'] = $tk->last_seen_in_csv;
            }
            if ( $reporting_summary['newest_date'] === null || $tk->last_seen_in_csv > $reporting_summary['newest_date'] ) {
                $reporting_summary['newest_date'] = $tk->last_seen_in_csv;
            }
        } else {
            $reporting_summary['never']++;
        }
    }

    // [1.5.209] Detectar matches pendentes em match_review que sugerem tracks
    // desta release (qualquer matching: por suggested_release_id directo OU
    // por csv_isrc batendo com isrc de track da release).
    $t_match_review = $wpdb->prefix . 'rmbz_distro_match_review';
    if ( $wpdb->get_var("SHOW TABLES LIKE '$t_match_review'") === $t_match_review && ! empty($tracks) ) {
        // ISRCs das tracks desta release (normalizados — sem hífens, uppercase)
        $release_isrcs = [];
        foreach ( $tracks as $tk ) {
            if ( ! empty( $tk->isrc_code ) ) {
                $release_isrcs[] = strtoupper( preg_replace('/[^A-Z0-9]/i', '', $tk->isrc_code) );
            }
        }

        $isrc_clause = '';
        $params = [ $release_id ];
        if ( ! empty( $release_isrcs ) ) {
            $isrc_placeholders = implode(',', array_fill(0, count($release_isrcs), '%s'));
            $isrc_clause = " OR UPPER(REPLACE(mr.csv_isrc, '-', '')) IN ($isrc_placeholders)";
            $params = array_merge( $params, $release_isrcs );
        }

        $pending_data = $wpdb->get_row( $wpdb->prepare(
            "SELECT COUNT(*) AS cnt, COALESCE(SUM(mr.csv_amount_usd), 0) AS total
             FROM $t_match_review mr
             WHERE mr.status = 'pending'
               AND ( mr.suggested_release_id = %d $isrc_clause )",
            $params
        ) );

        if ( $pending_data ) {
            $reporting_summary['pending_matches']        = (int) $pending_data->cnt;
            $reporting_summary['pending_matches_amount'] = (float) $pending_data->total;
        }
    }

    $platforms = function_exists('rmbz_distro_get_platforms') ? rmbz_distro_get_platforms($release_id) : null;

    $history = [];
    if ( $wpdb->get_var("SHOW TABLES LIKE '$t_history'") === $t_history ) {
        $history = $wpdb->get_results( $wpdb->prepare(
            "SELECT * FROM $t_history WHERE release_id = %d ORDER BY created_at DESC",
            $release_id
        ) ) ?: [];
    }

    // Mensagens de sucesso
    if ( ! empty($_GET['msg']) ) {
        $msgs = [
            'approved'    => ['success', '✓ Lançamento aprovado. Próximo passo: marcar como Entregue aos DSPs.'],
            'delivered'   => ['success', '🚀 Marcado como Entregue aos DSPs. Quando aparecer nas lojas, marcar como Ao Vivo.'],
            'live'        => ['success', '🎉 Lançamento marcado como Ao Vivo. Cola os links de cada loja no bloco abaixo.'],
            'links_saved' => ['success', '✓ Links das lojas guardados' . ( isset($_GET['n']) ? ' (' . (int) $_GET['n'] . ' exacto' . ((int)$_GET['n'] === 1 ? '' : 's') . ').' : '.' )],
            'dsps_saved'  => ['success', '✓ Selecção de lojas actualizada. Alteração registada no histórico.'],
            'dsps_error'  => ['error',   '✗ Tens de seleccionar pelo menos uma loja.'],
            'upc_saved'   => ['success', '✓ UPC actualizado. Alteração registada no histórico.'],
            'upc_empty'   => ['error',   '✗ Preenche o UPC ou usa "Gerar automático".'],
            'upc_invalid' => ['error',   '✗ UPC inválido. Deve ter 12 ou 13 dígitos com checksum GS1 válido.'],
            'upc_dup'     => ['error',   '✗ Este UPC já está em uso por outro release' . ( isset($_GET['dup_id']) ? ' (ID ' . (int) $_GET['dup_id'] . ').' : '.' )],
            'upc_locked'  => ['error',   '✗ Este release já está publicado — o UPC não pode ser alterado.'],
            'upc_error'   => ['error',   '✗ Erro ao processar o UPC. Tenta novamente.'],
            'split_added'    => ['success', '✓ Split adicionado. Alteração registada no audit log.'],
            'split_saved'    => ['success', '✓ Split actualizado.'],
            'split_deleted'  => ['warning', '🗑 Split removido.'],
            'split_invalid'  => ['error',   '✗ Dados inválidos. Verifica nome e percentagem (0.01–100).'],
            'split_overflow' => ['error',   '✗ A soma total dos splits ultrapassaria 100%. Ajusta os existentes primeiro.'],
            'rejected'    => ['warning', '✗ Lançamento rejeitado. O artista foi notificado.'],
            'returned'    => ['warning', '⟲ Lançamento devolvido ao artista para correcção.'],
            'takedown'    => ['warning', '🗑 Takedown solicitado. O lançamento será removido dos DSPs.'],
            'takedown_finalized' => ['success', '🚫 Takedown finalizado. O artista foi notificado e o release está marcado como removido.'],
            'takedown_cancelled' => ['success', '⟲ Pedido de takedown cancelado. O release continua nas lojas e o artista foi notificado.'],
            'takedown_invalid_state' => ['error', '✗ Estado inválido — esta acção só é possível em releases com pedido de takedown pendente.'],
            'updated'     => ['success', '✓ Metadata actualizada.'],
        ];
        if ( isset($msgs[$_GET['msg']]) ) {
            list($type, $txt) = $msgs[$_GET['msg']];
            echo '<div class="notice notice-' . esc_attr($type) . ' is-dismissible"><p>' . esc_html($txt) . '</p></div>';
        }
    }

    $status_label = ucfirst( $release->status );
    $is_pending = in_array( $release->status, ['pendente','pending','submitted'], true );
    $is_live    = in_array( $release->status, ['live','distribuido'], true );
    // Estados intermédios do workflow de 3 passos — Aprovado → Entregue → Ao Vivo.
    // Antes desta versão, um release em `approved` ou `delivered` não mostrava
    // qualquer botão (bug), porque só o pendente tinha UI de acções.
    $is_in_workflow = in_array( $release->status, ['approved','delivered'], true );
    ?>

    <?php rmbz_distro_modern_styles(); ?>

    <div class="rmbz-rd2">
    <div style="margin-bottom:15px; display:flex; gap:8px; align-items:center; flex-wrap:wrap;">
        <a href="?page=rmbz-admin-distribution&tab=releases" class="button">← Voltar à lista</a>

        <?php
        // [1.5.196] Botão "Editar como artista (modo admin)" — abre o wizard
        // com bypass do gate de status (válido para tudo excepto live/distribuido).
        // Permite ao admin fazer alterações grandes (faixas, áudio, capa, splits)
        // que seriam complexas via inline edit no detalhe.
        $admin_editable = ! in_array( $release->status, [ 'live', 'distribuido', 'takedown_requested' ], true );

        // Descobrir a URL da página que tem o shortcode [1mz_distribution_dashboard].
        // Cache em transient para não fazer query repetida (raramente muda).
        $wizard_base_url = get_transient( 'rmbz_distro_dashboard_page_url' );
        if ( $wizard_base_url === false ) {
            global $wpdb;
            $page_id = (int) $wpdb->get_var(
                "SELECT ID FROM {$wpdb->posts}
                 WHERE post_status = 'publish' AND post_type = 'page'
                   AND post_content LIKE '%[1mz_distribution_dashboard%'
                 LIMIT 1"
            );
            $wizard_base_url = $page_id ? get_permalink( $page_id ) : '';
            set_transient( 'rmbz_distro_dashboard_page_url', $wizard_base_url, HOUR_IN_SECONDS );
        }

        if ( $admin_editable && ! empty( $wizard_base_url ) ):
            $wizard_url = add_query_arg( [
                'distro_action' => 'edit_release',
                'id'            => (int) $release->id,
            ], $wizard_base_url );
        ?>
            <a href="<?php echo esc_url( $wizard_url ); ?>"
               target="_blank"
               class="button button-primary"
               style="background:#dba617; border-color:#bf8a10; color:var(--wp-components-color-foreground, #1d2327);"
               title="Abre o wizard do artista em modo admin — funcional em qualquer status excepto live/distribuido">
                ✏️ Editar como artista (modo admin) ↗
            </a>
        <?php elseif ( ! $admin_editable ): ?>
            <span class="button" disabled
                  title="Lançamento nas lojas — usa takedown primeiro"
                  style="opacity:0.5; cursor:not-allowed;">
                🔒 Editar bloqueado
            </span>
        <?php else: ?>
            <span class="button" disabled
                  title="Página do dashboard distribution não encontrada — verifica configuração da página com shortcode [1mz_distribution_dashboard]"
                  style="opacity:0.5; cursor:not-allowed;">
                ⚠ Edição via wizard indisponível
            </span>
        <?php endif; ?>
    </div>

    <div style="display: grid; grid-template-columns: 280px 1fr; gap: 20px; align-items: start;">

        <div class="rmbz-section rmbz-rel-sticky-col" style="margin:0; padding:16px;">
            <?php if ( ! empty($release->cover_image) ):
                // [FEAT 1.6.22] Tentar obter dimensões + tamanho da capa.
                // Se for URL local, usa getimagesize + filesize. Se for URL
                // remota, faz uma chamada HEAD para tamanho (rápido) e tenta
                // getimagesize (pode ser lento — fallback silencioso).
                $cover_dims = '';
                $cover_size = '';
                $cover_filename = basename( parse_url($release->cover_image, PHP_URL_PATH) );
                $local_path = '';
                $upload_dir = wp_get_upload_dir();
                if ( strpos($release->cover_image, $upload_dir['baseurl']) === 0 ) {
                    $local_path = str_replace($upload_dir['baseurl'], $upload_dir['basedir'], $release->cover_image);
                }
                if ( $local_path && file_exists($local_path) ) {
                    $sz = @getimagesize($local_path);
                    if ( $sz ) $cover_dims = $sz[0] . '×' . $sz[1];
                    $fb = @filesize($local_path);
                    if ( $fb ) $cover_size = $fb >= 1048576
                        ? number_format($fb/1048576, 1) . ' MB'
                        : number_format($fb/1024, 0) . ' KB';
                }
            ?>
                <a href="<?php echo esc_url($release->cover_image); ?>" target="_blank" rel="noopener" title="Abrir em tamanho real">
                    <img src="<?php echo esc_url($release->cover_image); ?>" style="width:100%; border-radius:6px; display:block; margin-bottom:8px;">
                </a>
                <div style="display:flex; justify-content:space-between; align-items:center; gap:8px; margin-bottom:15px; font-size:11px;">
                    <span style="color:var(--rmbz-text-muted, #666); font-family:ui-monospace,monospace;">
                        <?php if ( $cover_dims ): ?>
                            <strong><?php echo esc_html($cover_dims); ?></strong>
                        <?php endif; ?>
                        <?php if ( $cover_size ): ?>
                            <?php echo $cover_dims ? ' · ' : ''; ?><?php echo esc_html($cover_size); ?>
                        <?php endif; ?>
                    </span>
                    <a href="<?php echo esc_url($release->cover_image); ?>"
                       download="<?php echo esc_attr($cover_filename ?: 'capa.jpg'); ?>"
                       class="button button-small"
                       title="Baixar capa para o teu computador"
                       style="font-size:11px; padding:2px 9px; height:auto; line-height:1.5;">
                        ⬇ Baixar
                    </a>
                </div>
            <?php else: ?>
                <div style="width:100%; aspect-ratio:1/1; background:#eee; border-radius:6px; display:flex; align-items:center; justify-content:center; font-size:48px; color:var(--rmbz-text-faint, #aaa); margin-bottom:15px;">🎵</div>
            <?php endif; ?>

            <?php
            // [1.5.196] Título editável inline (campo: title)
            $release_locked = in_array( $release->status, ['live','distribuido'], true );
            $title_nonce = wp_create_nonce( 'rmbz_release_field_save_' . (int) $release->id );
            ?>
            <h2 style="font-size:20px; margin:0 0 4px 0;">
                <span class="rmbz-rel-edit-wrap"
                      data-release-id="<?php echo (int) $release->id; ?>"
                      data-field="title"
                      data-locked="<?php echo $release_locked ? '1' : '0'; ?>"
                      data-nonce="<?php echo esc_attr( $title_nonce ); ?>">
                    <span class="rmbz-rel-display"
                          title="<?php echo $release_locked ? 'Bloqueado: nas lojas' : 'Click para editar título'; ?>"
                          style="<?php echo $release_locked ? 'cursor:not-allowed;' : 'cursor:pointer;'; ?>">
                        <?php echo esc_html($release->title ?: '(sem título)'); ?><?php if ( ! $release_locked ): ?> <span style="font-size:12px; opacity:0.4;">✏️</span><?php endif; ?>
                    </span>
                    <?php if ( ! $release_locked ): ?>
                        <input type="text" class="rmbz-rel-input" maxlength="200"
                               value="<?php echo esc_attr( $release->title ?? '' ); ?>"
                               style="display:none; font-size:20px; padding:4px 8px; border-radius:4px; border:1px solid var(--wp-admin-theme-color, #2271b1); outline:none; width:100%; box-sizing:border-box;">
                        <span class="rmbz-rel-status" style="display:none; font-size:11px;"></span>
                    <?php endif; ?>
                </span>
            </h2>
            <p style="color:var(--rmbz-text-muted, #666); margin:0 0 10px 0;">por <strong><?php echo esc_html($release->artist_name ?: '—'); ?></strong></p>

            <p style="margin:5px 0;"><strong>Status:</strong> <span class="rmbz-status-pill rmbz-status-<?php echo esc_attr($release->status); ?>"><?php echo esc_html($status_label); ?></span></p>
            <p style="margin:5px 0; font-size:12px; color:var(--rmbz-text-faint, #888);">ID: #<?php echo (int) $release->id; ?></p>
            <p style="margin:5px 0; font-size:12px; color:var(--rmbz-text-faint, #888);">Criado: <?php echo esc_html( date('d/m/Y H:i', strtotime($release->created_at)) ); ?></p>

            <hr>

            <?php if ( $is_pending ): ?>
                <strong style="display:block; margin-bottom:8px;">Acções:</strong>

                <?php
                // Calcular checklist automático
                $auto_checks = rmbz_admin_compute_review_checklist( $release, $tracks );
                $auto_all_pass = true;
                foreach ( $auto_checks as $c ) if ( ! $c['pass'] ) { $auto_all_pass = false; break; }
                ?>

                <div class="rmbz-review-checklist">
                    <strong>📋 Checklist de revisão</strong>
                    <?php
                    // [FEAT 1.6.22] Contadores no header — admin vê de relance
                    // quantas verificações já passaram vs quantas faltam corrigir.
                    $auto_total = count($auto_checks);
                    $auto_pass  = 0;
                    $auto_fails = [];
                    foreach ( $auto_checks as $c ) {
                        if ( $c['pass'] ) $auto_pass++;
                        else $auto_fails[] = $c;
                    }
                    $fail_count = count($auto_fails);
                    ?>
                    <div class="rmbz-check-progress <?php echo $fail_count > 0 ? 'has-fails' : 'all-ok'; ?>">
                        <?php if ( $fail_count > 0 ): ?>
                            <span class="rmbz-check-progress-icon">⚠</span>
                            <strong><?php echo $fail_count; ?> falha<?php echo $fail_count === 1 ? '' : 's'; ?> automática<?php echo $fail_count === 1 ? '' : 's'; ?></strong>
                            <span class="rmbz-check-progress-stat"><?php echo $auto_pass; ?>/<?php echo $auto_total; ?> OK</span>
                        <?php else: ?>
                            <span class="rmbz-check-progress-icon">✓</span>
                            <strong>Verificações automáticas OK</strong>
                            <span class="rmbz-check-progress-stat"><?php echo $auto_total; ?>/<?php echo $auto_total; ?></span>
                        <?php endif; ?>
                    </div>

                    <?php if ( $fail_count > 0 ): ?>
                        <div class="rmbz-checklist-fails">
                            <div class="rmbz-checklist-head rmbz-fail-head">A corrigir antes de aprovar</div>
                            <?php foreach ( $auto_fails as $c ): ?>
                                <div class="rmbz-check fail prominent">
                                    <span class="ico">✗</span>
                                    <span class="txt"><?php echo esc_html($c['label']); ?></span>
                                </div>
                            <?php endforeach; ?>
                        </div>
                    <?php endif; ?>

                    <div class="rmbz-checklist-auto">
                        <div class="rmbz-checklist-head">Verificação automática</div>
                        <?php foreach ( $auto_checks as $c ):
                            // Já mostrámos os fails em cima — aqui só os pass
                            // (para evitar duplicação visual).
                            if ( ! $c['pass'] && $fail_count > 0 ) continue;
                        ?>
                            <div class="rmbz-check <?php echo $c['pass'] ? 'pass' : 'fail'; ?>">
                                <span class="ico"><?php echo $c['pass'] ? '✓' : '✗'; ?></span>
                                <span class="txt"><?php echo esc_html($c['label']); ?></span>
                            </div>
                        <?php endforeach; ?>
                    </div>
                    <div class="rmbz-checklist-manual">
                        <div class="rmbz-checklist-head">Verificação manual</div>
                        <label><input type="checkbox" class="rmbz-manual-check" data-k="listened"> Escutei todas as faixas</label>
                        <label><input type="checkbox" class="rmbz-manual-check" data-k="cover"> Capa não tem logos de terceiros</label>
                        <label><input type="checkbox" class="rmbz-manual-check" data-k="metadata"> Metadata está correcta</label>
                        <label><input type="checkbox" class="rmbz-manual-check" data-k="rights"> Sem problemas de direitos</label>
                    </div>
                </div>

                <?php
                // Painel de flags heurísticas (fraud detection).
                // NÃO bloqueia aprovação — só alerta o revisor.
                if ( function_exists('rmbz_fraud_render_flags_panel') ) {
                    rmbz_fraud_render_flags_panel( $release, $tracks );
                }
                ?>

                <form method="post" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" style="margin:10px 0;">
                    <?php wp_nonce_field('rmbz_release_action_' . $release->id); ?>
                    <input type="hidden" name="action" value="rmbz_release_approve">
                    <input type="hidden" name="release_id" value="<?php echo (int) $release->id; ?>">
                    <?php
                    // NOVA UI: workflow em 3 passos (Aprovar → Entregue → Ao Vivo).
                    // O antigo botão único "Aprovar e marcar LIVE" saltava etapas
                    // e tornava inútil o tracker de 5 passos do artista.
                    //
                    // O gate dos checks manuais (requer $auto_all_pass e checks
                    // manuais) só se aplica ao primeiro passo (Aprovar). Os
                    // passos 2 e 3 (Entregue, Ao Vivo) já são decisões admin
                    // sem gate — a função rmbz_admin_render_workflow_buttons
                    // decide qual mostrar consoante $release->status.
                    if ( function_exists('rmbz_admin_render_workflow_buttons') ) {
                        // Se o primeiro passo ainda está disponível e há falhas
                        // automáticas, mostramos antes o aviso bloqueador.
                        $show_blocker = ! $auto_all_pass && in_array(
                            $release->status,
                            ['pendente','pending','submitted','returned'],
                            true
                        );
                        if ( $show_blocker ) {
                            echo '<div style="padding:10px; background:#fff3cd; border-left:3px solid #e74c3c; border-radius:4px; color:#856404; font-size:13px; margin-bottom:8px;">⚠ Resolve as falhas automáticas antes de aprovar.</div>';
                        } else {
                            // Check manual gate (só relevante no primeiro passo)
                            $first_step_available = in_array(
                                $release->status,
                                ['pendente','pending','submitted','returned'],
                                true
                            );
                            if ( $first_step_available ) {
                                echo '<div id="rmbz-approve-hint" style="padding:8px; background:#f6f7f7; border-radius:4px; color:var(--rmbz-text-muted, #666); font-size:12px; text-align:center; margin-bottom:8px;">Marca todos os checks manuais acima para desbloquear a aprovação</div>';
                            }
                            rmbz_admin_render_workflow_buttons( $release );
                        }
                    } else {
                        // Fallback: se o ficheiro de workflow não carregou, manter botão antigo
                        ?>
                        <button type="submit" class="button button-primary" id="rmbz-approve-btn" style="width:100%;"
                                <?php echo $auto_all_pass ? '' : 'disabled'; ?>
                                onclick="return confirm('Aprovar este lançamento? Será marcado como LIVE.');">
                            ✓ Aprovar e marcar LIVE
                        </button>
                        <?php if ( ! $auto_all_pass ): ?>
                            <small style="display:block; text-align:center; color:var(--rmbz-danger, #ef4444); margin-top:4px;">
                                ⚠ Resolve as falhas automáticas primeiro
                            </small>
                        <?php else: ?>
                            <small style="display:block; text-align:center; color:var(--rmbz-text-muted, #666); margin-top:4px;" id="rmbz-approve-hint">
                                Marca todos os checks manuais para desbloquear
                            </small>
                        <?php endif;
                    }
                    ?>
                </form>

                <?php
                // Editor de links DSP (aparece quando o release está delivered/live)
                if ( function_exists('rmbz_admin_render_dsp_links_editor') ) {
                    rmbz_admin_render_dsp_links_editor( $release );
                }
                ?>

                <button type="button" class="button" style="width:100%; margin-bottom:8px; border-color:var(--rmbz-danger-strong, #b91c1c); color:var(--rmbz-danger-strong, #b91c1c);"
                        onclick="document.getElementById('rmbz-return-form').style.display='block'; document.getElementById('rmbz-reject-form').style.display='none';">
                    ⟲ Devolver para correcção
                </button>

                <?php if ( function_exists('rmbz_admin_render_return_form') ) rmbz_admin_render_return_form( $release->id, 'detail' ); ?>

                <button type="button" class="button" style="width:100%; margin-bottom:8px;"
                        onclick="document.getElementById('rmbz-reject-form').style.display='block'; document.getElementById('rmbz-return-form').style.display='none';">
                    ✗ Rejeitar definitivamente
                </button>

                <form method="post" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>"
                      id="rmbz-reject-form" style="display:none; margin-top:10px; padding:10px; background:#fff3cd; border-radius:4px;">
                    <?php wp_nonce_field('rmbz_release_action_' . $release->id); ?>
                    <input type="hidden" name="action" value="rmbz_release_reject">
                    <input type="hidden" name="release_id" value="<?php echo (int) $release->id; ?>">
                    <p style="font-size:12px; color:var(--rmbz-text-muted, #666); margin:0 0 8px 0;">
                        Use <strong>Rejeitar</strong> apenas para problemas graves ou irrecuperáveis.
                        Para problemas normais, prefere <strong>Devolver</strong>.
                    </p>
                    <label style="font-size:11px; font-weight:600;">Motivo:</label>
                    <select name="reject_code" required style="width:100%; margin:4px 0;">
                        <option value="">— Escolher —</option>
                        <option value="low_quality_audio">Áudio com qualidade insuficiente</option>
                        <option value="low_quality_cover">Capa com resolução/qualidade insuficiente</option>
                        <option value="metadata_incomplete">Metadata incompleta</option>
                        <option value="copyright_concern">Possível violação de direitos autorais</option>
                        <option value="explicit_not_flagged">Conteúdo explícito não declarado</option>
                        <option value="duplicate">Duplicado de lançamento anterior</option>
                        <option value="cover_third_party_logo">Capa contém logo de terceiros</option>
                        <option value="other">Outro motivo</option>
                    </select>
                    <textarea name="reject_note" rows="3" placeholder="Nota adicional (opcional)..." style="width:100%;"></textarea>
                    <button type="submit" class="button button-primary" style="width:100%; margin-top:6px;">Confirmar rejeição</button>
                </form>

                <script>
                (function() {
                    var btn = document.getElementById('rmbz-approve-btn');
                    var hint = document.getElementById('rmbz-approve-hint');
                    if ( btn && btn.disabled ) return;
                    if ( ! btn ) return;

                    function update() {
                        var all = document.querySelectorAll('.rmbz-manual-check');
                        var checked = document.querySelectorAll('.rmbz-manual-check:checked');
                        var allOk = all.length > 0 && all.length === checked.length;
                        btn.disabled = ! allOk;
                        if ( hint ) {
                            hint.innerText = allOk
                                ? '✓ Tudo verificado — pode aprovar'
                                : 'Marca todos os checks manuais (' + checked.length + '/' + all.length + ') para desbloquear';
                            hint.style.color = allOk ? '#27ae60' : '#666';
                        }
                    }
                    btn.disabled = true;
                    document.querySelectorAll('.rmbz-manual-check').forEach(function(cb) {
                        cb.addEventListener('change', update);
                    });
                    update();
                })();
                </script>

                <style>
                /* [FEAT 1.6.22] Coluna esquerda sticky: capa + checklist + acções
                   acompanham o scroll para o admin nunca ter de voltar ao topo. */
                .rmbz-rel-sticky-col {
                    position: sticky;
                    top: 42px; /* WP admin bar */
                    max-height: calc(100vh - 60px);
                    overflow-y: auto;
                    scrollbar-width: thin;
                }
                .rmbz-rel-sticky-col::-webkit-scrollbar { width: 6px; }
                .rmbz-rel-sticky-col::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 3px; }

                .rmbz-review-checklist { background: #f8f9fa; border: 1px solid #dee2e6; border-radius: 6px; padding: 10px 12px; margin-bottom: 12px; }
                .rmbz-review-checklist > strong { display: block; font-size: 12px; margin-bottom: 8px; }
                .rmbz-checklist-head { font-size: 10px; text-transform: uppercase; color: var(--rmbz-text-muted, #666); letter-spacing: 0.3px; margin: 6px 0 4px 0; font-weight: 600; }
                .rmbz-check { display: flex; align-items: center; gap: 6px; font-size: 12px; padding: 2px 0; }
                .rmbz-check .ico { font-weight: 700; width: 14px; display: inline-block; text-align: center; }
                .rmbz-check.pass { color: var(--rmbz-success-strong, #166534); }
                .rmbz-check.pass .ico { color: var(--rmbz-success-strong, #059669); }
                .rmbz-check.fail { color: var(--rmbz-danger-strong, #721c24); }
                .rmbz-check.fail .ico { color: var(--rmbz-danger, #ef4444); }
                .rmbz-checklist-manual label { display: flex; align-items: center; gap: 6px; font-size: 12px; padding: 3px 0; cursor: pointer; color: #333; }
                .rmbz-checklist-manual input { cursor: pointer; }

                /* [FEAT 1.6.22] Header com contador */
                .rmbz-check-progress {
                    display: flex; align-items: center; gap: 8px;
                    padding: 7px 10px; border-radius: 5px;
                    margin-bottom: 10px; font-size: 12px;
                }
                .rmbz-check-progress.has-fails {
                    background: linear-gradient(135deg, #fee2e2, #fef2f2);
                    border-left: 3px solid #dc2626;
                    color: #7f1d1d;
                }
                .rmbz-check-progress.all-ok {
                    background: linear-gradient(135deg, #d1fae5, #ecfdf5);
                    border-left: 3px solid #10b981;
                    color: #065f46;
                }
                .rmbz-check-progress-icon { font-size: 14px; line-height: 1; }
                .rmbz-check-progress-stat {
                    margin-left: auto; font-size: 10px; opacity: 0.75;
                    background: rgba(255,255,255,0.6);
                    padding: 1px 6px; border-radius: 8px;
                    font-family: ui-monospace, monospace;
                }

                /* [FEAT 1.6.22] Falhas promovidas em cima */
                .rmbz-checklist-fails {
                    background: #fef2f2;
                    border: 1px solid #fecaca;
                    border-radius: 5px;
                    padding: 6px 10px;
                    margin-bottom: 10px;
                }
                .rmbz-fail-head {
                    color: #991b1b !important;
                }
                .rmbz-check.prominent {
                    padding: 4px 0;
                    font-weight: 600;
                }
                .rmbz-check.prominent .ico {
                    background: #dc2626;
                    color: #fff;
                    border-radius: 50%;
                    width: 16px; height: 16px;
                    line-height: 16px;
                    font-size: 10px;
                }
                </style>

            <?php elseif ( $is_in_workflow ): ?>
                <strong style="display:block; margin-bottom:8px;">Acções:</strong>
                <?php
                // Release já foi aprovado — agora avança pelo workflow:
                // Approved → Delivered → Live.
                // A função rmbz_admin_render_workflow_buttons mostra o botão
                // certo para o estado actual.
                if ( function_exists('rmbz_admin_render_workflow_buttons') ) {
                    rmbz_admin_render_workflow_buttons( $release );
                } else {
                    echo '<p style="color:#856404;">⚠ Módulo de workflow não carregado.</p>';
                }

                // Editor de links DSP (aparece a partir de delivered)
                if ( function_exists('rmbz_admin_render_dsp_links_editor') ) {
                    rmbz_admin_render_dsp_links_editor( $release );
                }
                ?>

            <?php elseif ( $is_live ): ?>
                <strong style="display:block; margin-bottom:8px;">Acções:</strong>
                <?php
                // Release já está ao vivo. Ainda assim mostramos o editor de
                // links DSP (admin pode corrigir/adicionar links depois) +
                // botão de takedown.
                if ( function_exists('rmbz_admin_render_dsp_links_editor') ) {
                    rmbz_admin_render_dsp_links_editor( $release );
                }
                ?>
                <form method="post" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" style="margin-top:12px;">
                    <?php wp_nonce_field('rmbz_release_action_' . $release->id); ?>
                    <input type="hidden" name="action" value="rmbz_release_takedown">
                    <input type="hidden" name="release_id" value="<?php echo (int) $release->id; ?>">
                    <button type="submit" class="button button-link-delete" style="width:100%;"
                            onclick="return confirm('Remover este lançamento dos DSPs? Esta acção é irreversível.');">
                        🗑 Pedir takedown
                    </button>
                </form>

            <?php elseif ( $release->status === 'returned' ): ?>
                <?php
                $return_data = rmbz_distro_get_return_data( $release );
                $days_left = rmbz_distro_return_days_left( $release );
                $overdue   = rmbz_distro_return_is_overdue( $release );
                ?>
                <div style="background:#fff3cd; border:1px solid #f0b90b; border-radius:6px; padding:10px; font-size:12px;">
                    <strong style="color:#856404;">⟲ Devolvido ao artista</strong>
                    <p style="margin:4px 0 0 0;">
                        <?php if ( $overdue ): ?>
                            <span style="color:var(--rmbz-danger, #ef4444);">⏰ Prazo expirado</span>
                        <?php else: ?>
                            <?php echo $days_left; ?> dia(s) restante(s)
                        <?php endif; ?>
                        · <?php echo count($return_data['problems'] ?? []); ?> problema(s)
                    </p>
                </div>

            <?php elseif ( $release->status === 'takedown_requested' ): ?>
                <strong style="display:block; margin-bottom:8px;">Acções:</strong>
                <?php
                // Pedido de takedown a aguardar decisão do admin.
                // Mostrar contexto do pedido + 2 acções: confirmar (passar a
                // taken_down) ou cancelar (voltar a live).

                global $wpdb;
                $t_hist = $wpdb->prefix . 'rmbz_distro_status_history';
                $last_event = $wpdb->get_row( $wpdb->prepare(
                    "SELECT changed_by, reason_code, reason_text, created_at
                     FROM $t_hist
                     WHERE release_id = %d AND to_status = 'takedown_requested'
                     ORDER BY id DESC LIMIT 1",
                    $release->id
                ) );

                $req_by   = $last_event ? $last_event->changed_by : '—';
                $req_when = $last_event ? $last_event->created_at : '';
                $req_text = $last_event ? $last_event->reason_text : ($release->takedown_reason ?? '');
                $req_code = $last_event ? $last_event->reason_code : '';

                // O reason_text vem com formato "[Motivo] detalhes adicionais"
                // (ver distribution-lifecycle.php artist_request_takedown).
                ?>
                <div style="background:#fde4e2; border:1px solid #e74c3c; border-radius:6px; padding:12px; font-size:12px; margin-bottom:10px;">
                    <strong style="color:#921a13; display:block; margin-bottom:6px;">🗑 Pedido de takedown</strong>
                    <table style="width:100%; font-size:11px; border-collapse:collapse;">
                        <tr><td style="color:var(--rmbz-text-muted, #666); padding:2px 0;">Pedido por:</td><td><code><?php echo esc_html($req_by); ?></code></td></tr>
                        <?php if ( $req_when ): ?>
                            <tr><td style="color:var(--rmbz-text-muted, #666); padding:2px 0;">Quando:</td><td><?php echo esc_html( date('d/m/Y H:i', strtotime($req_when)) ); ?></td></tr>
                        <?php endif; ?>
                        <?php if ( $req_code ): ?>
                            <tr><td style="color:var(--rmbz-text-muted, #666); padding:2px 0;">Código:</td><td><code><?php echo esc_html($req_code); ?></code></td></tr>
                        <?php endif; ?>
                    </table>
                    <?php if ( $req_text ): ?>
                        <div style="margin-top:8px; padding:8px; background:var(--rmbz-bg-card, #fff); border-radius:4px; color:#333; line-height:1.4;">
                            <?php echo esc_html($req_text); ?>
                        </div>
                    <?php endif; ?>
                </div>

                <form method="post" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" style="margin-bottom:8px;">
                    <?php wp_nonce_field('rmbz_release_action_' . $release->id); ?>
                    <input type="hidden" name="action" value="rmbz_release_takedown_confirm">
                    <input type="hidden" name="release_id" value="<?php echo (int) $release->id; ?>">
                    <button type="submit" class="button button-primary" style="width:100%; background:var(--rmbz-danger-strong, #b91c1c); border-color:#a93226;"
                            onclick="return confirm('FINALIZAR takedown? O lançamento será marcado como removido das lojas. Esta acção é IRREVERSÍVEL — para repor, o artista terá de criar novo release com novo UPC e novos ISRCs.');">
                        ✓ Finalizar takedown (já removido das lojas)
                    </button>
                </form>

                <form method="post" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" style="margin-bottom:8px;">
                    <?php wp_nonce_field('rmbz_release_action_' . $release->id); ?>
                    <input type="hidden" name="action" value="rmbz_release_takedown_cancel">
                    <input type="hidden" name="release_id" value="<?php echo (int) $release->id; ?>">
                    <button type="submit" class="button" style="width:100%;"
                            onclick="return confirm('CANCELAR este pedido de takedown? O release volta a estar live e o artista será notificado.');">
                        ⟲ Cancelar pedido (manter nas lojas)
                    </button>
                </form>

                <p style="font-size:11px; color:var(--rmbz-text-faint, #888); margin:6px 0 0 0; line-height:1.4;">
                    O takedown nas lojas demora 7-14 dias a propagar. Só finaliza
                    quando confirmares manualmente que o release já saiu de todas
                    as lojas (ou aceitas que está em processo).
                </p>

            <?php elseif ( $release->status === 'taken_down' ): ?>
                <?php
                global $wpdb;
                $t_hist = $wpdb->prefix . 'rmbz_distro_status_history';
                $td_event = $wpdb->get_row( $wpdb->prepare(
                    "SELECT changed_by, reason_text, created_at
                     FROM $t_hist
                     WHERE release_id = %d AND to_status = 'taken_down'
                     ORDER BY id DESC LIMIT 1",
                    $release->id
                ) );
                ?>
                <div style="background:#f0f0f0; border:1px solid #999; border-radius:6px; padding:12px; font-size:12px;">
                    <strong style="color:var(--rmbz-text-primary, #444); display:block; margin-bottom:6px;">🚫 Lançamento removido</strong>
                    <p style="margin:4px 0 0 0; color:var(--rmbz-text-muted, #666);">
                        Estado terminal — não há mais acções disponíveis.
                        <?php if ( $td_event ): ?>
                            <br><small>Removido em <?php echo esc_html( date('d/m/Y H:i', strtotime($td_event->created_at)) ); ?> por <code><?php echo esc_html($td_event->changed_by); ?></code></small>
                        <?php endif; ?>
                    </p>
                </div>
            <?php endif; ?>
        </div>

        <div>
            <div class="rmbz-section rmbz-meta-section">
                <?php /* [1.5.124] Painel Metadata redesenhado.
                    Antes: tabela 2-col `<table>` com `color:#666` em labels e
                    valores em texto plano. Layout não escalava bem em sidebars
                    estreitos e era visualmente "WP-classic".
                    Agora: grid CSS moderno com:
                      - Cada campo = card mini com label uppercase + valor
                      - Códigos identificadores (UPC, ISRC, tel) em "chip" mono
                      - 2 colunas em ≥600px, 1 coluna em ≤600px
                      - Estados visuais (pending/exact/warning) usando cor subtil
                      - Sem `<table>` — grid permite reflow natural
                */ ?>
                <style>
                    .rmbz-meta-section h3 {
                        display:flex; align-items:center; gap:8px;
                        font-size:14px; font-weight:600;
                        color:var(--rmbz-text-strong, #1d2327);
                        text-transform:uppercase; letter-spacing:0.04em;
                        margin:0 0 18px;
                        padding-bottom:12px;
                        border-bottom:1px solid #e7e9ed;
                    }
                    .rmbz-meta-grid {
                        display:grid;
                        grid-template-columns:1fr;
                        gap:14px 24px;
                    }
                    @media (min-width: 600px) {
                        .rmbz-meta-grid { grid-template-columns:1fr 1fr; }
                        .rmbz-meta-grid .rmbz-meta-item--full { grid-column:1 / -1; }
                    }
                    .rmbz-meta-item {
                        display:flex; flex-direction:column;
                        gap:4px;
                        min-width:0;
                    }
                    .rmbz-meta-label {
                        font-size:11px;
                        font-weight:600;
                        color:#646970;
                        text-transform:uppercase;
                        letter-spacing:0.06em;
                    }
                    .rmbz-meta-value {
                        font-size:14px;
                        color:var(--rmbz-text-strong, #1d2327);
                        line-height:1.4;
                        word-break:break-word;
                    }
                    .rmbz-meta-value--strong { font-weight:600; }
                    .rmbz-meta-value--muted { color:#8c8f94; font-style:italic; }
                    .rmbz-meta-chip {
                        display:inline-flex; align-items:center; gap:6px;
                        padding:4px 10px;
                        background:#f0f0f1;
                        border:1px solid #dcdcde;
                        border-radius:5px;
                        font-family:ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
                        font-size:12.5px;
                        color:var(--rmbz-text-strong, #1d2327);
                        max-width:100%;
                        overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
                    }
                    .rmbz-meta-chip-list {
                        display:flex; flex-wrap:wrap; gap:6px;
                        align-items:center;
                    }
                    .rmbz-meta-status {
                        display:inline-flex; align-items:center; gap:4px;
                        font-size:11.5px;
                        padding:2px 8px;
                        border-radius:10px;
                        font-weight:500;
                    }
                    .rmbz-meta-status--locked { background:#fef3e2; color:#996b00; }
                    .rmbz-meta-status--pending { background:#fff1f0; color:#8a1f11; }
                    .rmbz-meta-status--ok { background:#e8f5e9; color:#2e7d32; }
                    .rmbz-meta-rejection {
                        margin-top:18px;
                        padding:14px 16px;
                        background:#fff1f0;
                        border:1px solid #f5c2c7;
                        border-left:4px solid #d63638;
                        border-radius:6px;
                        font-size:13px;
                        line-height:1.5;
                        color:#641e16;
                    }
                    .rmbz-meta-rejection strong { color:var(--rmbz-danger, #ef4444); }
                </style>

                <h3>📝 Metadata</h3>

                <?php
                // Pre-compute ISRC summary (lógica preservada da 1.5.123).
                $isrc_codes = [];
                $tracks_without_isrc = 0;
                foreach ( (array) $tracks as $tr ) {
                    if ( ! empty($tr->isrc_code) ) {
                        $isrc_codes[] = $tr->isrc_code;
                    } else {
                        $tracks_without_isrc++;
                    }
                }
                $total_tracks = count( (array) $tracks );
                ?>

                <div class="rmbz-meta-grid">

                    <?php
                    // [1.5.196] Data de lançamento e género editáveis inline
                    $rel_field_locked = in_array( $release->status, ['live','distribuido'], true );
                    $rel_field_nonce  = wp_create_nonce( 'rmbz_release_field_save_' . (int) $release->id );
                    ?>

                    <div class="rmbz-meta-item">
                        <span class="rmbz-meta-label">📅 Data de lançamento</span>
                        <span class="rmbz-meta-value rmbz-meta-value--strong">
                            <span class="rmbz-rel-edit-wrap"
                                  data-release-id="<?php echo (int) $release->id; ?>"
                                  data-field="release_date"
                                  data-input-type="date"
                                  data-locked="<?php echo $rel_field_locked ? '1' : '0'; ?>"
                                  data-nonce="<?php echo esc_attr( $rel_field_nonce ); ?>">
                                <span class="rmbz-rel-display"
                                      title="<?php echo $rel_field_locked ? 'Bloqueado: nas lojas' : 'Click para editar data'; ?>"
                                      style="<?php echo $rel_field_locked ? 'cursor:not-allowed;' : 'cursor:pointer;'; ?>">
                                    <?php echo $release->release_date
                                        ? esc_html( date('d/m/Y', strtotime($release->release_date)) )
                                        : '<span class="rmbz-meta-value--muted">—</span>'; ?><?php if ( ! $rel_field_locked ): ?> <span style="font-size:11px; opacity:0.4;">✏️</span><?php endif; ?>
                                </span>
                                <?php if ( ! $rel_field_locked ): ?>
                                    <input type="date" class="rmbz-rel-input"
                                           value="<?php echo esc_attr( $release->release_date ?? '' ); ?>"
                                           style="display:none; font-size:13px; padding:3px 6px; border-radius:4px; border:1px solid var(--wp-admin-theme-color, #2271b1);">
                                    <span class="rmbz-rel-status" style="display:none; font-size:11px;"></span>
                                <?php endif; ?>
                            </span>
                        </span>
                    </div>

                    <div class="rmbz-meta-item">
                        <span class="rmbz-meta-label">🎵 Género</span>
                        <span class="rmbz-meta-value">
                            <span class="rmbz-rel-edit-wrap"
                                  data-release-id="<?php echo (int) $release->id; ?>"
                                  data-field="primary_genre"
                                  data-input-type="select"
                                  data-locked="<?php echo $rel_field_locked ? '1' : '0'; ?>"
                                  data-nonce="<?php echo esc_attr( $rel_field_nonce ); ?>">
                                <span class="rmbz-rel-display"
                                      title="<?php echo $rel_field_locked ? 'Bloqueado: nas lojas' : 'Click para editar género'; ?>"
                                      style="<?php echo $rel_field_locked ? 'cursor:not-allowed;' : 'cursor:pointer;'; ?>">
                                    <?php echo $release->primary_genre
                                        ? esc_html($release->primary_genre)
                                        : '<span class="rmbz-meta-value--muted">—</span>'; ?><?php if ( ! $rel_field_locked ): ?> <span style="font-size:11px; opacity:0.4;">✏️</span><?php endif; ?>
                                </span>
                                <?php if ( ! $rel_field_locked ): ?>
                                    <?php
                                    // Lista de géneros usados no sistema (autopopulada)
                                    global $wpdb;
                                    $available_genres = $wpdb->get_col( "SELECT DISTINCT primary_genre FROM {$wpdb->prefix}rmbz_distro_releases WHERE primary_genre IS NOT NULL AND primary_genre != '' ORDER BY primary_genre ASC" );
                                    // Adicionar géneros standard caso a lista esteja curta
                                    $std_genres = ['Pop','R&B','Rock','Hip-Hop','Reggae','Afrobeats','Kizomba','Marrabenta','Pandza','Gospel','Electronic','Jazz','Classical','Country','Latin','World','Other'];
                                    $all_genres = array_unique( array_merge( $available_genres, $std_genres ) );
                                    sort( $all_genres );
                                    ?>
                                    <select class="rmbz-rel-input"
                                            style="display:none; font-size:13px; padding:3px 6px; border-radius:4px; border:1px solid var(--wp-admin-theme-color, #2271b1);">
                                        <option value="">— sem género —</option>
                                        <?php foreach ( $all_genres as $g ): ?>
                                            <option value="<?php echo esc_attr($g); ?>" <?php selected( $release->primary_genre, $g ); ?>><?php echo esc_html($g); ?></option>
                                        <?php endforeach; ?>
                                    </select>
                                    <span class="rmbz-rel-status" style="display:none; font-size:11px;"></span>
                                <?php endif; ?>
                            </span>
                        </span>
                    </div>

                    <div class="rmbz-meta-item">
                        <span class="rmbz-meta-label">🌐 Idioma</span>
                        <span class="rmbz-meta-value">
                            <?php echo $release->language
                                ? esc_html($release->language)
                                : '<span class="rmbz-meta-value--muted">—</span>'; ?>
                        </span>
                    </div>

                    <div class="rmbz-meta-item">
                        <span class="rmbz-meta-label">🏢 Gravadora</span>
                        <span class="rmbz-meta-value">
                            <?php echo $release->label_name
                                ? esc_html($release->label_name)
                                : '<span class="rmbz-meta-value--muted">—</span>'; ?>
                        </span>
                    </div>

                    <div class="rmbz-meta-item">
                        <span class="rmbz-meta-label">🆔 UPC</span>
                        <div class="rmbz-meta-value">
                            <?php
                            if ( function_exists('rmbz_admin_render_upc_editor') ) {
                                rmbz_admin_render_upc_editor( $release );
                            } else {
                                if ( $release->upc_code ) {
                                    echo '<span class="rmbz-meta-chip">' . esc_html($release->upc_code) . '</span>';
                                } else {
                                    echo '<span class="rmbz-meta-status rmbz-meta-status--pending">Pendente</span>';
                                }
                            }
                            ?>
                        </div>
                    </div>

                    <div class="rmbz-meta-item">
                        <span class="rmbz-meta-label">
                            🏷 ISRC<?php echo $total_tracks > 1 ? ' (faixas)' : ''; ?>
                        </span>
                        <div class="rmbz-meta-value">
                            <?php if ( $total_tracks === 0 ): ?>
                                <span class="rmbz-meta-value--muted">Sem faixas</span>
                            <?php elseif ( $total_tracks === 1 && count($isrc_codes) === 1 ): ?>
                                <span class="rmbz-meta-chip"><?php echo esc_html( $isrc_codes[0] ); ?></span>
                            <?php elseif ( count($isrc_codes) === $total_tracks ): ?>
                                <div class="rmbz-meta-chip-list">
                                    <span class="rmbz-meta-status rmbz-meta-status--ok">
                                        ✓ <?php echo count($isrc_codes); ?> atribuídos
                                    </span>
                                    <?php foreach ( $isrc_codes as $code ): ?>
                                        <span class="rmbz-meta-chip"><?php echo esc_html($code); ?></span>
                                    <?php endforeach; ?>
                                </div>
                            <?php else: ?>
                                <div class="rmbz-meta-chip-list">
                                    <span class="rmbz-meta-status rmbz-meta-status--pending">
                                        ⚠ <?php echo count($isrc_codes); ?>/<?php echo $total_tracks; ?> atribuídos
                                    </span>
                                    <?php foreach ( $isrc_codes as $code ): ?>
                                        <span class="rmbz-meta-chip"><?php echo esc_html($code); ?></span>
                                    <?php endforeach; ?>
                                </div>
                            <?php endif; ?>
                        </div>
                    </div>

                    <div class="rmbz-meta-item">
                        <span class="rmbz-meta-label">📍 Local de gravação</span>
                        <span class="rmbz-meta-value">
                            <?php echo $release->recording_location
                                ? esc_html($release->recording_location)
                                : '<span class="rmbz-meta-value--muted">—</span>'; ?>
                        </span>
                    </div>

                    <div class="rmbz-meta-item">
                        <span class="rmbz-meta-label">📱 Artista (telemóvel)</span>
                        <div class="rmbz-meta-value">
                            <span class="rmbz-meta-chip"><?php echo esc_html($release->artist_tel); ?></span>
                        </div>
                    </div>

                </div>

                <?php if ( ! empty($release->rejection_reason) ): ?>
                    <div class="rmbz-meta-rejection">
                        <strong>Motivo de rejeição:</strong>
                        <?php echo esc_html($release->rejection_reason); ?>
                    </div>
                <?php endif; ?>
            </div>

            <?php
            // [1.5.191] CARD: Saúde de relatórios desta release
            //
            // Mostra de relance:
            //   - Quando foi o último import que tocou em alguma faixa
            //   - Há quantos meses está silenciosa (se aplicável)
            //   - Quantas faixas nunca receberam vs quantas já receberam
            //
            // Cor do card consoante a saúde:
            //   verde:    último relatório < 2 meses
            //   amarelo:  2-4 meses
            //   laranja:  5-6 meses
            //   vermelho: 7+ meses ou nenhuma faixa nunca recebeu
            $rs_total     = $reporting_summary['total'];
            $rs_oldest    = $reporting_summary['oldest_date'];
            $rs_newest    = $reporting_summary['newest_date'];
            $rs_never     = $reporting_summary['never'];
            $rs_with_data = $reporting_summary['with_data'];
            // [1.5.209] Match Review pending — estado intermédio
            $rs_pending_n = (int)   ($reporting_summary['pending_matches']        ?? 0);
            $rs_pending_v = (float) ($reporting_summary['pending_matches_amount'] ?? 0);

            $health = 'unknown'; // grey/green/yellow/orange/red/amber
            $health_label = '';
            $health_msg = '';

            if ( $rs_total === 0 ) {
                $health = 'unknown';
                $health_label = 'Sem faixas';
                $health_msg   = 'Esta release não tem faixas registadas.';
            } elseif ( $rs_with_data === 0 && $rs_pending_n > 0 ) {
                // [1.5.209] Faixas têm dados mas em "Matches a Rever" — não saíram
                // ainda para daily_stats. Estado intermédio: amber (laranja claro).
                $health = 'amber';
                $health_label = 'Aguardando confirmação de match';
                $health_msg   = sprintf(
                    'Existem %d linha(s) no CSV ($%s USD) mas o match não foi feito por ISRC. Vai a "Matches a Rever" confirmar.',
                    $rs_pending_n,
                    number_format( $rs_pending_v, 2 )
                );
            } elseif ( $rs_with_data === 0 ) {
                // Nenhuma faixa nunca recebeu
                $health = 'red';
                $health_label = 'Nunca reportou';
                $health_msg   = 'Esta release ainda não recebeu nenhum relatório de royalties.';
            } else {
                $newest_ts = strtotime( $rs_newest );
                $months_since_newest = (int) floor( ( time() - $newest_ts ) / ( 30 * 86400 ) );

                if ( $months_since_newest < 2 ) {
                    $health = 'green';
                    $health_label = 'Saudável';
                    $health_msg   = 'A receber relatórios normalmente.';
                } elseif ( $months_since_newest < 5 ) {
                    $health = 'yellow';
                    $health_label = 'Atenção';
                    $health_msg   = 'Não recebe relatórios há ' . $months_since_newest . ' meses.';
                } elseif ( $months_since_newest < 7 ) {
                    $health = 'orange';
                    $health_label = 'Atraso médio';
                    $health_msg   = 'Sem relatórios há ' . $months_since_newest . ' meses — investigar.';
                } else {
                    $health = 'red';
                    $health_label = 'Crítico';
                    $health_msg   = 'Sem relatórios há ' . $months_since_newest . ' meses — atenção urgente.';
                }

                // [1.5.209] Mesmo com dados, alertar se há matches pendentes
                // (faixas têm dados mas há mais $ retidos em match_review)
                if ( $rs_pending_n > 0 ) {
                    $health_msg .= sprintf(
                        ' · ⚠ %d linha(s) pendente(s) em "Matches a Rever" ($%s USD).',
                        $rs_pending_n,
                        number_format( $rs_pending_v, 2 )
                    );
                }
            }

            $health_colors = [
                'green'   => [ 'bg' => '#ecfdf5', 'border' => '#10b981', 'text' => '#065f46' ],
                'yellow'  => [ 'bg' => '#fffbeb', 'border' => '#f59e0b', 'text' => '#854d0e' ],
                'amber'   => [ 'bg' => '#fff7ed', 'border' => '#f59e0b', 'text' => '#854d0e' ],
                'orange'  => [ 'bg' => '#fff7ed', 'border' => '#ea580c', 'text' => '#9a3412' ],
                'red'     => [ 'bg' => '#fef2f2', 'border' => '#dc2626', 'text' => '#991b1b' ],
                'unknown' => [ 'bg' => '#f9fafb', 'border' => '#9ca3af', 'text' => '#374151' ],
            ];
            $hc = $health_colors[ $health ];
            ?>
            <div class="rmbz-section" style="background:<?php echo esc_attr($hc['bg']); ?>; border-left:4px solid <?php echo esc_attr($hc['border']); ?>;">
                <div style="display:flex; gap:18px; align-items:flex-start; flex-wrap:wrap;">
                    <div style="flex:1; min-width:200px;">
                        <div style="font-size:11px; color:<?php echo esc_attr($hc['text']); ?>; text-transform:uppercase; letter-spacing:0.04em; font-weight:700;">
                            📊 Estado dos relatórios
                        </div>
                        <div style="font-size:18px; color:<?php echo esc_attr($hc['text']); ?>; font-weight:600; margin-top:4px;">
                            <?php echo esc_html( $health_label ); ?>
                        </div>
                        <div style="font-size:13px; color:<?php echo esc_attr($hc['text']); ?>; margin-top:2px;">
                            <?php echo esc_html( $health_msg ); ?>
                        </div>
                    </div>
                    <div style="display:grid; grid-template-columns:repeat(auto-fit, minmax(140px, 1fr)); gap:14px; flex:2; min-width:280px;">
                        <div>
                            <div style="font-size:11px; color:#6b7280; text-transform:uppercase; letter-spacing:0.04em;">Último relatório</div>
                            <div style="font-size:14px; color:#1f2937; font-weight:600; margin-top:2px;">
                                <?php if ( $rs_newest ): ?>
                                    <?php echo esc_html( date('d/m/Y', strtotime($rs_newest)) ); ?>
                                <?php else: ?>
                                    <span style="color:#9ca3af;">— nunca —</span>
                                <?php endif; ?>
                            </div>
                        </div>
                        <div>
                            <div style="font-size:11px; color:#6b7280; text-transform:uppercase; letter-spacing:0.04em;">Mais antigo</div>
                            <div style="font-size:14px; color:#1f2937; font-weight:600; margin-top:2px;">
                                <?php if ( $rs_oldest ): ?>
                                    <?php echo esc_html( date('d/m/Y', strtotime($rs_oldest)) ); ?>
                                <?php else: ?>
                                    <span style="color:#9ca3af;">—</span>
                                <?php endif; ?>
                            </div>
                        </div>
                        <div>
                            <div style="font-size:11px; color:#6b7280; text-transform:uppercase; letter-spacing:0.04em;">Faixas com dados</div>
                            <div style="font-size:14px; color:#1f2937; font-weight:600; margin-top:2px;">
                                <?php echo (int) $rs_with_data; ?> / <?php echo (int) $rs_total; ?>
                                <?php if ( $rs_never > 0 ): ?>
                                    <span style="font-size:11px; color:#dc2626; font-weight:500;">
                                        (<?php echo (int) $rs_never; ?> sem dados)
                                    </span>
                                <?php endif; ?>
                            </div>
                        </div>
                        <?php if ( $rs_pending_n > 0 ): ?>
                        <div>
                            <div style="font-size:11px; color:#6b7280; text-transform:uppercase; letter-spacing:0.04em;">Em Match Review</div>
                            <div style="font-size:14px; color:#854d0e; font-weight:600; margin-top:2px;">
                                <?php echo (int) $rs_pending_n; ?> linha(s)
                                <span style="font-size:11px; color:#854d0e; font-weight:500;">
                                    · $<?php echo number_format( $rs_pending_v, 2 ); ?>
                                </span>
                                <br>
                                <a href="<?php echo esc_url( admin_url('admin.php?page=rmbz-admin-distribution&tab=match_review') ); ?>"
                                   style="display:inline-block; margin-top:4px; padding:3px 9px; background:#f59e0b; color:#fff; border-radius:3px; font-size:11px; font-weight:600; text-decoration:none;">
                                    🔍 Confirmar matches →
                                </a>
                            </div>
                        </div>
                        <?php endif; ?>
                    </div>
                </div>
            </div>

            <div class="rmbz-section">
                <h3>🎶 Faixas (<?php echo count($tracks); ?>)</h3>
                <?php if ( empty($tracks) ): ?>
                    <p style="color:var(--rmbz-text-faint, #888);">Nenhuma faixa associada.</p>
                <?php else: ?>
                    <div class="rmbz-admin-tracks">
                    <?php foreach ( $tracks as $i => $t ):
                        $extra = [];
                        if ( ! empty($t->extra_data) ) {
                            $d = json_decode($t->extra_data, true);
                            if ( is_array($d) ) $extra = $d;
                        }
                        $dur = (int) ($extra['duration_seconds'] ?? 0);
                        $has_sw = ! empty($extra['songwriters']);
                        $has_col = ! empty($extra['collaborators']);
                        $audio_info = $extra['audio_info'] ?? [];
                        $splits_count = 0;
                        if ( $wpdb->get_var("SHOW TABLES LIKE '$t_splits'") === $t_splits ) {
                            $splits_count = (int) $wpdb->get_var( $wpdb->prepare(
                                "SELECT COUNT(*) FROM $t_splits WHERE track_id = %d", $t->id
                            ) );
                        }

                        // Re-analisar on-the-fly se não há info guardada
                        if ( empty($audio_info) && ! empty($t->audio_url) && function_exists('rmbz_analyze_audio_file') ) {
                            $upload_dir = wp_upload_dir();
                            $local_path = str_replace( $upload_dir['baseurl'], $upload_dir['basedir'], $t->audio_url );
                            if ( file_exists($local_path) ) {
                                $fresh = rmbz_analyze_audio_file( $local_path );
                                if ( $fresh['ok'] ) $audio_info = $fresh['info'];
                            }
                        }

                        // Badges de qualidade
                        $quality_label = '—'; $quality_class = 'neutral';
                        if ( ! empty($audio_info) ) {
                            $fmt = $audio_info['format'] ?? '';
                            $bd  = (int) ($audio_info['bit_depth'] ?? 0);
                            $sr  = (int) ($audio_info['sample_rate_hz'] ?? 0);
                            if ( in_array($fmt, ['wav','flac'], true) && $bd >= 24 && $sr >= 48000 ) {
                                $quality_label = 'Estúdio'; $quality_class = 'excellent';
                            } elseif ( in_array($fmt, ['wav','flac'], true) ) {
                                $quality_label = 'Alta'; $quality_class = 'good';
                            } elseif ( $fmt === 'mp3' && ($audio_info['bitrate_kbps'] ?? 0) >= 320 ) {
                                $quality_label = 'MP3 320'; $quality_class = 'ok';
                            } else {
                                $quality_label = 'Baixa'; $quality_class = 'warning';
                            }
                        }
                    ?>
                        <div class="rmbz-track-card">
                            <div class="rmbz-track-head">
                                <div class="rmbz-track-num"><?php echo ($i + 1); ?></div>
                                <div class="rmbz-track-meta">
                                    <strong><?php echo esc_html($t->track_title); ?></strong>
                                    <?php
                                    // [1.5.195] Render melhor de colaboradores
                                    //
                                    // Antes: $has_col = qualquer colaborador → mostra "feat."
                                    //   Bug: produtores e mixers apareciam como "feat." (errado).
                                    //
                                    // Agora: separa por role:
                                    //   - 'feature' → "feat. NOME"  (badge laranja destacado)
                                    //   - outros (producer/mixer/songwriter/etc) → linha pequena
                                    //
                                    // Também olha para a coluna feat_artists (fallback texto livre).
                                    $featuring = [];   // collaborators com role=feature
                                    $other_cols = [];  // outros colaboradores
                                    if ( $has_col && is_array($extra['collaborators']) ) {
                                        foreach ( $extra['collaborators'] as $c ) {
                                            $name = trim( $c['name'] ?? '' );
                                            $role = trim( $c['role'] ?? '' );
                                            if ( $name === '' ) continue;
                                            if ( $role === 'feature' || $role === 'featuring' || $role === '' ) {
                                                $featuring[] = $name;
                                            } else {
                                                $other_cols[] = [ 'name' => $name, 'role' => $role ];
                                            }
                                        }
                                    }
                                    // Fallback: campo feat_artists directo na tabela tracks
                                    if ( empty($featuring) && ! empty( $t->feat_artists ) ) {
                                        $raw = trim( (string) $t->feat_artists );
                                        if ( $raw !== '' ) {
                                            // Pode ser "DJ X, Maya" ou "DJ X & Maya" — tenta partir
                                            $parts = preg_split('/\s*[,&]\s*/', $raw);
                                            foreach ( $parts as $p ) {
                                                $p = trim( $p );
                                                if ( $p !== '' ) $featuring[] = $p;
                                            }
                                        }
                                    }
                                    ?>
                                    <?php if ( ! empty( $featuring ) ): ?>
                                        <div class="rmbz-track-feats" style="margin-top:3px;">
                                            <span style="background:#fff7ed; color:#9a3412; padding:2px 8px; border-radius:10px; font-size:11px; font-weight:600;">
                                                🎤 feat. <?php echo esc_html( implode(', ', array_slice($featuring, 0, 5)) ); ?>
                                                <?php if ( count($featuring) > 5 ): ?>
                                                    <span style="opacity:0.7;">+<?php echo count($featuring) - 5; ?></span>
                                                <?php endif; ?>
                                            </span>
                                        </div>
                                    <?php endif; ?>
                                    <?php if ( ! empty( $other_cols ) ): ?>
                                        <div class="rmbz-track-feats" style="margin-top:3px; font-size:10px; color:#6b7280;">
                                            <?php
                                            $role_labels = [
                                                'producer' => 'Produtor', 'production' => 'Produtor',
                                                'mixer'    => 'Mistura',  'mix'        => 'Mistura',
                                                'master'   => 'Mastering', 'mastering' => 'Mastering',
                                                'songwriter' => 'Compositor', 'composer' => 'Compositor',
                                                'arranger' => 'Arranjador',
                                                'engineer' => 'Engenheiro de som',
                                                'instrumentalist' => 'Instrumentista',
                                            ];
                                            $other_strs = [];
                                            foreach ( array_slice($other_cols, 0, 4) as $oc ) {
                                                $role_label = $role_labels[ $oc['role'] ] ?? ucfirst( $oc['role'] );
                                                $other_strs[] = $oc['name'] . ' <em style="color:#9ca3af;">(' . esc_html($role_label) . ')</em>';
                                            }
                                            echo wp_kses( implode(' · ', $other_strs), [ 'em' => [ 'style' => true ] ] );
                                            if ( count($other_cols) > 4 ) {
                                                echo ' <span style="opacity:0.6;">+' . (count($other_cols) - 4) . '</span>';
                                            }
                                            ?>
                                        </div>
                                    <?php endif; ?>
                                    <?php if ( empty( $featuring ) && empty( $other_cols ) ): ?>
                                        <div class="rmbz-track-feats" style="margin-top:3px; font-size:10px; color:#9ca3af;">
                                            <em>Sem colaboradores registados</em>
                                        </div>
                                    <?php endif; ?>
                                    <div class="rmbz-track-badges">
                                        <span class="rmbz-badge rmbz-badge-<?php echo esc_attr($quality_class); ?>"><?php echo esc_html($quality_label); ?></span>
                                        <?php
                                        // [1.5.192] ISRC editável inline
                                        //
                                        // Editável quando: status NÃO é 'live'/'distribuido'
                                        // (uma vez entregue aos DSPs, mudar ISRC localmente
                                        // criaria desync com Spotify/Apple e perde-se monetização).
                                        //
                                        // Click no badge → vira input → Enter ou blur grava via AJAX.
                                        // Esc cancela. Validação local: 12 chars alphanum.
                                        $isrc_locked = in_array( $release->status, ['live','distribuido'], true );
                                        $isrc_value  = $t->isrc_code ?? '';
                                        $isrc_nonce  = wp_create_nonce( 'rmbz_track_isrc_save_' . (int) $t->id );
                                        ?>
                                        <span class="rmbz-isrc-edit-wrap"
                                              data-track-id="<?php echo (int) $t->id; ?>"
                                              data-locked="<?php echo $isrc_locked ? '1' : '0'; ?>"
                                              data-nonce="<?php echo esc_attr( $isrc_nonce ); ?>">
                                            <?php if ( ! empty($isrc_value) ): ?>
                                                <span class="rmbz-badge rmbz-badge-code rmbz-isrc-display"
                                                      title="<?php echo $isrc_locked ? 'ISRC bloqueado: já está nas lojas' : 'Click para editar'; ?>"
                                                      style="<?php echo $isrc_locked ? 'cursor:not-allowed;' : 'cursor:pointer;'; ?>">
                                                    <?php echo esc_html($isrc_value); ?><?php if ( ! $isrc_locked ): ?> ✏️<?php endif; ?>
                                                </span>
                                            <?php else: ?>
                                                <span class="rmbz-badge rmbz-badge-warning rmbz-isrc-display"
                                                      title="<?php echo $isrc_locked ? 'ISRC pendente (release nas lojas — bloqueado)' : 'Click para atribuir manualmente'; ?>"
                                                      style="<?php echo $isrc_locked ? 'cursor:not-allowed;' : 'cursor:pointer;'; ?>">
                                                    ISRC pendente<?php if ( ! $isrc_locked ): ?> ✏️<?php endif; ?>
                                                </span>
                                            <?php endif; ?>
                                            <?php if ( ! $isrc_locked ): ?>
                                                <input type="text" class="rmbz-isrc-input" maxlength="17"
                                                       placeholder="Ex: BG-A47-25-12345"
                                                       value="<?php echo esc_attr( $isrc_value ); ?>"
                                                       style="display:none;">
                                                <span class="rmbz-isrc-status" style="display:none;"></span>
                                            <?php endif; ?>
                                        </span>
                                        <span class="rmbz-badge rmbz-badge-neutral"><?php echo $dur > 0 ? sprintf('%d:%02d', floor($dur/60), $dur%60) : '—:—'; ?></span>
                                        <?php
                                        // [1.5.191] Badge de última actualização de import.
                                        // Mostra ao admin quando esta faixa apareceu pela última
                                        // vez num CSV. Cor consoante a recência.
                                        if ( ! empty( $t->last_seen_in_csv ) ) {
                                            $tk_ts = strtotime( $t->last_seen_in_csv );
                                            $tk_months = (int) floor( ( time() - $tk_ts ) / ( 30 * 86400 ) );
                                            $tk_class = 'rmbz-badge-good';
                                            if ( $tk_months >= 7 )      $tk_class = 'rmbz-badge-warning';
                                            elseif ( $tk_months >= 5 )  $tk_class = 'rmbz-badge-warning';
                                            elseif ( $tk_months >= 3 )  $tk_class = 'rmbz-badge-ok';
                                            $tk_label = '📊 ' . date('M Y', $tk_ts);
                                            if ( $tk_months > 0 ) {
                                                $tk_label .= ' · há ' . $tk_months . ( $tk_months === 1 ? ' mês' : ' meses' );
                                            } else {
                                                $tk_label .= ' · recente';
                                            }
                                            echo '<span class="rmbz-badge ' . esc_attr($tk_class) . '" title="Último relatório de royalties recebido para esta faixa">' . esc_html($tk_label) . '</span>';
                                        } else {
                                            echo '<span class="rmbz-badge rmbz-badge-warning" title="Esta faixa nunca recebeu relatório de royalties">📊 Sem relatórios</span>';
                                        }
                                        ?>
                                        <?php if ( $t->is_explicit ): ?>
                                            <span class="rmbz-badge rmbz-badge-explicit">🔞 Explícito</span>
                                        <?php endif; ?>
                                        <?php if ( $has_sw ): ?>
                                            <span class="rmbz-badge rmbz-badge-ok">✓ Songwriters</span>
                                        <?php else: ?>
                                            <span class="rmbz-badge rmbz-badge-warning">⚠ Sem songwriters</span>
                                        <?php endif; ?>
                                        <?php if ( $splits_count > 0 ): ?>
                                            <a href="#splits-<?php echo (int) $t->id; ?>" class="rmbz-badge rmbz-badge-info" style="text-decoration:none; cursor:pointer;" onclick="event.preventDefault(); var p=document.getElementById('splits-<?php echo (int) $t->id; ?>'); if(p){p.style.display='block'; p.scrollIntoView({behavior:'smooth',block:'center'});}">🤝 <?php echo $splits_count; ?> split(s) — ver</a>
                                        <?php endif; ?>
                                    </div>
                                </div>
                                <div class="rmbz-track-actions">
                                    <a href="<?php echo esc_url($t->audio_url); ?>" download
                                       class="button button-small"
                                       title="Descarregar ficheiro original">
                                        ⬇ Download
                                    </a>
                                </div>
                            </div>

                            <?php if ( ! empty($t->audio_url) ): ?>
                                <div class="rmbz-track-player">
                                    <audio controls preload="none"
                                           data-waveform-src="<?php echo esc_url($t->audio_url); ?>"
                                           data-waveform-id="wf-<?php echo (int) $t->id; ?>"
                                           style="width:100%;">
                                        <source src="<?php echo esc_url($t->audio_url); ?>">
                                        O seu browser não suporta o player de áudio.
                                    </audio>
                                    <div class="rmbz-waveform" id="wf-<?php echo (int) $t->id; ?>"
                                         data-audio="<?php echo esc_url($t->audio_url); ?>">
                                        <span class="rmbz-waveform-load">Carregar waveform</span>
                                    </div>
                                </div>
                            <?php endif; ?>

                            <?php if ( ! empty($audio_info) ): ?>
                                <div class="rmbz-track-techinfo">
                                    <div class="ti-item">
                                        <span>Formato</span>
                                        <strong><?php echo strtoupper(esc_html($audio_info['format'] ?? '—')); ?></strong>
                                    </div>
                                    <div class="ti-item">
                                        <span>Bitrate</span>
                                        <strong><?php echo esc_html( isset($audio_info['bitrate_kbps']) ? rmbz_fmt_bitrate($audio_info['bitrate_kbps']) : '—' ); ?></strong>
                                    </div>
                                    <div class="ti-item">
                                        <span>Sample rate</span>
                                        <strong><?php echo esc_html( ($audio_info['sample_rate_hz'] ?? 0) > 0 ? (number_format($audio_info['sample_rate_hz']/1000, 1) . ' kHz') : '—' ); ?></strong>
                                    </div>
                                    <?php if ( ! empty($audio_info['bit_depth']) ): ?>
                                    <div class="ti-item">
                                        <span>Bit depth</span>
                                        <strong><?php echo (int) $audio_info['bit_depth']; ?>-bit</strong>
                                    </div>
                                    <?php endif; ?>
                                    <div class="ti-item">
                                        <span>Canais</span>
                                        <strong><?php echo (int) ($audio_info['channels'] ?? 0) === 2 ? 'Estéreo' : ((int) ($audio_info['channels'] ?? 0) === 1 ? 'Mono' : '—'); ?></strong>
                                    </div>
                                    <?php if ( ! empty($audio_info['file_size_pretty']) ): ?>
                                    <div class="ti-item">
                                        <span>Tamanho</span>
                                        <strong><?php echo esc_html($audio_info['file_size_pretty']); ?></strong>
                                    </div>
                                    <?php elseif ( ! empty($audio_info['file_size_bytes']) ): ?>
                                    <div class="ti-item">
                                        <span>Tamanho</span>
                                        <strong><?php echo esc_html( size_format($audio_info['file_size_bytes']) ); ?></strong>
                                    </div>
                                    <?php endif; ?>
                                </div>
                            <?php endif; ?>

                            <?php
                            // [1.5.211] Painel de detecção de plágio.
                            // Aparece para cada faixa com áudio. Análise on-demand
                            // (não corre automaticamente — admin clica para iniciar).
                            if ( function_exists('rmbz_fp_render_track_panel') ) {
                                rmbz_fp_render_track_panel( (int) $t->id );
                            }
                            ?>

                            <?php
                            // Painel de splits — mostra lista completa e permite ao admin editar.
                            // Sempre visível se houver splits; escondido por defeito se não houver
                            // (mas link "ver" no topo abre).
                            if ( function_exists('rmbz_splits_admin_render_panel') ) {
                                $splits_open = $splits_count > 0 ? '' : ' style="display:none;"';
                                echo '<div id="splits-' . (int) $t->id . '"' . $splits_open . '>';
                                rmbz_splits_admin_render_panel( $t );
                                echo '</div>';
                            }
                            ?>
                        </div>
                    <?php endforeach; ?>
                    </div>

                    <style>
                    .rmbz-admin-tracks { display: flex; flex-direction: column; gap: 12px; }
                    .rmbz-track-card { background: #fafafa; border: 1px solid #e0e0e0; border-radius: 6px; padding: 12px 14px; }
                    .rmbz-track-head { display: flex; align-items: flex-start; gap: 12px; }
                    .rmbz-track-num { width: 28px; height: 28px; background: var(--rmbz-bg-elevated, #333); color: var(--rmbz-text-on-color, #fff); border-radius: 4px; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 12px; flex-shrink: 0; }
                    .rmbz-track-meta { flex: 1; min-width: 0; }
                    .rmbz-track-meta strong { font-size: 14px; display: block; }
                    .rmbz-track-feats { font-size: 11px; color: var(--rmbz-text-muted, #666); margin-top: 2px; }
                    .rmbz-track-badges { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 8px; }
                    .rmbz-track-actions { flex-shrink: 0; }

                    .rmbz-badge { display: inline-block; padding: 2px 8px; border-radius: 10px; font-size: 10px; font-weight: 600; white-space: nowrap; }
                    .rmbz-badge-excellent { background: #d4edda; color: var(--rmbz-success-strong, #166534); }
                    .rmbz-badge-good      { background: #cfe2ff; color: #084298; }
                    .rmbz-badge-ok        { background: #e2e3e5; color: #383d41; }
                    .rmbz-badge-warning   { background: #fff3cd; color: #856404; }
                    .rmbz-badge-info      { background: #cff4fc; color: #055160; }
                    .rmbz-badge-neutral   { background: #e9ecef; color: #495057; }
                    .rmbz-badge-code      { background: var(--rmbz-bg-elevated, #333); color: var(--rmbz-text-on-color, #fff); font-family: monospace; letter-spacing: 0.3px; }
                    .rmbz-badge-explicit  { background: #f8d7da; color: var(--rmbz-danger-strong, #721c24); }

                    .rmbz-track-player { margin-top: 10px; }
                    .rmbz-track-player audio { display: block; height: 34px; border-radius: 4px; }
                    .rmbz-waveform { margin-top: 8px; height: 60px; background: #f0f0f0; border-radius: 4px; position: relative; cursor: pointer; overflow: hidden; }
                    .rmbz-waveform-load { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); font-size: 11px; color: #999; pointer-events: none; }
                    .rmbz-waveform canvas { display: block; width: 100%; height: 100%; }

                    .rmbz-track-techinfo { margin-top: 10px; display: grid; grid-template-columns: repeat(auto-fit, minmax(100px, 1fr)); gap: 8px; padding: 8px; background: var(--rmbz-bg-card, #fff); border: 1px solid #e5e5e5; border-radius: 4px; }
                    .ti-item { display: flex; flex-direction: column; text-align: center; }
                    .ti-item span { font-size: 10px; color: var(--rmbz-text-faint, #888); text-transform: uppercase; letter-spacing: 0.3px; margin-bottom: 2px; }
                    .ti-item strong { font-size: 13px; color: var(--rmbz-text-strong, #222); }
                    </style>

                    <script>
                    (function() {
                        var canvasCache = {};
                        async function drawWaveform(wfEl) {
                            if (canvasCache[wfEl.id]) return;
                            canvasCache[wfEl.id] = true;
                            var load = wfEl.querySelector('.rmbz-waveform-load');
                            if (load) load.innerText = 'A carregar...';

                            try {
                                var res = await fetch(wfEl.dataset.audio);
                                if (!res.ok) throw new Error('Download falhou');
                                var arrayBuf = await res.arrayBuffer();
                                var AudioCtx = window.AudioContext || window.webkitAudioContext;
                                if (!AudioCtx) throw new Error('Browser não suporta AudioContext');
                                var ctx = new AudioCtx();
                                var buf = await ctx.decodeAudioData(arrayBuf);

                                var canvas = document.createElement('canvas');
                                wfEl.innerHTML = '';
                                wfEl.appendChild(canvas);
                                canvas.width = wfEl.offsetWidth * 2;
                                canvas.height = 60 * 2;
                                var c = canvas.getContext('2d');
                                var data = buf.getChannelData(0);
                                var step = Math.ceil(data.length / canvas.width);
                                var amp = canvas.height / 2;
                                c.fillStyle = '#f0f0f0';
                                c.fillRect(0, 0, canvas.width, canvas.height);
                                c.strokeStyle = '#3498db';
                                c.lineWidth = 1;
                                c.beginPath();
                                for (var i = 0; i < canvas.width; i++) {
                                    var min = 1.0, max = -1.0;
                                    for (var j = 0; j < step; j++) {
                                        var v = data[i * step + j];
                                        if (v < min) min = v;
                                        if (v > max) max = v;
                                    }
                                    c.moveTo(i, (1 + min) * amp);
                                    c.lineTo(i, (1 + max) * amp);
                                }
                                c.stroke();

                                // Detectar clipping (amostras em ±1.0)
                                var clipped = 0;
                                for (var k = 0; k < data.length; k++) {
                                    if (data[k] >= 0.99 || data[k] <= -0.99) clipped++;
                                }
                                var clipRatio = clipped / data.length;
                                if (clipRatio > 0.001) {
                                    var warn = document.createElement('div');
                                    warn.style.cssText = 'position:absolute;top:4px;right:6px;font-size:10px;font-weight:700;color:var(--rmbz-text-on-color, #fff);background:var(--rmbz-danger, #ef4444);padding:2px 6px;border-radius:3px;';
                                    warn.innerText = '⚠ Clipping ' + (clipRatio * 100).toFixed(2) + '%';
                                    wfEl.appendChild(warn);
                                }

                                ctx.close();
                            } catch (err) {
                                wfEl.innerHTML = '<span class="rmbz-waveform-load" style="color:var(--rmbz-danger, #ef4444);">Erro: ' + err.message + '</span>';
                                canvasCache[wfEl.id] = false;
                            }
                        }

                        document.querySelectorAll('.rmbz-waveform').forEach(function(el) {
                            el.addEventListener('click', function() { drawWaveform(el); });
                        });
                    })();
                    </script>
                <?php endif; ?>
            </div>

            <?php if ( $platforms ): ?>
                <div class="rmbz-section">
                    <h3>🌍 Distribuição</h3>
                    <table style="width:100%; font-size:13px;">
                        <?php
                        $mode_labels = [
                            'worldwide' => 'Mundo inteiro',
                            'worldwide_except' => 'Mundo excepto ' . count($platforms->_territory_list) . ' país(es)',
                            'selected' => count($platforms->_territory_list) . ' país(es) seleccionado(s)',
                        ];
                        $mode = $platforms->territory_mode ?? 'worldwide';
                        ?>
                        <tr><td style="color:var(--rmbz-text-muted, #666); width:180px;">Territórios</td><td><strong><?php echo esc_html($mode_labels[$mode] ?? $mode); ?></strong></td></tr>
                        <tr><td style="color:var(--rmbz-text-muted, #666);">Plataformas (DSPs)</td><td>
                            <?php
                            $dsps = $platforms->_dsp_list ?? [];
                            $catalog = function_exists('rmbz_distro_dsp_catalog') ? rmbz_distro_dsp_catalog() : [];
                            $total_catalog = count($catalog);
                            echo '<strong>' . count($dsps) . ' de ' . $total_catalog . ' lojas seleccionadas</strong>';

                            if ( ! empty($dsps) ) {
                                /* [1.5.163] Mostrar com logos SVG quando disponíveis,
                                   fallback para texto se módulo não carregar. */
                                if ( function_exists('rmbz_service_logo') ) {
                                    echo '<div style="display:flex; flex-wrap:wrap; gap:8px; margin-top:8px;">';
                                    foreach ( $dsps as $slug ) {
                                        $name = $catalog[$slug]['name'] ?? $slug;
                                        echo '<span style="display:inline-flex; align-items:center; gap:6px; background:#f0f0f1; border-radius:4px; padding:4px 8px; font-size:12px;" title="' . esc_attr($name) . '">';
                                        echo rmbz_service_logo( $slug, ['size' => 18] );
                                        echo '<span>' . esc_html($name) . '</span>';
                                        echo '</span>';
                                    }
                                    echo '</div>';
                                } else {
                                    // Fallback texto plano
                                    $names = [];
                                    foreach ( $dsps as $slug ) {
                                        $names[] = $catalog[$slug]['name'] ?? $slug;
                                    }
                                    echo '<div style="font-size:12px; color:var(--rmbz-text-primary, #444); margin-top:6px; line-height:1.6;">';
                                    echo esc_html( implode(' · ', $names) );
                                    echo '</div>';
                                }
                            }

                            // Botão para abrir o editor (só aparece se a função existir)
                            if ( function_exists('rmbz_admin_render_dsp_override_panel') ) {
                                echo '<div style="margin-top:8px;">';
                                echo '<button type="button" class="button button-small" onclick="document.getElementById(\'rmbz-dsp-override-block\').style.display=\'block\'; this.style.display=\'none\'; this.scrollIntoView({behavior:\'smooth\'});">✏️ Editar lista de lojas</button>';
                                echo '</div>';
                            }
                            ?>
                        </td></tr>
                        <tr><td style="color:var(--rmbz-text-muted, #666);">YouTube Content ID</td><td><?php echo rmbz_exclusive_pill($platforms->yt_content_id_status ?? 'not_requested'); ?></td></tr>
                        <tr><td style="color:var(--rmbz-text-muted, #666);">Facebook/IG Monetization</td><td><?php echo rmbz_exclusive_pill($platforms->fb_monet_status ?? 'not_requested'); ?></td></tr>
                        <tr><td style="color:var(--rmbz-text-muted, #666);">TikTok Monetization</td><td><?php echo rmbz_exclusive_pill($platforms->tt_monet_status ?? 'not_requested'); ?></td></tr>
                    </table>

                    <?php
                    // Painel de edição de DSPs — escondido até o admin clicar em "Editar lista de lojas"
                    if ( function_exists('rmbz_admin_render_dsp_override_panel') ) {
                        echo '<div id="rmbz-dsp-override-block" style="display:none; margin-top:16px;">';
                        rmbz_admin_render_dsp_override_panel( $release, $platforms );
                        echo '</div>';
                    }
                    ?>
                </div>
            <?php endif; ?>

            <?php
            // ════════════════════════════════════════════════════════════════
            // SECÇÃO — PERFORMANCE REAL (estatísticas de streams + receita)
            //
            // Só aparece se já houver linhas em rmbz_distro_daily_stats para
            // este release_id. Antes da música começar a gerar dinheiro,
            // a secção fica simplesmente escondida.
            //
            // Defensivo:
            //   - tabela pode não existir (instalação parcial)
            //   - coluna pending_approval pode não existir (esquema antigo)
            //   - sales pode ser NULL → COALESCE
            //
            // Mostramos: 4 KPIs no topo + 2 tabelas top10 (lojas + países)
            // + 1 tabela do desempenho por faixa (se o release tem >1 track).
            // ════════════════════════════════════════════════════════════════
            $t_stats = $wpdb->prefix . 'rmbz_distro_daily_stats';
            $perf_data = null;
            if ( $wpdb->get_var("SHOW TABLES LIKE '$t_stats'") === $t_stats ) {
                $stats_cols = (array) $wpdb->get_col("SHOW COLUMNS FROM $t_stats");
                $has_pending = in_array('pending_approval', $stats_cols, true);
                // Filtro: só conta linhas aprovadas (se a coluna existir)
                $approved_clause = $has_pending ? " AND pending_approval = 0" : "";

                // KPIs globais do release
                $kpis = $wpdb->get_row( $wpdb->prepare(
                    "SELECT
                        COALESCE(SUM(streams), 0)                      AS total_streams,
                        COALESCE(SUM(sales),   0)                      AS total_sales,
                        COUNT(DISTINCT country_code)                   AS total_countries,
                        COUNT(DISTINCT store)                          AS total_stores,
                        MIN(report_date)                               AS first_date,
                        MAX(report_date)                               AS last_date
                     FROM $t_stats
                     WHERE release_id = %d $approved_clause",
                    $release->id
                ) );

                if ( $kpis && (int) $kpis->total_streams > 0 ) {
                    // Top lojas
                    $top_stores = $wpdb->get_results( $wpdb->prepare(
                        "SELECT store,
                                SUM(streams) AS streams,
                                SUM(sales)   AS sales
                         FROM $t_stats
                         WHERE release_id = %d $approved_clause
                         GROUP BY store
                         ORDER BY sales DESC, streams DESC
                         LIMIT 10",
                        $release->id
                    ) );
                    // Top países
                    $top_countries = $wpdb->get_results( $wpdb->prepare(
                        "SELECT country_code,
                                SUM(streams) AS streams,
                                SUM(sales)   AS sales
                         FROM $t_stats
                         WHERE release_id = %d $approved_clause
                         GROUP BY country_code
                         ORDER BY sales DESC, streams DESC
                         LIMIT 10",
                        $release->id
                    ) );
                    // Performance por faixa (útil se release tem >1 track)
                    $by_track = [];
                    if ( count($tracks) > 1 ) {
                        $by_track = $wpdb->get_results( $wpdb->prepare(
                            "SELECT s.track_id,
                                    SUM(s.streams) AS streams,
                                    SUM(s.sales)   AS sales,
                                    t.track_title
                             FROM $t_stats s
                             LEFT JOIN {$wpdb->prefix}rmbz_distro_tracks t ON s.track_id = t.id
                             WHERE s.release_id = %d $approved_clause
                             GROUP BY s.track_id
                             ORDER BY sales DESC, streams DESC",
                            $release->id
                        ) );
                    }

                    $perf_data = [
                        'kpis'          => $kpis,
                        'top_stores'    => $top_stores,
                        'top_countries' => $top_countries,
                        'by_track'      => $by_track,
                    ];
                }
            }
            ?>

            <?php if ( $perf_data ):
                // Normaliza o nome livre da loja (vindo do CSV) para o slug do logo.
                $store_slug = function( $name ) {
                    $n = strtolower( trim( (string) $name ) );
                    $n = str_replace( [' ', '-'], '_', $n );
                    $map = [
                        'youtube_premium' => 'youtube', 'youtube_ads' => 'youtube',
                        'youtube_music' => 'youtube_music', 'yt_music' => 'youtube_music',
                        'tiktok_monetization' => 'tiktok', 'tiktok_music' => 'tiktok',
                        'facebook' => 'meta', 'instagram' => 'meta', 'fb' => 'meta', 'facebook_instagram' => 'meta',
                        'apple' => 'apple_music', 'itunes' => 'apple_music',
                        'amazon' => 'amazon_music', 'amazon_unlimited' => 'amazon_music',
                    ];
                    return $map[ $n ] ?? $n;
                };
                // Receita máxima para normalizar as barras de proporção.
                $st_max = 0.0; foreach ( $perf_data['top_stores'] as $s ) $st_max = max( $st_max, (float) $s->sales, (int) $s->streams );
                $ct_max = 0.0; foreach ( $perf_data['top_countries'] as $c ) $ct_max = max( $ct_max, (float) $c->sales, (int) $c->streams );
            ?>
                <div class="rmbz-section rmbz-perf">
                    <h3>📈 Performance Real <small>(de <?php echo esc_html(date('d/m/Y', strtotime($perf_data['kpis']->first_date))); ?> a <?php echo esc_html(date('d/m/Y', strtotime($perf_data['kpis']->last_date))); ?>)</small></h3>

                    <!-- KPIs -->
                    <div class="rmbz-perf-kpis">
                        <div class="rmbz-perf-kpi green">
                            <span class="ico">💰</span>
                            <span class="lbl">Receita</span>
                            <span class="val">$<?php echo number_format( (float) $perf_data['kpis']->total_sales, 2 ); ?></span>
                        </div>
                        <div class="rmbz-perf-kpi blue">
                            <span class="ico">📈</span>
                            <span class="lbl">Streams</span>
                            <span class="val"><?php echo number_format( (int) $perf_data['kpis']->total_streams ); ?></span>
                        </div>
                        <div class="rmbz-perf-kpi amber">
                            <span class="ico">🌍</span>
                            <span class="lbl">Países</span>
                            <span class="val"><?php echo (int) $perf_data['kpis']->total_countries; ?></span>
                        </div>
                        <div class="rmbz-perf-kpi purple">
                            <span class="ico">🏪</span>
                            <span class="lbl">Lojas activas</span>
                            <span class="val"><?php echo (int) $perf_data['kpis']->total_stores; ?></span>
                        </div>
                    </div>

                    <div class="rmbz-perf-cols">
                        <!-- Top Lojas -->
                        <div class="rmbz-perf-block">
                            <h4>🏪 Top lojas <small>por receita</small></h4>
                            <div class="rmbz-perf-list">
                                <?php foreach ( $perf_data['top_stores'] as $i => $s ):
                                    $slug = $store_slug( $s->store );
                                    $color = function_exists('rmbz_service_logo_color') ? rmbz_service_logo_color( rmbz_service_logo_resolve($slug) ) : '#6356E5';
                                    $w = $st_max > 0 ? max( 3, round( (float)$s->sales > 0 ? (float)$s->sales/$st_max*100 : (int)$s->streams/$st_max*100 ) ) : 0;
                                ?>
                                    <div class="rmbz-perf-row" style="animation-delay: <?php echo $i*45; ?>ms;">
                                        <span class="rmbz-perf-logo">
                                            <?php echo function_exists('rmbz_service_logo') ? rmbz_service_logo( $slug, ['size' => 22] ) : '🏪'; ?>
                                        </span>
                                        <span class="rmbz-perf-rowbody">
                                            <span class="rmbz-perf-name"><?php echo esc_html($s->store); ?></span>
                                            <span class="rmbz-perf-track"><span class="rmbz-perf-fill" style="width: <?php echo $w; ?>%; background: <?php echo esc_attr($color); ?>;"></span></span>
                                        </span>
                                        <span class="rmbz-perf-nums">
                                            <span class="rmbz-perf-money">$<?php echo number_format( (float) $s->sales, 2 ); ?></span>
                                            <span class="rmbz-perf-streams"><?php echo number_format( (int) $s->streams ); ?> streams</span>
                                        </span>
                                    </div>
                                <?php endforeach; ?>
                            </div>
                        </div>

                        <!-- Top Países -->
                        <div class="rmbz-perf-block">
                            <h4>🌍 Top países <small>por receita</small></h4>
                            <div class="rmbz-perf-list">
                                <?php foreach ( $perf_data['top_countries'] as $i => $c ):
                                    $cc = strtoupper( trim( (string) $c->country_code ) );
                                    $cc_lower = strtolower( $cc );
                                    $cname = function_exists('rmbz_country_name_pt') ? rmbz_country_name_pt( $cc ) : $cc;
                                    $w = $ct_max > 0 ? max( 3, round( (float)$c->sales > 0 ? (float)$c->sales/$ct_max*100 : (int)$c->streams/$ct_max*100 ) ) : 0;
                                ?>
                                    <div class="rmbz-perf-row" style="animation-delay: <?php echo $i*45; ?>ms;">
                                        <span class="rmbz-perf-flag">
                                            <?php if ( strlen($cc_lower) === 2 && ctype_alpha($cc_lower) ): ?>
                                                <img src="https://flagcdn.com/32x24/<?php echo esc_attr($cc_lower); ?>.png" alt="<?php echo esc_attr($cc); ?>" loading="lazy" onerror="this.replaceWith(document.createTextNode('🌍'));">
                                            <?php else: ?>🌍<?php endif; ?>
                                        </span>
                                        <span class="rmbz-perf-rowbody">
                                            <span class="rmbz-perf-name"><?php echo esc_html($cname); ?> <small><?php echo esc_html($cc); ?></small></span>
                                            <span class="rmbz-perf-track"><span class="rmbz-perf-fill" style="width: <?php echo $w; ?>%; background: #6356E5;"></span></span>
                                        </span>
                                        <span class="rmbz-perf-nums">
                                            <span class="rmbz-perf-money">$<?php echo number_format( (float) $c->sales, 2 ); ?></span>
                                            <span class="rmbz-perf-streams"><?php echo number_format( (int) $c->streams ); ?> streams</span>
                                        </span>
                                    </div>
                                <?php endforeach; ?>
                            </div>
                        </div>
                    </div>

                    <?php if ( ! empty($perf_data['by_track']) ): ?>
                        <div class="rmbz-perf-block" style="margin-top:18px;">
                            <h4>🎵 Performance por faixa</h4>
                            <div class="rmbz-perf-list">
                                <?php foreach ( $perf_data['by_track'] as $i => $bt ): ?>
                                    <div class="rmbz-perf-row" style="animation-delay: <?php echo $i*45; ?>ms;">
                                        <span class="rmbz-perf-tracknum"><?php echo $i + 1; ?></span>
                                        <span class="rmbz-perf-rowbody">
                                            <span class="rmbz-perf-name"><?php echo esc_html($bt->track_title ?: '(faixa #' . (int) $bt->track_id . ')'); ?></span>
                                        </span>
                                        <span class="rmbz-perf-nums">
                                            <span class="rmbz-perf-money">$<?php echo number_format( (float) $bt->sales, 2 ); ?></span>
                                            <span class="rmbz-perf-streams"><?php echo number_format( (int) $bt->streams ); ?> streams</span>
                                        </span>
                                    </div>
                                <?php endforeach; ?>
                            </div>
                        </div>
                    <?php endif; ?>

                    <p class="rmbz-perf-note">
                        ℹ Dados de <code>rmbz_distro_daily_stats</code> (apenas linhas aprovadas).
                        Lojas/países sem valor ainda não receberam reports dessa região/plataforma.
                    </p>
                </div>

                <style>
                .rmbz-perf h3 small { color: #9aa1ad; font-weight: normal; font-size: 12px; }
                .rmbz-perf-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 12px; margin-bottom: 20px; }
                .rmbz-perf-kpi { position: relative; display: flex; flex-direction: column; gap: 2px; padding: 14px 16px; border-radius: 16px; overflow: hidden; border: 1px solid; animation: rmbz-perf-rise .5s cubic-bezier(.4,0,.2,1) both; }
                @keyframes rmbz-perf-rise { from { opacity:0; transform: translateY(10px); } to { opacity:1; transform:none; } }
                .rmbz-perf-kpi .ico { font-size: 20px; }
                .rmbz-perf-kpi .lbl { font-size: 10px; text-transform: uppercase; letter-spacing: .05em; font-weight: 700; color: #6b7280; margin-top: 6px; }
                .rmbz-perf-kpi .val { font-size: 26px; font-weight: 900; line-height: 1.05; font-variant-numeric: tabular-nums; }
                .rmbz-perf-kpi.green  { background: #ecfdf3; border-color: #abefc6; } .rmbz-perf-kpi.green .val  { color: #08653a; }
                .rmbz-perf-kpi.blue   { background: #eff8ff; border-color: #b2ddff; } .rmbz-perf-kpi.blue .val   { color: #0b4a8f; }
                .rmbz-perf-kpi.amber  { background: #fffaeb; border-color: #fde29a; } .rmbz-perf-kpi.amber .val  { color: #b54708; }
                .rmbz-perf-kpi.purple { background: #f4f3ff; border-color: #d9d6fe; } .rmbz-perf-kpi.purple .val { color: #5925dc; }

                .rmbz-perf-cols { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
                @media (max-width: 880px) { .rmbz-perf-cols { grid-template-columns: 1fr; } }
                .rmbz-perf-block h4 { margin: 0 0 12px; font-size: 13px; font-weight: 800; color: #16181d; }
                .rmbz-perf-block h4 small { font-weight: 500; color: #9aa1ad; font-size: 11px; }
                .rmbz-perf-list { display: flex; flex-direction: column; gap: 4px; }
                .rmbz-perf-row {
                    display: grid; grid-template-columns: 32px 1fr auto; gap: 12px; align-items: center;
                    padding: 8px 10px; border-radius: 12px; transition: background .15s;
                    animation: rmbz-perf-rise .45s cubic-bezier(.4,0,.2,1) both;
                }
                .rmbz-perf-row:hover { background: #f7f8fa; }
                .rmbz-perf-logo, .rmbz-perf-flag { display: flex; align-items: center; justify-content: center; width: 32px; height: 32px; }
                .rmbz-perf-logo svg, .rmbz-perf-logo img { width: 22px; height: 22px; border-radius: 5px; }
                .rmbz-perf-flag img { width: 28px; height: 21px; border-radius: 3px; box-shadow: 0 1px 3px rgba(0,0,0,.18); object-fit: cover; }
                .rmbz-perf-flag { font-size: 20px; }
                .rmbz-perf-tracknum { display:flex; align-items:center; justify-content:center; width:28px; height:28px; border-radius:8px; background: linear-gradient(135deg,#E37A26,#c4621a); color:#fff; font-size:12px; font-weight:800; }
                .rmbz-perf-rowbody { min-width: 0; }
                .rmbz-perf-name { display: block; font-size: 13px; font-weight: 600; color: #16181d; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
                .rmbz-perf-name small { color: #9aa1ad; font-weight: 500; font-size: 11px; }
                .rmbz-perf-track { display: block; height: 6px; background: #eef0f3; border-radius: 999px; overflow: hidden; margin-top: 5px; }
                .rmbz-perf-fill { display: block; height: 100%; border-radius: 999px; transform-origin: left; animation: rmbz-perf-fill .6s cubic-bezier(.4,0,.2,1) both; }
                @keyframes rmbz-perf-fill { from { transform: scaleX(0); } to { transform: scaleX(1); } }
                .rmbz-perf-nums { text-align: right; white-space: nowrap; }
                .rmbz-perf-money { display: block; font-size: 13px; font-weight: 800; color: #08653a; font-variant-numeric: tabular-nums; }
                .rmbz-perf-streams { display: block; font-size: 10.5px; color: #9aa1ad; font-variant-numeric: tabular-nums; }
                .rmbz-perf-note { margin-top: 14px; font-size: 11px; color: #9aa1ad; }
                .rmbz-perf-note code { background: #f1f3f5; padding: 1px 5px; border-radius: 4px; }
                </style>
            <?php endif; ?>

            <div class="rmbz-section">
                <h3>📋 Histórico de estado</h3>
                <?php if ( empty($history) ): ?>
                    <p style="color:var(--rmbz-text-faint, #888);">Sem transições registadas.</p>
                <?php else: ?>
                    <div style="max-height:220px; overflow-y:auto;">
                        <?php foreach ( $history as $h ): ?>
                            <div style="padding:8px; border-bottom:1px solid #eee; display:flex; justify-content:space-between; font-size:12px;">
                                <div>
                                    <strong><?php echo esc_html($h->from_status ?: 'criação'); ?> → <?php echo esc_html($h->to_status); ?></strong>
                                    <?php if ( ! empty($h->reason_text) ): ?>
                                        <div style="color:var(--rmbz-text-muted, #666); font-size:11px; margin-top:2px;"><?php echo esc_html($h->reason_text); ?></div>
                                    <?php endif; ?>
                                </div>
                                <div style="color:var(--rmbz-text-faint, #888); text-align:right; white-space:nowrap;">
                                    <?php echo esc_html( date('d/m/Y H:i', strtotime($h->created_at)) ); ?><br>
                                    <small>por <?php echo esc_html($h->changed_by ?: 'sistema'); ?></small>
                                </div>
                            </div>
                        <?php endforeach; ?>
                    </div>
                <?php endif; ?>
            </div>
        </div>
    </div>

    <?php /* [1.5.192] CSS + JS para edição inline de ISRC */ ?>
    <style>
    .rmbz-isrc-edit-wrap { display:inline-flex; align-items:center; gap:6px; }
    .rmbz-isrc-input {
        font-family: monospace; font-size:11px;
        padding: 3px 8px; border-radius: 4px;
        border: 1px solid var(--wp-admin-theme-color, #2271b1);
        background: #fff; color: var(--wp-components-color-foreground, #1d2327);
        max-width: 200px; outline: none;
        text-transform: uppercase;
    }
    .rmbz-isrc-input:focus {
        border-color: var(--wp-admin-theme-color-darker-10, #135e96); box-shadow: 0 0 0 2px rgba(34,113,177,0.15);
    }
    .rmbz-isrc-input.rmbz-isrc-input-invalid {
        border-color: #d63638; background: #fef3f2;
    }
    .rmbz-isrc-status {
        font-size: 10px; padding: 2px 6px; border-radius: 3px;
    }
    .rmbz-isrc-status.is-saving { background: #fffbeb; color: #854d0e; }
    .rmbz-isrc-status.is-success { background: #ecfdf5; color: #065f46; }
    .rmbz-isrc-status.is-error { background: #fef2f2; color: #991b1b; }
    </style>
    <script>
    (function() {
        var ajaxUrl = '<?php echo esc_js( admin_url('admin-ajax.php') ); ?>';

        // Validar formato ISRC.
        // [1.5.193] Versão simplificada — apenas exigir:
        //   - 12 caracteres alfanuméricos
        //   - 2 primeiros são letras (código de país, sempre)
        //   - resto pode ser letras ou dígitos (alguns distribuidores usam
        //     formatos com letras no ano ou na designação)
        // ISRC standard rigoroso seria: CC + XYZ + YY + NNNNN. Mas vimos
        // que distribuidores reais (ex: Amadea) podem variar este formato.
        // Melhor permissivo aqui e deixar o admin julgar correcção.
        function normalizeIsrc(raw) {
            return String(raw || '').toUpperCase().replace(/[^A-Z0-9]/g, '');
        }
        function isValidIsrc(normalized) {
            // Permitir vazio (limpar) ou 12 chars válidos
            if (normalized === '') return true;
            if (normalized.length !== 12) return false;
            // 2 letras (país) + 10 alfanum (resto)
            return /^[A-Z]{2}[A-Z0-9]{10}$/.test(normalized);
        }

        // Click no display → entrar em edit mode
        document.querySelectorAll('.rmbz-isrc-edit-wrap').forEach(function(wrap) {
            if (wrap.getAttribute('data-locked') === '1') return;

            var display = wrap.querySelector('.rmbz-isrc-display');
            var input = wrap.querySelector('.rmbz-isrc-input');
            var status = wrap.querySelector('.rmbz-isrc-status');
            var trackId = wrap.getAttribute('data-track-id');
            var nonce = wrap.getAttribute('data-nonce');
            if (!display || !input) return;

            var originalValue = input.value;

            display.addEventListener('click', function() {
                display.style.display = 'none';
                input.style.display = '';
                input.focus();
                input.select();
            });

            input.addEventListener('keydown', function(e) {
                if (e.key === 'Enter') {
                    e.preventDefault();
                    saveIsrc();
                } else if (e.key === 'Escape') {
                    e.preventDefault();
                    cancelEdit();
                }
            });

            // [1.5.194] Mostrar contador de chars normalizados em tempo real
            // Ajuda admin a ver se ISRC está completo (precisa 12 chars válidos).
            input.addEventListener('input', function() {
                var n = normalizeIsrc(input.value);
                var len = n.length;
                if (status) {
                    if (len === 0) {
                        status.style.display = 'none';
                    } else if (len < 12) {
                        showStatus('saving', '⚠ ' + len + '/12 chars (faltam ' + (12 - len) + ')');
                    } else if (len === 12) {
                        if (isValidIsrc(n)) {
                            showStatus('success', '✓ 12/12 chars válido');
                        } else {
                            showStatus('error', '✗ 12 chars mas formato inválido');
                        }
                    } else {
                        showStatus('error', '✗ ' + len + '/12 chars (excede em ' + (len - 12) + ')');
                    }
                }
                // Limpar mensagem de inválido se voltar a um estado válido
                if (isValidIsrc(n)) input.classList.remove('rmbz-isrc-input-invalid');
            });

            input.addEventListener('blur', function() {
                // Pequeno delay para não interferir se o utilizador clicou Enter
                setTimeout(function() {
                    if (input.style.display === '' && document.activeElement !== input) {
                        // Se o valor mudou mas blur sem Enter, gravar mesmo assim
                        if (normalizeIsrc(input.value) !== normalizeIsrc(originalValue)) {
                            saveIsrc();
                        } else {
                            cancelEdit();
                        }
                    }
                }, 100);
            });

            function cancelEdit() {
                input.value = originalValue;
                input.style.display = 'none';
                input.classList.remove('rmbz-isrc-input-invalid');
                status.style.display = 'none';
                display.style.display = '';
            }

            function saveIsrc() {
                var newValue = normalizeIsrc(input.value);

                // Validar
                if (!isValidIsrc(newValue)) {
                    input.classList.add('rmbz-isrc-input-invalid');
                    showStatus('error', '✗ Formato inválido (precisa 12 chars: 2 letras país + 10 alfanum)');
                    input.focus();
                    return;
                }
                input.classList.remove('rmbz-isrc-input-invalid');

                // Sem mudança? Sair sem fazer nada
                if (newValue === normalizeIsrc(originalValue)) {
                    cancelEdit();
                    return;
                }

                showStatus('saving', '⏳ A guardar...');
                input.disabled = true;

                var fd = new FormData();
                fd.append('action', 'rmbz_track_isrc_save');
                fd.append('track_id', trackId);
                fd.append('isrc', newValue);
                fd.append('_nonce', nonce);

                fetch(ajaxUrl, { method: 'POST', body: fd, credentials: 'same-origin' })
                    .then(function(r) { return r.json(); })
                    .then(function(data) {
                        input.disabled = false;
                        if (data && data.success) {
                            // Actualizar display
                            originalValue = newValue;
                            input.value = newValue;
                            input.style.display = 'none';
                            display.style.display = '';
                            // Atualizar texto e classe do display
                            if (newValue) {
                                display.className = 'rmbz-badge rmbz-badge-code rmbz-isrc-display';
                                display.textContent = newValue + ' ✏️';
                                display.title = 'Click para editar';
                                display.style.cursor = 'pointer';
                            } else {
                                display.className = 'rmbz-badge rmbz-badge-warning rmbz-isrc-display';
                                display.textContent = 'ISRC pendente ✏️';
                            }
                            showStatus('success', '✓ Guardado');
                            setTimeout(function() { status.style.display = 'none'; }, 2000);
                        } else {
                            var msg = (data && data.data && data.data.msg) ? data.data.msg : 'Erro ao guardar';
                            showStatus('error', '✗ ' + msg);
                        }
                    })
                    .catch(function(err) {
                        input.disabled = false;
                        showStatus('error', '✗ Erro de rede');
                        console.error('[ISRC save]', err);
                    });
            }

            function showStatus(type, msg) {
                if (!status) return;
                status.style.display = '';
                status.className = 'rmbz-isrc-status is-' + type;
                status.textContent = msg;
            }
        });

        // [1.5.196] Edição inline de campos do RELEASE (título, data, género, etc).
        // Sistema genérico: cada wrap tem data-field que diz qual campo gravar.
        // Suporta input types: text (default), date, select.
        document.querySelectorAll('.rmbz-rel-edit-wrap').forEach(function(wrap) {
            if (wrap.getAttribute('data-locked') === '1') return;

            var display = wrap.querySelector('.rmbz-rel-display');
            var input = wrap.querySelector('.rmbz-rel-input');
            var status = wrap.querySelector('.rmbz-rel-status');
            var releaseId = wrap.getAttribute('data-release-id');
            var field = wrap.getAttribute('data-field');
            var nonce = wrap.getAttribute('data-nonce');
            var inputType = wrap.getAttribute('data-input-type') || 'text';
            if (!display || !input) return;

            var originalValue = input.value;

            display.addEventListener('click', function() {
                display.style.display = 'none';
                input.style.display = '';
                if (inputType !== 'select') input.focus();
                if (inputType === 'text') input.select();
            });

            // Para select: gravar imediatamente ao mudar
            if (inputType === 'select') {
                input.addEventListener('change', function() {
                    saveField();
                });
                input.addEventListener('blur', function() {
                    setTimeout(function() {
                        if (input.style.display !== 'none' && input.value === originalValue) {
                            cancelEdit();
                        }
                    }, 200);
                });
            } else {
                input.addEventListener('keydown', function(e) {
                    if (e.key === 'Enter') {
                        e.preventDefault();
                        saveField();
                    } else if (e.key === 'Escape') {
                        e.preventDefault();
                        cancelEdit();
                    }
                });
                input.addEventListener('blur', function() {
                    setTimeout(function() {
                        if (input.style.display !== 'none' && document.activeElement !== input) {
                            if (input.value !== originalValue) saveField();
                            else cancelEdit();
                        }
                    }, 100);
                });
            }

            function cancelEdit() {
                input.value = originalValue;
                input.style.display = 'none';
                if (status) status.style.display = 'none';
                display.style.display = '';
            }

            function saveField() {
                var newValue = input.value;
                if (newValue === originalValue) {
                    cancelEdit();
                    return;
                }

                showStatus('saving', '⏳');
                input.disabled = true;

                var fd = new FormData();
                fd.append('action', 'rmbz_release_field_save');
                fd.append('release_id', releaseId);
                fd.append('field', field);
                fd.append('value', newValue);
                fd.append('_nonce', nonce);

                fetch(ajaxUrl, { method: 'POST', body: fd, credentials: 'same-origin' })
                    .then(function(r) { return r.json(); })
                    .then(function(data) {
                        input.disabled = false;
                        if (data && data.success) {
                            originalValue = newValue;
                            input.style.display = 'none';
                            display.style.display = '';

                            // Actualizar texto do display
                            var displayText = (data.data && data.data.display_value) ? data.data.display_value : (newValue || '—');
                            // Adicionar de volta o ícone ✏️
                            display.innerHTML = displayText + ' <span style="font-size:11px; opacity:0.4;">✏️</span>';

                            showStatus('success', '✓');
                            setTimeout(function() { if (status) status.style.display = 'none'; }, 2000);
                        } else {
                            var msg = (data && data.data && data.data.msg) ? data.data.msg : 'Erro';
                            showStatus('error', '✗ ' + msg);
                            input.focus();
                        }
                    })
                    .catch(function(err) {
                        input.disabled = false;
                        showStatus('error', '✗ Erro de rede');
                        console.error('[Release field save]', err);
                    });
            }

            function showStatus(type, msg) {
                if (!status) return;
                status.style.display = '';
                status.className = 'rmbz-isrc-status is-' + type; // reutilizar classes do CSS ISRC
                status.style.marginLeft = '6px';
                status.textContent = msg;
            }
        });
    })();
    </script>
    </div><?php /* fecha .rmbz-rd2 */ ?>

    <?php
}

function rmbz_exclusive_pill( $status ) {
    $map = [
        'not_requested' => ['color:var(--rmbz-text-faint, #888);', '—'],
        'requested'     => ['background:#fff3cd; color:#856404; padding:2px 8px; border-radius:10px;', '⏳ Em revisão'],
        'approved'      => ['background:#d4edda; color:var(--rmbz-success-strong, #166534); padding:2px 8px; border-radius:10px;', '✓ Aprovado'],
        'rejected'      => ['background:#f8d7da; color:var(--rmbz-danger-strong, #721c24); padding:2px 8px; border-radius:10px;', '✗ Rejeitado'],
    ];
    $m = $map[ $status ] ?? $map['not_requested'];
    return '<span style="font-size:11px; font-weight:600; ' . esc_attr($m[0]) . '">' . esc_html($m[1]) . '</span>';
}


/* ============================================================================
 * [1.5.181] TAB 3 — Fila de Aprovação (REDESIGN COMPLETO)
 *
 * Melhorias vs versão anterior:
 *   - Agrupamento por artista (1 click aprova todos do mesmo artista)
 *   - Detector de avisos (capa pequena, metadata incompleta, sem ISRC, etc)
 *   - Indicador "aguarda há X dias" com cores graduais
 *   - Filtros: ordenação, género, tipo, idade, "só com problemas"
 *   - Bulk actions com checkboxes
 *   - Snackbar undo após cada acção
 *   - Botões modernos sem confirm() nativo
 * ============================================================================ */
function rmbz_admin_render_approval_queue() {
    global $wpdb;
    $t_releases = $wpdb->prefix . 'rmbz_distro_releases';
    $t_tracks   = $wpdb->prefix . 'rmbz_distro_tracks';
    $t_wallets  = $wpdb->prefix . 'rmbz_wallets';

    // ----- Filtros via URL -----
    $filter_sort      = isset($_GET['q_sort']) ? sanitize_key($_GET['q_sort']) : 'oldest';
    $filter_genre     = isset($_GET['q_genre']) ? sanitize_text_field($_GET['q_genre']) : '';
    $filter_type      = isset($_GET['q_type']) ? sanitize_key($_GET['q_type']) : '';
    $filter_age       = isset($_GET['q_age']) ? sanitize_key($_GET['q_age']) : '';
    $filter_warns     = isset($_GET['q_warns']) ? (bool) $_GET['q_warns'] : false;

    // ----- Query enriquecida -----
    // [1.5.181] Inclui contagem de tracks com ISRC válido e dimensões da capa
    // (se a tabela ter as colunas — fallback gracioso se não).
    $cols_t = $wpdb->get_col("SHOW COLUMNS FROM $t_tracks");
    $has_isrc_col = in_array('isrc_code', $cols_t, true);

    $isrc_subquery = $has_isrc_col
        ? "(SELECT COUNT(*) FROM $t_tracks t WHERE t.release_id = r.id AND t.isrc_code IS NOT NULL AND t.isrc_code != '') AS tracks_with_isrc,"
        : "0 AS tracks_with_isrc,";

    $where_extra = "r.status IN ('pendente','pending','submitted')";
    if ( $filter_type !== '' && in_array($filter_type, ['single','ep','album'], true) ) {
        $where_extra .= $wpdb->prepare(" AND r.release_type = %s", $filter_type);
    }
    if ( $filter_genre !== '' ) {
        $where_extra .= $wpdb->prepare(" AND r.primary_genre = %s", $filter_genre);
    }

    $sql = "SELECT r.*, w.user_nome AS artist_name,
                   (SELECT COUNT(*) FROM $t_tracks t WHERE t.release_id = r.id) AS tracks_count,
                   $isrc_subquery
                   COALESCE(r.submitted_at, r.created_at) AS effective_submitted
            FROM $t_releases r
            LEFT JOIN $t_wallets w ON r.artist_telemovel = w.user_telemovel
            WHERE $where_extra
            ORDER BY effective_submitted ASC, r.id ASC";

    $pending = $wpdb->get_results( $sql );

    // ----- Mensagens -----
    if ( ! empty($_GET['msg']) ) {
        $msgs = [
            'approved'       => ['success', '✓ Lançamento aprovado.'],
            'rejected'       => ['warning', '✗ Lançamento rejeitado.'],
            'returned'       => ['info',    '⟲ Lançamento devolvido ao artista.'],
            'bulk_approved'  => ['success', sprintf('✓ %d lançamento(s) aprovado(s) em massa.', isset($_GET['n']) ? (int) $_GET['n'] : 0)],
            'bulk_rejected'  => ['warning', sprintf('✗ %d lançamento(s) rejeitado(s) em massa.', isset($_GET['n']) ? (int) $_GET['n'] : 0)],
            'bulk_approve_disabled' => ['info', 'ℹ Aprovação em massa desactivada — cada lançamento deve passar pelo checklist individual antes de ser aprovado.'],
            'undone_approve' => ['info',    sprintf('↩ Aprovação revertida: %d lançamento(s).', isset($_GET['n']) ? (int) $_GET['n'] : 0)],
            'undone_reject'  => ['info',    sprintf('↩ Rejeição revertida: %d lançamento(s).', isset($_GET['n']) ? (int) $_GET['n'] : 0)],
        ];
        $key = sanitize_key($_GET['msg']);
        if ( isset($msgs[$key]) ) {
            list($type, $text) = $msgs[$key];
            echo '<div class="notice notice-' . esc_attr($type) . ' is-dismissible"><p>' . esc_html($text) . '</p></div>';
        }
    }

    // ----- Estado vazio -----
    if ( empty($pending) ) {
        echo '<div class="rmbz-section" style="text-align:center; padding:60px 40px;">';
        echo '<div style="font-size:48px; margin-bottom:12px;">🎉</div>';
        echo '<h2 style="color:var(--rmbz-success, #10b981); margin-bottom:8px;">Fila vazia!</h2>';
        echo '<p style="color:var(--rmbz-text-muted, #666);">Não há lançamentos pendentes de aprovação. Bom trabalho!</p>';
        echo '</div>';
        return;
    }

    // ----- Calcular avisos por release + agrupar por artista -----
    $now = time();
    $by_artist = []; // telemovel → [name, releases[], total_warns, oldest_age]
    $total_with_warns = 0;
    $genres_seen = [];

    foreach ( $pending as $r ) {
        $warns = rmbz_compute_release_warnings( $r );
        $r->_warnings = $warns;
        $r->_warn_count = count( $warns );
        if ( $r->_warn_count > 0 ) $total_with_warns++;

        // Calcular idade
        $submitted_ts = strtotime( $r->effective_submitted );
        $age_days = $submitted_ts ? (int) floor( ($now - $submitted_ts) / 86400 ) : 0;
        $r->_age_days = $age_days;
        $r->_age_color = rmbz_age_color( $age_days );
        $r->_age_label = rmbz_age_label( $age_days );

        // Filtro avisos
        if ( $filter_warns && $r->_warn_count === 0 ) continue;
        // Filtro idade
        if ( $filter_age && ! rmbz_age_matches_filter($age_days, $filter_age) ) continue;

        // Géneros para o filter dropdown
        if ( ! empty($r->primary_genre) ) $genres_seen[ $r->primary_genre ] = true;

        // Agrupar
        $tel = $r->artist_telemovel ?: 'unknown';
        if ( ! isset($by_artist[$tel]) ) {
            $by_artist[$tel] = [
                'telemovel'   => $tel,
                'name'        => $r->artist_name ?: '(Sem nome)',
                'releases'    => [],
                'oldest_age'  => 0,
                'total_warns' => 0,
            ];
        }
        $by_artist[$tel]['releases'][] = $r;
        if ( $age_days > $by_artist[$tel]['oldest_age'] ) $by_artist[$tel]['oldest_age'] = $age_days;
        $by_artist[$tel]['total_warns'] += $r->_warn_count;
    }

    // ----- Ordenação -----
    if ( $filter_sort === 'newest' ) {
        // Inverter ordem dentro de cada grupo + reordenar grupos por release mais recente
        foreach ( $by_artist as &$g ) {
            usort( $g['releases'], function($a, $b) { return $b->_age_days <=> $a->_age_days ? -1 : 1; });
        }
        unset($g);
        uasort( $by_artist, function($a, $b) {
            $a_min = PHP_INT_MAX; foreach ($a['releases'] as $rel) if ($rel->_age_days < $a_min) $a_min = $rel->_age_days;
            $b_min = PHP_INT_MAX; foreach ($b['releases'] as $rel) if ($rel->_age_days < $b_min) $b_min = $rel->_age_days;
            return $a_min <=> $b_min;
        });
    } elseif ( $filter_sort === 'warns' ) {
        uasort( $by_artist, function($a, $b) { return $b['total_warns'] <=> $a['total_warns']; });
        foreach ( $by_artist as &$g ) {
            usort( $g['releases'], function($a, $b) { return $b->_warn_count <=> $a->_warn_count; });
        }
        unset($g);
    } else {
        // 'oldest' default — já vem ordenado por SQL
        uasort( $by_artist, function($a, $b) { return $b['oldest_age'] <=> $a['oldest_age']; });
    }

    $total_releases = 0;
    foreach ( $by_artist as $g ) $total_releases += count($g['releases']);
    $total_artists = count( $by_artist );

    // URL builder helper
    $build_url = function( $changes = [] ) {
        $args = $_GET;
        foreach ( $changes as $k => $v ) {
            if ( $v === null || $v === '' ) unset($args[$k]);
            else $args[$k] = $v;
        }
        unset($args['msg'], $args['n'], $args['undo']);
        return '?' . http_build_query( $args );
    };
    $undo_nonce = wp_create_nonce( 'rmbz_release_undo' );

    ?>

    <?php /* [1.5.181] HEADER COM CONTAGEM + ORDENAÇÃO + FILTROS */ ?>
    <div class="rmbz-aq-header">
        <div>
            <div class="rmbz-aq-kicker">Fila de aprovação</div>
            <div class="rmbz-aq-title">
                <strong><?php echo (int) $total_releases; ?></strong> lançamento<?php echo $total_releases !== 1 ? 's' : ''; ?>
                · <strong><?php echo (int) $total_artists; ?></strong> artista<?php echo $total_artists !== 1 ? 's' : ''; ?>
                <?php if ( $total_with_warns > 0 ): ?>
                    · <span class="rmbz-aq-warn-badge">⚠ <?php echo (int) $total_with_warns; ?> com avisos</span>
                <?php endif; ?>
            </div>
        </div>
        <div class="rmbz-aq-sort-buttons">
            <a href="<?php echo esc_url( $build_url(['q_sort' => 'oldest']) ); ?>"
               class="rmbz-aq-sort-btn <?php echo $filter_sort === 'oldest' ? 'active' : ''; ?>">
                📅 Mais antigos
            </a>
            <a href="<?php echo esc_url( $build_url(['q_sort' => 'newest']) ); ?>"
               class="rmbz-aq-sort-btn <?php echo $filter_sort === 'newest' ? 'active' : ''; ?>">
                🆕 Mais recentes
            </a>
            <a href="<?php echo esc_url( $build_url(['q_sort' => 'warns']) ); ?>"
               class="rmbz-aq-sort-btn <?php echo $filter_sort === 'warns' ? 'active' : ''; ?>">
                ⚠ Com avisos
            </a>
        </div>
    </div>

    <?php /* Filtros chips */ ?>
    <div class="rmbz-aq-filters">
        <select onchange="window.location.href=this.value;" class="rmbz-aq-filter-chip">
            <option value="<?php echo esc_url( $build_url(['q_genre' => null]) ); ?>"<?php echo $filter_genre === '' ? ' selected' : ''; ?>>Todos os géneros</option>
            <?php foreach ( array_keys($genres_seen) as $g ): ?>
                <option value="<?php echo esc_url( $build_url(['q_genre' => $g]) ); ?>"
                        <?php echo $filter_genre === $g ? ' selected' : ''; ?>>
                    <?php echo esc_html($g); ?>
                </option>
            <?php endforeach; ?>
        </select>

        <select onchange="window.location.href=this.value;" class="rmbz-aq-filter-chip">
            <option value="<?php echo esc_url( $build_url(['q_type' => null]) ); ?>"<?php echo $filter_type === '' ? ' selected' : ''; ?>>Tipo: tudo</option>
            <option value="<?php echo esc_url( $build_url(['q_type' => 'single']) ); ?>"<?php echo $filter_type === 'single' ? ' selected' : ''; ?>>Single</option>
            <option value="<?php echo esc_url( $build_url(['q_type' => 'ep']) ); ?>"<?php echo $filter_type === 'ep' ? ' selected' : ''; ?>>EP</option>
            <option value="<?php echo esc_url( $build_url(['q_type' => 'album']) ); ?>"<?php echo $filter_type === 'album' ? ' selected' : ''; ?>>Álbum</option>
        </select>

        <select onchange="window.location.href=this.value;" class="rmbz-aq-filter-chip">
            <option value="<?php echo esc_url( $build_url(['q_age' => null]) ); ?>"<?php echo $filter_age === '' ? ' selected' : ''; ?>>Idade: tudo</option>
            <option value="<?php echo esc_url( $build_url(['q_age' => 'today']) ); ?>"<?php echo $filter_age === 'today' ? ' selected' : ''; ?>>Hoje</option>
            <option value="<?php echo esc_url( $build_url(['q_age' => 'week']) ); ?>"<?php echo $filter_age === 'week' ? ' selected' : ''; ?>>Esta semana</option>
            <option value="<?php echo esc_url( $build_url(['q_age' => 'old']) ); ?>"<?php echo $filter_age === 'old' ? ' selected' : ''; ?>>+7 dias (antigos)</option>
        </select>

        <a href="<?php echo esc_url( $build_url(['q_warns' => $filter_warns ? null : '1']) ); ?>"
           class="rmbz-aq-filter-toggle <?php echo $filter_warns ? 'active' : ''; ?>">
            ⚠ Apenas com problemas
        </a>
    </div>

    <?php /* GRUPOS POR ARTISTA */ ?>
    <div class="rmbz-aq-groups" id="rmbz-aq-groups">
        <?php foreach ( $by_artist as $group ):
            $rels = $group['releases'];
            $count = count( $rels );
            $initials = mb_strtoupper( mb_substr( $group['name'], 0, 2 ) );
            $age_str = rmbz_age_label( $group['oldest_age'] );
            $all_ids = array_map(function($r){ return (int) $r->id; }, $rels);
        ?>
            <div class="rmbz-aq-group" data-artist-tel="<?php echo esc_attr( $group['telemovel'] ); ?>">
                <div class="rmbz-aq-group-head">
                    <div class="rmbz-aq-group-info">
                        <div class="rmbz-aq-avatar"><?php echo esc_html( $initials ); ?></div>
                        <div>
                            <strong><?php echo esc_html( $group['name'] ); ?></strong>
                            <span class="rmbz-aq-group-meta">
                                <?php echo (int) $count; ?> lançamento<?php echo $count !== 1 ? 's' : ''; ?>
                                <?php if ( $group['total_warns'] > 0 ): ?>
                                    · <span style="color:#f87171;">⚠ <?php echo (int) $group['total_warns']; ?> aviso(s)</span>
                                <?php endif; ?>
                                · aguarda há <?php echo esc_html( $age_str ); ?>
                            </span>
                        </div>
                    </div>
                    <div class="rmbz-aq-group-actions">
                        <?php /* [1.5.184] Removido botão "Aprovar todos" — política nova:
                                 nunca aprovar sem passar pelo checklist individual.
                                 O grupo continua útil para visão organizada por artista
                                 e para collapse. */ ?>
                        <button type="button" class="rmbz-aq-collapse-btn" data-collapse-target="grp-<?php echo esc_attr($group['telemovel']); ?>">▼</button>
                    </div>
                </div>

                <div class="rmbz-aq-group-cards" id="grp-<?php echo esc_attr($group['telemovel']); ?>">
                    <?php foreach ( $rels as $r ): ?>
                        <?php rmbz_render_approval_card( $r ); ?>
                    <?php endforeach; ?>
                </div>
            </div>
        <?php endforeach; ?>
    </div>

    <?php /* Snackbar undo (preenchido via PHP se há ?undo=) */ ?>
    <?php if ( in_array($_GET['msg'] ?? '', ['bulk_approved', 'bulk_rejected', 'approved', 'rejected'], true) && ! empty($_GET['undo']) ):
        $token = sanitize_text_field( $_GET['undo'] );
        if ( get_transient('rmbz_rel_undo_' . $token) !== false ):
            $is_reject = in_array($_GET['msg'], ['bulk_rejected', 'rejected'], true);
            $action_label = $is_reject ? 'Rejeição' : 'Aprovação';
            $count = isset($_GET['n']) ? (int) $_GET['n'] : 1;
    ?>
        <div class="rmbz-aq-snackbar <?php echo $is_reject ? 'is-reject' : ''; ?>"
             id="rmbz-aq-snackbar"
             data-token="<?php echo esc_attr($token); ?>"
             data-nonce="<?php echo esc_attr($undo_nonce); ?>"
             data-action="<?php echo $is_reject ? 'reject' : 'approve'; ?>">
            <div>
                <strong><?php echo esc_html($action_label); ?> aplicada</strong>
                a <?php echo (int) $count; ?> lançamento<?php echo $count !== 1 ? 's' : ''; ?>.
            </div>
            <button type="button" id="rmbz-aq-undo-btn">Desfazer</button>
            <span id="rmbz-aq-countdown">10s</span>
        </div>
    <?php endif; endif; ?>

    <?php rmbz_render_approval_queue_styles(); ?>
    <?php rmbz_render_approval_queue_scripts(); ?>

    <?php
}


/* ============================================================================
 * [1.5.181] HELPERS — calcular avisos, formatar idade, render card
 * ============================================================================ */

/**
 * Calcula avisos para um release.
 * @return array Lista de strings curtas (cada uma é um aviso)
 */
function rmbz_compute_release_warnings( $r ) {
    $warns = [];

    // 1. Sem capa
    if ( empty($r->cover_image) ) {
        $warns[] = 'Sem capa';
    } else {
        // 1b. Capa pequena (se a coluna existir e tiver dados)
        if ( ! empty($r->cover_width) && (int) $r->cover_width < 3000 ) {
            $warns[] = 'Capa <3000px';
        }
    }

    // 2. Sem género
    if ( empty($r->primary_genre) ) {
        $warns[] = 'Sem género';
    }

    // 3. Sem data de lançamento
    if ( empty($r->release_date) || $r->release_date === '0000-00-00' ) {
        $warns[] = 'Sem data';
    }

    // 4. Sem faixas com ISRC
    if ( isset($r->tracks_count) && (int) $r->tracks_count > 0 ) {
        $isrc_count = (int) ( $r->tracks_with_isrc ?? 0 );
        if ( $isrc_count === 0 ) {
            $warns[] = 'Sem ISRC';
        } elseif ( $isrc_count < (int) $r->tracks_count ) {
            $missing = (int) $r->tracks_count - $isrc_count;
            $warns[] = $missing . ' faixa(s) sem ISRC';
        }
    } elseif ( isset($r->tracks_count) && (int) $r->tracks_count === 0 ) {
        $warns[] = 'Sem faixas!';
    }

    // 5. Título com caracteres suspeitos
    if ( ! empty($r->title) ) {
        if ( preg_match('/[<>{}\[\]\\\\|]/', $r->title) ) {
            $warns[] = 'Título suspeito';
        }
        if ( mb_strlen($r->title) < 2 ) {
            $warns[] = 'Título muito curto';
        }
    }

    return $warns;
}

/**
 * Devolve cor (hex) baseada na idade em dias.
 */
function rmbz_age_color( $days ) {
    if ( $days < 1 ) return '#888';
    if ( $days <= 3 ) return '#f0b90b';   // amarelo
    if ( $days <= 7 ) return '#f59e0b';   // laranja
    return '#ef4444';                      // vermelho
}

/**
 * Devolve texto humano "há X dias / horas".
 */
function rmbz_age_label( $days ) {
    if ( $days < 1 ) return 'menos de 1 dia';
    if ( $days === 1 ) return '1 dia';
    return $days . ' dias';
}

/**
 * Verifica se idade combina com o filtro selecionado.
 */
function rmbz_age_matches_filter( $days, $filter ) {
    switch ( $filter ) {
        case 'today': return $days < 1;
        case 'week':  return $days >= 1 && $days <= 7;
        case 'old':   return $days > 7;
    }
    return true;
}

/**
 * Render de um card individual.
 */
function rmbz_render_approval_card( $r ) {
    $warn_count  = (int) ( $r->_warn_count ?? 0 );
    $warns       = $r->_warnings ?? [];
    $age_color   = $r->_age_color ?? '#888';
    $age_label   = $r->_age_label ?? '';
    $type_label  = ucfirst( $r->release_type ?: 'single' );
    $rid         = (int) $r->id;
    $detail_url  = admin_url('admin.php?page=rmbz-admin-distribution&tab=releases&view=detail&id=' . $rid);
    ?>
    <div class="rmbz-aq-card <?php echo $warn_count > 0 ? 'has-warnings' : ''; ?>"
         data-release-id="<?php echo $rid; ?>">

        <?php if ( $warn_count > 0 ): ?>
            <div class="rmbz-aq-card-warn-badge" title="<?php echo esc_attr( implode(' · ', $warns) ); ?>">
                ⚠ <?php echo $warn_count; ?>
            </div>
        <?php endif; ?>

        <label class="rmbz-aq-card-checkbox" title="Selecionar">
            <input type="checkbox" class="rmbz-aq-card-cb" data-release-id="<?php echo $rid; ?>">
        </label>

        <div class="rmbz-aq-card-cover">
            <?php if ( ! empty($r->cover_image) ): ?>
                <img src="<?php echo esc_url($r->cover_image); ?>" alt="">
            <?php else: ?>
                <div class="rmbz-aq-card-cover-placeholder">🎵</div>
            <?php endif; ?>
        </div>

        <div class="rmbz-aq-card-body">
            <div class="rmbz-aq-card-title-row">
                <strong><?php echo esc_html( $r->title ?: '(sem título)' ); ?></strong>
            </div>
            <div class="rmbz-aq-card-meta">
                <span class="rmbz-aq-card-type-pill"><?php echo esc_html($type_label); ?></span>
                · <?php echo esc_html( $r->primary_genre ?: '—' ); ?>
                · <?php echo (int) $r->tracks_count; ?> faixa<?php echo (int) $r->tracks_count !== 1 ? 's' : ''; ?>
                · <span style="color: <?php echo esc_attr($age_color); ?>;">há <?php echo esc_html($age_label); ?></span>
            </div>

            <?php if ( $warn_count > 0 ): ?>
                <div class="rmbz-aq-card-warns">
                    ⚠ <?php echo esc_html( implode(' · ', $warns) ); ?>
                </div>
            <?php endif; ?>

            <div class="rmbz-aq-card-actions">
                <?php /* [1.5.184] BOTÃO PRINCIPAL agora é "Analisar" — nunca aprovar
                         directamente da fila. Política: todo lançamento passa pelo
                         checklist (auto + manual) antes de aprovar. O botão "Aprovar"
                         ficou só na página de detalhe, com gate que requer checks. */ ?>
                <a href="<?php echo esc_url($detail_url); ?>" class="rmbz-aq-btn rmbz-aq-btn-analyze">
                    🔍 Analisar
                </a>
                <button type="button" class="rmbz-aq-btn rmbz-aq-btn-reject"
                        onclick="document.getElementById('rmbz-rej-<?php echo $rid; ?>').style.display='block';">
                    ✕ Rejeitar
                </button>
            </div>

            <form method="post" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>"
                  id="rmbz-rej-<?php echo $rid; ?>"
                  class="rmbz-aq-reject-form" style="display:none;">
                <?php wp_nonce_field('rmbz_release_action_' . $rid); ?>
                <input type="hidden" name="action" value="rmbz_release_reject">
                <input type="hidden" name="release_id" value="<?php echo $rid; ?>">
                <input type="hidden" name="return_to" value="approval">
                <select name="reject_code" required class="rmbz-aq-reject-select">
                    <option value="">— Motivo —</option>
                    <option value="low_quality_audio">Áudio má qualidade</option>
                    <option value="low_quality_cover">Capa má qualidade</option>
                    <option value="metadata_incomplete">Metadata incompleta</option>
                    <option value="copyright_concern">Direitos autorais</option>
                    <option value="explicit_not_flagged">Explícito não declarado</option>
                    <option value="duplicate">Duplicado</option>
                    <option value="cover_third_party_logo">Logo de terceiros</option>
                    <option value="other">Outro</option>
                </select>
                <button type="submit" class="rmbz-aq-btn rmbz-aq-btn-reject-confirm">Confirmar rejeição</button>
            </form>
        </div>
    </div>
    <?php
}


/* ============================================================================
 * [1.5.181] CSS da fila — escrito como função para manter render limpo
 * ============================================================================ */
function rmbz_render_approval_queue_styles() {
    ?>
    <style>
    /* [1.5.182] LIGHT THEME — coerente com WP admin standard
       Cores WP: var(--wp-components-color-foreground, #1d2327) texto / #50575e cinza / var(--wp-admin-theme-color, #2271b1) azul / #00a32a verde
                 #dcdcde border / #f0f0f1 hover bg / #fafafa surface */

    .rmbz-aq-header {
        display:flex; justify-content:space-between; align-items:center;
        gap:14px; flex-wrap:wrap; margin-bottom:14px; padding:16px 20px;
        background:#fff; border:1px solid #dcdcde; border-radius:8px;
    }
    .rmbz-aq-kicker {
        font-size:11px; color:#787c82; text-transform:uppercase; letter-spacing:0.05em;
    }
    .rmbz-aq-title {
        font-size:18px; color:var(--wp-components-color-foreground, #1d2327); font-weight:600; margin-top:2px;
    }
    .rmbz-aq-warn-badge {
        background:#fde8e8; color:#a02929; padding:2px 9px; border-radius:10px;
        font-size:12px; font-weight:600; margin-left:6px;
    }
    .rmbz-aq-sort-buttons { display:flex; gap:6px; flex-wrap:wrap; }
    .rmbz-aq-sort-btn {
        background:#fff; color:#50575e !important; border:1px solid #c3c4c7;
        padding:7px 14px; border-radius:5px; font-size:12px; cursor:pointer;
        text-decoration:none !important; transition:all 0.15s ease; line-height:1.4;
    }
    .rmbz-aq-sort-btn:hover {
        background:#f0f0f1; border-color:#8c8f94;
    }
    .rmbz-aq-sort-btn.active {
        background:var(--wp-admin-theme-color, #2271b1) !important; color:#fff !important; border-color:var(--wp-admin-theme-color, #2271b1) !important;
        font-weight:600;
    }

    .rmbz-aq-filters {
        display:flex; gap:6px; flex-wrap:wrap; margin-bottom:18px; align-items:center;
    }
    .rmbz-aq-filter-chip {
        background:#fff; border:1px solid #c3c4c7; color:#50575e;
        padding:6px 12px; border-radius:14px; font-size:12px;
        cursor:pointer;
    }
    .rmbz-aq-filter-toggle {
        background:#fff; border:1px solid #c3c4c7; color:#50575e !important;
        padding:6px 12px; border-radius:14px; font-size:12px;
        text-decoration:none !important; transition:all 0.15s ease;
    }
    .rmbz-aq-filter-toggle:hover { background:#f0f0f1; }
    .rmbz-aq-filter-toggle.active {
        background:#fef3f2 !important; border-color:#d63638 !important; color:#a02929 !important;
    }

    .rmbz-aq-groups { display:flex; flex-direction:column; gap:14px; }
    .rmbz-aq-group {
        background:#fff; border:1px solid #dcdcde; border-radius:8px;
        overflow:hidden;
    }
    .rmbz-aq-group-head {
        padding:12px 16px; background:#fafafa; border-bottom:1px solid #dcdcde;
        display:flex; justify-content:space-between; align-items:center;
        gap:12px; flex-wrap:wrap;
    }
    .rmbz-aq-group-info {
        display:flex; align-items:center; gap:10px; min-width:0;
    }
    .rmbz-aq-avatar {
        width:30px; height:30px; border-radius:50%; background:var(--wp-admin-theme-color, #2271b1);
        display:flex; align-items:center; justify-content:center;
        font-size:11px; font-weight:700; color:#fff; flex-shrink:0;
    }
    .rmbz-aq-group-info strong {
        color:var(--wp-components-color-foreground, #1d2327); font-size:14px;
    }
    .rmbz-aq-group-meta {
        font-size:11px; color:#787c82; margin-left:6px;
    }
    .rmbz-aq-group-actions { display:flex; gap:6px; align-items:center; }
    .rmbz-aq-collapse-btn {
        background:#fff; color:#50575e !important; border:1px solid #c3c4c7;
        padding:7px 11px; border-radius:5px; font-size:12px; cursor:pointer;
        transition:transform 0.15s ease;
    }
    .rmbz-aq-collapse-btn:hover { background:#f0f0f1; }
    .rmbz-aq-collapse-btn.collapsed { transform:rotate(-90deg); }

    .rmbz-aq-group-cards {
        padding:14px;
        /* [1.5.186] auto-fit fazia o card único esticar para 100% da largura
           (porque 1fr ocupa o espaço todo). Adicionamos max-width no card via
           grid-template-columns com minmax(290px, 380px) — nunca mais largo
           que ~380px, mesmo se for o único do grupo. */
        display:grid; grid-template-columns:repeat(auto-fit, minmax(290px, 380px));
        gap:12px;
        justify-content:start;
    }

    /* CARD — limpo e moderno, sem border vermelho agressivo */
    .rmbz-aq-card {
        background:#fff; border:1px solid #e0e0e0; border-radius:6px;
        padding:12px; display:flex; gap:10px; position:relative;
        transition:border-color 0.15s ease; min-height:115px;
    }
    .rmbz-aq-card.has-warnings {
        border-color:#f0c8c8;
        border-left:3px solid #d63638;
        padding-left:10px; /* compensar o border-left mais grosso */
    }
    .rmbz-aq-card.is-selected {
        border-color:var(--wp-admin-theme-color, #2271b1);
        background:#f0f6fc;
    }

    .rmbz-aq-card-warn-badge {
        position:absolute; top:-1px; right:-1px;
        background:#d63638; color:#fff;
        padding:3px 8px; border-bottom-left-radius:6px; border-top-right-radius:6px;
        font-size:10px; font-weight:700; cursor:help; line-height:1.2;
    }
    .rmbz-aq-card-checkbox {
        flex-shrink:0; padding:2px; cursor:pointer;
    }
    .rmbz-aq-card-checkbox input { margin:0; cursor:pointer; }

    .rmbz-aq-card-cover {
        width:54px; height:54px; border-radius:5px; overflow:hidden; flex-shrink:0;
    }
    .rmbz-aq-card-cover img { width:100%; height:100%; object-fit:cover; display:block; }
    .rmbz-aq-card-cover-placeholder {
        width:100%; height:100%; background:#f0f0f1; color:#a7aaad;
        display:flex; align-items:center; justify-content:center; font-size:22px;
    }

    .rmbz-aq-card-body { flex:1; min-width:0; }
    .rmbz-aq-card-title-row {
        /* [1.5.183] Reserva espaço para o badge de aviso no canto superior direito.
           Antes o pill "Single" estava aqui e era invadido pelo badge ⚠.
           Agora o pill foi movido para a linha de meta, e o título tem
           padding-right para nunca colidir com o badge (que tem ~30-40px). */
        padding-right:42px;
    }
    .rmbz-aq-card-title-row strong {
        font-size:13px; font-weight:600; color:var(--wp-components-color-foreground, #1d2327);
        white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
        display:block;
    }
    .rmbz-aq-card-type-pill {
        background:#f0f0f1; color:#646970; padding:1px 6px; border-radius:3px;
        font-size:10px; font-weight:600; text-transform:uppercase; letter-spacing:0.03em;
    }
    .rmbz-aq-card-meta {
        font-size:11px; color:#787c82; margin-top:4px;
        display:flex; align-items:center; gap:5px; flex-wrap:wrap;
    }
    .rmbz-aq-card-warns {
        font-size:11px; color:#a02929; margin-top:5px; line-height:1.4;
        padding:3px 7px; background:#fef3f2; border-radius:3px;
        display:inline-block; max-width:100%;
        overflow:hidden; text-overflow:ellipsis; white-space:nowrap;
    }
    .rmbz-aq-card-actions {
        display:flex; gap:4px; margin-top:8px;
    }

    /* BOTÕES — estilo WP standard */
    .rmbz-aq-btn {
        background:#fff; color:#50575e !important; border:1px solid #c3c4c7;
        padding:5px 10px; border-radius:3px; font-size:11px; cursor:pointer;
        text-decoration:none !important; transition:all 0.15s ease;
        font-weight:500; line-height:1.4;
    }
    .rmbz-aq-btn:hover {
        background:#f0f0f1; border-color:#8c8f94; color:var(--wp-components-color-foreground, #1d2327) !important;
    }
    /* [1.5.184] Botão "Analisar" — primary action de cada card.
       [1.5.185] Cor AMARELA (atenção/inspecionar) — semanticamente correcto.
       Verde (aprovar) / Azul (info) seriam confusos. Amarelo diz "vê isto antes
       de decidir". Leva à página de detalhe onde o admin completa o checklist. */
    .rmbz-aq-btn-analyze {
        background:#dba617 !important; color:var(--wp-components-color-foreground, #1d2327) !important;
        border-color:#bf8a10 !important;
        font-weight:600; flex:1; text-align:center;
    }
    .rmbz-aq-btn-analyze:hover {
        background:#bf8a10 !important; border-color:#a07308 !important;
        color:var(--wp-components-color-foreground, #1d2327) !important;
    }
    /* Botão Approve antigo (mantido para retro-compat caso alguém o use noutro lado) */
    .rmbz-aq-btn-approve {
        background:#00a32a !important; color:#fff !important;
        border-color:#008a20 !important;
        font-weight:600; flex:1;
    }
    .rmbz-aq-btn-approve:hover {
        background:#008a20 !important; border-color:#007014 !important;
        color:#fff !important;
    }
    .rmbz-aq-btn-approve-all {
        background:#00a32a !important; color:#fff !important;
        border:1px solid #008a20 !important;
        padding:7px 14px; border-radius:5px; font-size:12px; font-weight:600;
        cursor:pointer; transition:all 0.15s ease;
    }
    .rmbz-aq-btn-approve-all:hover {
        background:#008a20 !important; border-color:#007014 !important;
    }
    /* [1.5.184] Botão de bulk reject (na bulk bar) — destrutivo, cor vermelha WP */
    .rmbz-aq-btn-bulk-reject {
        background:#d63638 !important; color:#fff !important;
        border:1px solid #b32d2e !important;
        padding:7px 14px; border-radius:5px; font-size:12px; font-weight:600;
        cursor:pointer; transition:all 0.15s ease;
    }
    .rmbz-aq-btn-bulk-reject:hover {
        background:#b32d2e !important; border-color:#9b2627 !important;
    }
    /* [1.5.185] Rejeitar — vermelho preenchido para corresponder ao Analisar
       (acção visível, semanticamente clara). Antes era branco com hover vermelho
       — não chamava atenção suficiente como par do Analisar amarelo. */
    .rmbz-aq-btn-reject {
        background:#d63638 !important; color:#fff !important;
        border-color:#b32d2e !important;
        font-weight:600;
    }
    .rmbz-aq-btn-reject:hover {
        background:#b32d2e !important; border-color:#9b2627 !important;
        color:#fff !important;
    }
    .rmbz-aq-btn-reject-confirm {
        background:#d63638 !important; color:#fff !important;
        border:1px solid #b32d2e !important;
        padding:7px 12px; border-radius:4px; font-size:12px; font-weight:600;
        width:100%; cursor:pointer;
    }
    .rmbz-aq-btn-reject-confirm:hover {
        background:#b32d2e !important;
    }
    .rmbz-aq-reject-form {
        margin-top:8px; padding:8px; background:#fafafa;
        border:1px solid #dcdcde; border-radius:4px;
        display:flex; flex-direction:column; gap:6px;
    }
    .rmbz-aq-reject-select {
        width:100%; background:#fff; color:var(--wp-components-color-foreground, #1d2327); border:1px solid #c3c4c7;
        padding:6px 8px; border-radius:3px; font-size:12px;
    }

    /* BULK BAR — vermelha (acção destrutiva: bulk reject)
       [1.5.184] Era azul (bulk approve). Agora é vermelha porque a única
       bulk action disponível é rejeitar. */
    .rmbz-aq-bulk-bar {
        position:fixed; bottom:24px; left:50%; transform:translateX(-50%);
        background:#fff; border:2px solid #d63638; border-radius:8px;
        padding:12px 18px; display:flex; gap:10px; align-items:center;
        box-shadow:0 4px 16px rgba(0,0,0,0.15); z-index:99998;
        animation:rmbzAqSlideUp 0.2s ease-out;
    }
    @keyframes rmbzAqSlideUp { from { opacity:0; transform:translate(-50%, 20px); } to { opacity:1; transform:translate(-50%, 0); } }
    .rmbz-aq-bulk-bar strong { color:#d63638; }

    /* SNACKBAR UNDO */
    .rmbz-aq-snackbar {
        position:fixed; bottom:24px; right:24px; z-index:99999;
        background:var(--wp-components-color-foreground, #1d2327); color:#fff; padding:14px 18px; border-radius:6px;
        box-shadow:0 4px 16px rgba(0,0,0,0.3); display:flex; align-items:center;
        gap:14px; max-width:420px; font-size:13px; line-height:1.4;
        animation:rmbzAqSnackIn 0.25s ease-out;
        border-left:4px solid #00a32a;
    }
    .rmbz-aq-snackbar.is-reject { border-left-color:#d63638; }
    @keyframes rmbzAqSnackIn { from { opacity:0; transform:translateY(20px); } to { opacity:1; transform:translateY(0); } }
    .rmbz-aq-snackbar.is-leaving { animation:rmbzAqSnackOut 0.2s ease-in forwards; }
    @keyframes rmbzAqSnackOut { from { opacity:1; transform:translateY(0); } to { opacity:0; transform:translateY(20px); } }
    #rmbz-aq-undo-btn {
        background:transparent; border:1px solid rgba(255,255,255,0.4);
        color:#f0b90b; padding:6px 14px; border-radius:4px; font-size:12px;
        font-weight:700; cursor:pointer; text-transform:uppercase;
        letter-spacing:0.04em;
    }
    #rmbz-aq-undo-btn:hover { background:#f0b90b; color:var(--wp-components-color-foreground, #1d2327); }
    #rmbz-aq-countdown { font-size:11px; opacity:0.7; }

    /* ════════════════════ [DESIGN 2.0] CAMADA MATERIAL 3 ════════════════════
       Sobrepõe o estilo legado (vem por último no mesmo <style>). Cantos
       maiores, sombras suaves, gradientes e animações — sem tocar no HTML. */
    .rmbz-aq-header, .rmbz-aq-group {
        border-radius: 18px !important;
        border-color: #e6e8eb !important;
        box-shadow: 0 1px 3px rgba(16,24,40,.05) !important;
    }
    .rmbz-aq-kicker { font-weight: 700; letter-spacing: .08em; }
    .rmbz-aq-title { font-weight: 800; }

    .rmbz-aq-sort-btn, .rmbz-aq-collapse-btn {
        border-radius: 10px !important;
        transition: all .15s cubic-bezier(.4,0,.2,1) !important;
    }
    .rmbz-aq-sort-btn:active, .rmbz-aq-collapse-btn:active { transform: scale(.96); }
    .rmbz-aq-sort-btn.active { box-shadow: 0 2px 8px rgba(34,113,177,.25); }

    .rmbz-aq-filter-chip, .rmbz-aq-filter-toggle {
        border-radius: 999px !important; border-color: #e2e5e9 !important;
        transition: all .15s cubic-bezier(.4,0,.2,1) !important;
    }
    .rmbz-aq-filter-toggle:active { transform: scale(.97); }

    .rmbz-aq-group-head { background: #fafbfc !important; border-bottom-color: #eef0f3 !important; }
    .rmbz-aq-avatar {
        width: 36px !important; height: 36px !important;
        background: linear-gradient(135deg, #7c6df2, #5a4be0) !important;
        font-size: 13px !important; box-shadow: 0 3px 8px rgba(99,86,229,.28);
    }
    .rmbz-aq-group-info strong { font-weight: 800 !important; }

    /* Cards entram em cascata + elevam ao hover */
    .rmbz-aq-card {
        border-radius: 16px !important; border-color: #e6e8eb !important;
        box-shadow: 0 1px 2px rgba(16,24,40,.04);
        animation: rmbz-aq-rise .45s cubic-bezier(.4,0,.2,1) both;
        transition: transform .2s cubic-bezier(.4,0,.2,1), box-shadow .2s cubic-bezier(.4,0,.2,1), border-color .2s !important;
    }
    @keyframes rmbz-aq-rise { from { opacity:0; transform: translateY(10px); } to { opacity:1; transform:none; } }
    .rmbz-aq-card:nth-child(2) { animation-delay: .05s; }
    .rmbz-aq-card:nth-child(3) { animation-delay: .1s; }
    .rmbz-aq-card:nth-child(4) { animation-delay: .15s; }
    .rmbz-aq-card:hover {
        transform: translateY(-3px);
        box-shadow: 0 12px 28px rgba(16,24,40,.12) !important;
        border-color: #d6d9de !important;
    }
    .rmbz-aq-card.has-warnings { border-left-width: 4px !important; }
    .rmbz-aq-card-cover { border-radius: 11px !important; box-shadow: 0 3px 10px rgba(16,24,40,.14); }
    .rmbz-aq-card-cover img { transition: transform .3s cubic-bezier(.4,0,.2,1); }
    .rmbz-aq-card:hover .rmbz-aq-card-cover img { transform: scale(1.08); }
    .rmbz-aq-card-warn-badge { border-top-right-radius: 16px !important; }
    .rmbz-aq-card-type-pill { border-radius: 999px !important; }

    /* Snackbar de undo — flutuante e arredondado */
    .rmbz-aq-snackbar { border-radius: 14px !important; box-shadow: 0 12px 32px rgba(16,24,40,.22) !important; }
    #rmbz-aq-undo-btn { border-radius: 9px !important; transition: all .15s; }

    /* Botões de decisão dentro do card (aprovar/rejeitar/devolver) */
    .rmbz-aq-card .button { border-radius: 10px !important; transition: transform .1s, filter .15s !important; }
    .rmbz-aq-card .button:active { transform: scale(.96); }
    </style>
    <?php
}


/* ============================================================================
 * [1.5.181] JS — bulk selection, collapse, undo
 * ============================================================================ */
function rmbz_render_approval_queue_scripts() {
    ?>
    <script>
    (function() {
        // ===== Bulk selection =====
        var groups = document.getElementById('rmbz-aq-groups');
        if (groups) {
            var bulkBar = null;
            function getSelectedIds() {
                var ids = [];
                document.querySelectorAll('.rmbz-aq-card-cb:checked').forEach(function(cb) {
                    ids.push(cb.getAttribute('data-release-id'));
                });
                return ids;
            }
            function refreshBulkBar() {
                var ids = getSelectedIds();
                if (ids.length === 0) {
                    if (bulkBar) { bulkBar.parentNode.removeChild(bulkBar); bulkBar = null; }
                    return;
                }
                if (!bulkBar) {
                    bulkBar = document.createElement('div');
                    bulkBar.className = 'rmbz-aq-bulk-bar';
                    document.body.appendChild(bulkBar);
                }
                // [1.5.184] Bulk approve removido por política — só bulk reject
                // continua disponível (rejeição é menos arriscada que aprovação;
                // ex: 5 duplicados óbvios podem ser rejeitados de uma vez).
                bulkBar.innerHTML = '<strong>' + ids.length + '</strong> selecionado(s)' +
                    ' <button type="button" id="rmbz-aq-bulk-reject-btn" class="rmbz-aq-btn-bulk-reject">✕ Rejeitar selecionados</button>' +
                    ' <button type="button" id="rmbz-aq-bulk-clear-btn" class="rmbz-aq-btn">Limpar</button>';

                document.getElementById('rmbz-aq-bulk-reject-btn').onclick = function() {
                    var idsList = getSelectedIds().join(',');
                    if (!idsList) return;
                    // Pedir motivo via prompt simples (alternativa: modal custom)
                    var reasonOptions = [
                        'duplicate', 'low_quality_audio', 'low_quality_cover',
                        'metadata_incomplete', 'copyright_concern', 'other'
                    ];
                    var reasonLabels = {
                        'duplicate': 'Duplicado',
                        'low_quality_audio': 'Áudio má qualidade',
                        'low_quality_cover': 'Capa má qualidade',
                        'metadata_incomplete': 'Metadata incompleta',
                        'copyright_concern': 'Direitos autorais',
                        'other': 'Outro'
                    };
                    var prompt_msg = 'Motivo da rejeição em massa:\n\n' +
                                     reasonOptions.map(function(k, i) { return (i+1) + '. ' + reasonLabels[k]; }).join('\n') +
                                     '\n\nEscreve o número (1-' + reasonOptions.length + '):';
                    var picked = window.prompt(prompt_msg, '1');
                    if (!picked) return;
                    var idx = parseInt(picked, 10) - 1;
                    if (isNaN(idx) || idx < 0 || idx >= reasonOptions.length) {
                        alert('Número inválido. Operação cancelada.');
                        return;
                    }
                    var reasonCode = reasonOptions[idx];
                    if (!confirm('Rejeitar ' + ids.length + ' lançamento(s) com motivo "' + reasonLabels[reasonCode] + '"?')) return;

                    var f = document.createElement('form');
                    f.method = 'POST';
                    f.action = '<?php echo esc_js( admin_url('admin-post.php') ); ?>';
                    f.innerHTML = '<input type="hidden" name="action" value="rmbz_release_bulk_reject">' +
                                  '<input type="hidden" name="ids" value="' + idsList + '">' +
                                  '<input type="hidden" name="reject_code" value="' + reasonCode + '">' +
                                  '<input type="hidden" name="_wpnonce" value="<?php echo esc_js( wp_create_nonce('rmbz_release_bulk_action') ); ?>">';
                    document.body.appendChild(f);
                    f.submit();
                };
                document.getElementById('rmbz-aq-bulk-clear-btn').onclick = function() {
                    document.querySelectorAll('.rmbz-aq-card-cb:checked').forEach(function(cb) {
                        cb.checked = false;
                        cb.closest('.rmbz-aq-card').classList.remove('is-selected');
                    });
                    refreshBulkBar();
                };
            }
            groups.addEventListener('change', function(e) {
                if (e.target.classList.contains('rmbz-aq-card-cb')) {
                    e.target.closest('.rmbz-aq-card').classList.toggle('is-selected', e.target.checked);
                    refreshBulkBar();
                }
            });
        }

        // ===== Collapse de grupos =====
        document.querySelectorAll('.rmbz-aq-collapse-btn').forEach(function(btn) {
            btn.addEventListener('click', function() {
                var targetId = btn.getAttribute('data-collapse-target');
                var target = document.getElementById(targetId);
                if (!target) return;
                var isOpen = target.style.display !== 'none';
                target.style.display = isOpen ? 'none' : '';
                btn.classList.toggle('collapsed', isOpen);
            });
        });

        // ===== Snackbar undo =====
        var snackbar = document.getElementById('rmbz-aq-snackbar');
        if (snackbar) {
            var btn = document.getElementById('rmbz-aq-undo-btn');
            var countdown = document.getElementById('rmbz-aq-countdown');
            var token = snackbar.getAttribute('data-token');
            var nonce = snackbar.getAttribute('data-nonce');
            var action = snackbar.getAttribute('data-action');
            var ajaxUrl = '<?php echo esc_js( admin_url('admin-ajax.php') ); ?>';
            var seconds = 10;
            var timer = setInterval(function() {
                seconds--;
                if (seconds <= 0) {
                    clearInterval(timer);
                    snackbar.classList.add('is-leaving');
                    setTimeout(function() { snackbar.parentNode && snackbar.parentNode.removeChild(snackbar); }, 200);
                } else {
                    countdown.textContent = seconds + 's';
                }
            }, 1000);

            btn.addEventListener('click', function() {
                btn.disabled = true;
                btn.textContent = 'A desfazer...';
                clearInterval(timer);
                var fd = new FormData();
                fd.append('action', 'rmbz_release_undo');
                fd.append('undo_token', token);
                fd.append('_nonce', nonce);
                fetch(ajaxUrl, { method: 'POST', body: fd, credentials: 'same-origin' })
                    .then(function(r) { return r.json(); })
                    .then(function(data) {
                        if (data && data.success) {
                            var msgKey = (action === 'reject') ? 'undone_reject' : 'undone_approve';
                            var n = (data.data && data.data.reverted) ? data.data.reverted : 0;
                            window.location.href = '?page=rmbz-admin-distribution&tab=releases&view=approval&msg=' + msgKey + '&n=' + n;
                        } else {
                            btn.textContent = 'Erro';
                            btn.disabled = false;
                        }
                    })
                    .catch(function() { btn.textContent = 'Erro'; btn.disabled = false; });
            });
        }
    })();
    </script>
    <?php
}


/* ============================================================================
 * HANDLERS de acções (aprovar/rejeitar/takedown)
 * ============================================================================ */

function rmbz_admin_release_approve_handler() {
    // LEGACY HANDLER — mantido para compatibilidade com botões antigos e
    // bookmarks. Em vez de saltar directamente para `live` (como fazia antes
    // e que corrompia o tracker de 5 passos), redirecciona para o novo
    // handler por passos, que faz a transição correcta pendente → approved.
    //
    // Novos botões no painel usam directamente os handlers:
    //   - rmbz_release_mark_approved   (pendente → approved)
    //   - rmbz_release_mark_delivered  (approved → delivered)
    //   - rmbz_release_mark_live       (delivered → live)
    // ver: includes/distribution/distribution-release-workflow.php
    if ( function_exists('rmbz_admin_release_mark_approved_handler') ) {
        rmbz_admin_release_mark_approved_handler();
        return;
    }

    // Fallback ultra-defensivo (se o ficheiro de workflow não carregou):
    // não avançar nada e mostrar mensagem clara ao admin em vez de corromper
    // o estado saltando para live.
    if ( ! current_user_can('manage_options') ) wp_die('Sem permissão.');
    wp_die('O módulo de workflow não está carregado. Contacte o administrador.');
}
add_action('admin_post_rmbz_release_approve', 'rmbz_admin_release_approve_handler');

function rmbz_admin_release_reject_handler() {
    if ( ! current_user_can('manage_options') ) wp_die('Sem permissão.');
    $release_id = (int) ($_POST['release_id'] ?? 0);
    if ( ! $release_id ) wp_die('ID inválido.');
    check_admin_referer('rmbz_release_action_' . $release_id);

    $code = sanitize_key( $_POST['reject_code'] ?? 'other' );
    $note = sanitize_textarea_field( $_POST['reject_note'] ?? '' );

    global $wpdb;
    $t = $wpdb->prefix . 'rmbz_distro_releases';
    $current = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $t WHERE id = %d", $release_id) );
    if ( ! $current ) wp_die('Lançamento não encontrado.');

    $reject_msg = rmbz_admin_reject_reason_label($code);
    if ( $note ) $reject_msg .= ' — ' . $note;

    $wpdb->update( $t,
        [ 'status' => 'rejected', 'rejection_reason' => $reject_msg ],
        [ 'id' => $release_id ],
        [ '%s', '%s' ],
        [ '%d' ]
    );

    rmbz_admin_log_status_change( $release_id, $current->status, 'rejected', $reject_msg );

    do_action('rmbz_distro_status_changed', $release_id, $current->status, 'rejected');

    $return = $_POST['return_to'] ?? '';
    if ( $return === 'approval' ) {
        wp_safe_redirect( admin_url('admin.php?page=rmbz-admin-distribution&tab=approval&msg=rejected') );
    } else {
        wp_safe_redirect( admin_url('admin.php?page=rmbz-admin-distribution&tab=releases&view=detail&id=' . $release_id . '&msg=rejected') );
    }
    exit;
}
add_action('admin_post_rmbz_release_reject', 'rmbz_admin_release_reject_handler');

function rmbz_admin_release_takedown_handler() {
    if ( ! current_user_can('manage_options') ) wp_die('Sem permissão.');
    $release_id = (int) ($_POST['release_id'] ?? 0);
    if ( ! $release_id ) wp_die('ID inválido.');
    check_admin_referer('rmbz_release_action_' . $release_id);

    global $wpdb;
    $t = $wpdb->prefix . 'rmbz_distro_releases';
    $current = $wpdb->get_row( $wpdb->prepare("SELECT * FROM $t WHERE id = %d", $release_id) );
    if ( ! $current ) wp_die('Lançamento não encontrado.');

    $wpdb->update( $t,
        [ 'status' => 'takedown_requested', 'takedown_requested' => 1 ],
        [ 'id' => $release_id ],
        [ '%s', '%d' ],
        [ '%d' ]
    );

    rmbz_admin_log_status_change( $release_id, $current->status, 'takedown_requested', 'Takedown solicitado pelo admin' );

    wp_safe_redirect( admin_url('admin.php?page=rmbz-admin-distribution&tab=releases&view=detail&id=' . $release_id . '&msg=takedown') );
    exit;
}
add_action('admin_post_rmbz_release_takedown', 'rmbz_admin_release_takedown_handler');


/**
 * ----------------------------------------------------------------------------
 * HANDLER — Finalizar takedown (takedown_requested → taken_down)
 * ----------------------------------------------------------------------------
 * Confirma que o release já saiu (ou está em processo de sair) das lojas.
 * Marca como `taken_down` que é estado terminal (não há reversão possível
 * sem criar novo release com novo UPC + novos ISRCs).
 */
function rmbz_admin_release_takedown_confirm_handler() {
    if ( ! current_user_can('manage_options') ) wp_die('Sem permissão.');
    $release_id = (int) ($_POST['release_id'] ?? 0);
    if ( ! $release_id ) wp_die('ID inválido.');
    check_admin_referer('rmbz_release_action_' . $release_id);

    global $wpdb;
    $t = $wpdb->prefix . 'rmbz_distro_releases';
    $current = $wpdb->get_row( $wpdb->prepare("SELECT status, title FROM $t WHERE id = %d", $release_id) );
    if ( ! $current ) wp_die('Lançamento não encontrado.');
    if ( $current->status !== 'takedown_requested' ) {
        wp_safe_redirect( admin_url('admin.php?page=rmbz-admin-distribution&tab=releases&view=detail&id=' . $release_id . '&msg=takedown_invalid_state') );
        exit;
    }

    $wpdb->update( $t,
        [ 'status' => 'taken_down' ],
        [ 'id' => $release_id ],
        [ '%s' ], [ '%d' ]
    );

    rmbz_admin_log_status_change( $release_id, 'takedown_requested', 'taken_down', 'Takedown finalizado pelo admin — release removido das lojas' );

    // Notificar artista
    if ( function_exists('rmbz_add_notification') ) {
        $owner_tel = $wpdb->get_var( $wpdb->prepare(
            "SELECT artist_telemovel FROM $t WHERE id = %d", $release_id
        ) );
        if ( $owner_tel ) {
            rmbz_add_notification(
                $owner_tel,
                sprintf( '🚫 O takedown de "%s" foi finalizado. O lançamento foi removido das lojas.', $current->title ?: 'Lançamento' )
            );
        }
    }

    wp_safe_redirect( admin_url('admin.php?page=rmbz-admin-distribution&tab=releases&view=detail&id=' . $release_id . '&msg=takedown_finalized') );
    exit;
}
add_action('admin_post_rmbz_release_takedown_confirm', 'rmbz_admin_release_takedown_confirm_handler');


/**
 * ----------------------------------------------------------------------------
 * HANDLER — Cancelar pedido de takedown (takedown_requested → live)
 * ----------------------------------------------------------------------------
 * Admin decide rejeitar o pedido — o release volta a estar live e o artista
 * é notificado.
 */
function rmbz_admin_release_takedown_cancel_handler() {
    if ( ! current_user_can('manage_options') ) wp_die('Sem permissão.');
    $release_id = (int) ($_POST['release_id'] ?? 0);
    if ( ! $release_id ) wp_die('ID inválido.');
    check_admin_referer('rmbz_release_action_' . $release_id);

    global $wpdb;
    $t = $wpdb->prefix . 'rmbz_distro_releases';
    $current = $wpdb->get_row( $wpdb->prepare("SELECT status, title FROM $t WHERE id = %d", $release_id) );
    if ( ! $current ) wp_die('Lançamento não encontrado.');
    if ( $current->status !== 'takedown_requested' ) {
        wp_safe_redirect( admin_url('admin.php?page=rmbz-admin-distribution&tab=releases&view=detail&id=' . $release_id . '&msg=takedown_invalid_state') );
        exit;
    }

    // Volta a 'live' e limpa as flags de takedown
    $wpdb->update( $t,
        [
            'status' => 'live',
            'takedown_requested' => 0,
            'takedown_reason'    => null,
        ],
        [ 'id' => $release_id ],
        [ '%s', '%d', '%s' ], [ '%d' ]
    );

    rmbz_admin_log_status_change( $release_id, 'takedown_requested', 'live', 'Pedido de takedown cancelado pelo admin — release continua nas lojas' );

    // Notificar artista
    if ( function_exists('rmbz_add_notification') ) {
        $owner_tel = $wpdb->get_var( $wpdb->prepare(
            "SELECT artist_telemovel FROM $t WHERE id = %d", $release_id
        ) );
        if ( $owner_tel ) {
            rmbz_add_notification(
                $owner_tel,
                sprintf( '⟲ O teu pedido de takedown para "%s" foi cancelado pelo admin. O lançamento continua disponível nas lojas. Contacta o suporte se tiveres dúvidas.', $current->title ?: 'Lançamento' )
            );
        }
    }

    wp_safe_redirect( admin_url('admin.php?page=rmbz-admin-distribution&tab=releases&view=detail&id=' . $release_id . '&msg=takedown_cancelled') );
    exit;
}
add_action('admin_post_rmbz_release_takedown_cancel', 'rmbz_admin_release_takedown_cancel_handler');


/* ============================================================================
 * UTILITIES
 * ============================================================================ */

/**
 * Computa checklist automática de revisão de um lançamento.
 * Retorna array de ['label' => ..., 'pass' => bool].
 */
function rmbz_admin_compute_review_checklist( $release, $tracks ) {
    global $wpdb;
    $checks = [];

    // 1. Tem pelo menos uma faixa
    $checks[] = [
        'label' => 'Tem pelo menos uma faixa',
        'pass'  => ! empty($tracks),
    ];

    // 2. Todas as faixas têm título
    $all_titled = true;
    foreach ( (array) $tracks as $t ) {
        if ( empty(trim($t->track_title ?? '')) ) { $all_titled = false; break; }
    }
    $checks[] = [
        'label' => 'Todas as faixas têm título',
        'pass'  => $all_titled && ! empty($tracks),
    ];

    // 3. Todas as faixas têm songwriters
    $all_sw = true;
    foreach ( (array) $tracks as $t ) {
        $extra = ! empty($t->extra_data) ? json_decode($t->extra_data, true) : [];
        if ( empty($extra['songwriters']) ) { $all_sw = false; break; }
    }
    $checks[] = [
        'label' => 'Todas as faixas têm songwriters',
        'pass'  => $all_sw && ! empty($tracks),
    ];

    // 4. Capa existe
    $checks[] = [
        'label' => 'Capa carregada',
        'pass'  => ! empty($release->cover_image),
    ];

    // 5. Data de lançamento futura ou válida
    $has_date = ! empty($release->release_date);
    $checks[] = [
        'label' => 'Data de lançamento definida',
        'pass'  => $has_date,
    ];

    // 6. Género definido
    $checks[] = [
        'label' => 'Género principal definido',
        'pass'  => ! empty($release->primary_genre),
    ];

    // 7. Splits somam 100% em todas as faixas que têm splits
    $splits_valid = true;
    $t_splits = $wpdb->prefix . 'rmbz_track_splits';
    if ( $wpdb->get_var("SHOW TABLES LIKE '$t_splits'") === $t_splits ) {
        foreach ( (array) $tracks as $t ) {
            $sum = (float) $wpdb->get_var( $wpdb->prepare(
                "SELECT COALESCE(SUM(percentage), 0) FROM $t_splits WHERE track_id = %d",
                $t->id
            ) );
            if ( $sum > 0 && abs($sum - 100.0) > 0.01 ) {
                $splits_valid = false; break;
            }
        }
    }
    $checks[] = [
        'label' => 'Splits somam 100% (onde existem)',
        'pass'  => $splits_valid,
    ];

    // 8. Plataformas configuradas
    $plats_ok = false;
    $t_plats = $wpdb->prefix . 'rmbz_distro_release_platforms';
    if ( $wpdb->get_var("SHOW TABLES LIKE '$t_plats'") === $t_plats ) {
        $plats_ok = (int) $wpdb->get_var( $wpdb->prepare(
            "SELECT COALESCE(user_confirmed,0) FROM $t_plats WHERE release_id = %d",
            $release->id
        ) ) === 1;
    }
    $checks[] = [
        'label' => 'Plataformas/territórios confirmados',
        'pass'  => $plats_ok,
    ];

    // Permitir a módulos externos (ex. distribution-intelligence.php) adicionar
    // mais checks rigorosos (loudness, ISRCs duplicados, capa verificada, etc.).
    $checks = apply_filters('rmbz_admin_review_checklist_extra', $checks, $release, $tracks);

    return $checks;
}

function rmbz_admin_generate_upc() {
    $prefix = get_option('rmbz_upc_prefix', '858');
    $body = $prefix . str_pad( mt_rand(0, 999999999), 9, '0', STR_PAD_LEFT );
    $sum = 0;
    for ( $i = 0; $i < 12; $i++ ) {
        $d = (int) $body[$i];
        $sum += ($i % 2 === 0) ? $d * 3 : $d;
    }
    $check = (10 - ($sum % 10)) % 10;
    return $body . $check;
}

function rmbz_admin_generate_isrc() {
    $country  = get_option('rmbz_isrc_country', 'MZ');
    $registrant = get_option('rmbz_isrc_registrant', '0AB');
    $year = substr( date('Y'), -2 );
    $sequence = str_pad( mt_rand(0, 99999), 5, '0', STR_PAD_LEFT );
    return $country . $registrant . $year . $sequence;
}

function rmbz_admin_reject_reason_label( $code ) {
    $map = [
        'low_quality_audio'       => 'Áudio com qualidade insuficiente',
        'low_quality_cover'       => 'Capa com resolução/qualidade insuficiente',
        'metadata_incomplete'     => 'Metadata incompleta',
        'copyright_concern'       => 'Possível violação de direitos autorais',
        'explicit_not_flagged'    => 'Conteúdo explícito não declarado',
        'duplicate'               => 'Duplicado de lançamento anterior',
        'cover_third_party_logo'  => 'Capa contém logo de terceiros',
        'other'                   => 'Outro motivo',
    ];
    return $map[$code] ?? 'Motivo não especificado';
}

function rmbz_admin_log_status_change( $release_id, $old_status, $new_status, $note ) {
    global $wpdb;
    $t = $wpdb->prefix . 'rmbz_distro_status_history';
    if ( $wpdb->get_var("SHOW TABLES LIKE '$t'") !== $t ) return;

    $user = wp_get_current_user();
    $changed_by = $user && $user->exists() ? ( $user->user_login ?: 'admin#' . $user->ID ) : 'sistema';

    $wpdb->insert( $t, [
        'release_id'  => $release_id,
        'from_status' => $old_status,
        'to_status'   => $new_status,
        'changed_by'  => $changed_by,
        'reason_text' => $note,
        'created_at'  => current_time('mysql'),
    ], [ '%d','%s','%s','%s','%s','%s' ] );
}


/* ============================================================================
 * [1.5.181] BULK APPROVE — aprovar múltiplos releases em massa
 *
 * Recebe `ids` (CSV de IDs), aprova um a um, regista manifest para undo,
 * redireciona com snackbar.
 * ============================================================================ */
function rmbz_admin_release_bulk_approve_handler() {
    if ( ! current_user_can('manage_options') ) wp_die('Sem permissão.');
    check_admin_referer('rmbz_release_bulk_action');

    // [1.5.184] DESACTIVADO POR POLÍTICA — nunca aprovar sem checklist.
    // O bulk approve era um atalho perigoso: 10+ releases aprovados sem
    // sequer passar pelo checklist (auto + manual) que existe na página
    // de detalhe. A UI já não expõe este botão (1.5.184) mas mantemos a
    // função registada como guard contra requests directos via POST com
    // nonce capturado de uma página antiga.
    wp_safe_redirect( admin_url('admin.php?page=rmbz-admin-distribution&tab=approval&msg=bulk_approve_disabled') );
    exit;

    // ────────── CÓDIGO LEGADO ABAIXO — NÃO EXECUTADO ──────────
    $ids_raw = (string) ( $_POST['ids'] ?? '' );
    $ids = array_filter( array_map('intval', explode(',', $ids_raw)), function($v){ return $v > 0; } );
    if ( empty($ids) ) {
        wp_safe_redirect( admin_url('admin.php?page=rmbz-admin-distribution&tab=approval&msg=invalid') );
        exit;
    }

    global $wpdb;
    $t = $wpdb->prefix . 'rmbz_distro_releases';
    $manifest = []; // para undo: lista de [id, prev_status]
    $approved_count = 0;

    foreach ( $ids as $rid ) {
        $current = $wpdb->get_row( $wpdb->prepare("SELECT id, status FROM $t WHERE id = %d", $rid) );
        if ( ! $current ) continue;
        if ( ! in_array( $current->status, ['pendente','pending','submitted','returned'], true ) ) continue;

        // Reutilizar workflow existente para garantir códigos/transições correctas
        if ( function_exists('rmbz_release_workflow_assign_codes') ) {
            rmbz_release_workflow_assign_codes( $rid );
        }
        if ( function_exists('rmbz_release_workflow_transition') ) {
            rmbz_release_workflow_transition( $rid, 'approved', 'Bulk approve pela fila' );
        } else {
            // Fallback minimal
            $wpdb->update( $t, [ 'status' => 'approved' ], [ 'id' => $rid ], [ '%s' ], [ '%d' ] );
        }

        $manifest[] = [ 'id' => $rid, 'prev_status' => $current->status ];
        $approved_count++;
    }

    // Token undo
    $undo_token = '';
    if ( $approved_count > 0 ) {
        $undo_token = wp_generate_password( 24, false, false );
        set_transient(
            'rmbz_rel_undo_' . $undo_token,
            [
                'action'   => 'bulk_approve',
                'manifest' => $manifest,
            ],
            5 * MINUTE_IN_SECONDS
        );
    }

    $url = admin_url('admin.php?page=rmbz-admin-distribution&tab=approval&msg=bulk_approved&n=' . $approved_count);
    if ( $undo_token ) $url .= '&undo=' . $undo_token;
    wp_safe_redirect( $url );
    exit;
}
add_action('admin_post_rmbz_release_bulk_approve', 'rmbz_admin_release_bulk_approve_handler');


/* ============================================================================
 * [1.5.181] BULK REJECT — rejeitar múltiplos com mesmo motivo
 *
 * Recebe `ids` + `reject_code` + `reject_note` opcional.
 * ============================================================================ */
function rmbz_admin_release_bulk_reject_handler() {
    if ( ! current_user_can('manage_options') ) wp_die('Sem permissão.');
    check_admin_referer('rmbz_release_bulk_action');

    $ids_raw = (string) ( $_POST['ids'] ?? '' );
    $ids = array_filter( array_map('intval', explode(',', $ids_raw)), function($v){ return $v > 0; } );
    $code = sanitize_key( $_POST['reject_code'] ?? 'other' );
    $note = sanitize_textarea_field( $_POST['reject_note'] ?? '' );

    if ( empty($ids) ) {
        wp_safe_redirect( admin_url('admin.php?page=rmbz-admin-distribution&tab=approval&msg=invalid') );
        exit;
    }

    global $wpdb;
    $t = $wpdb->prefix . 'rmbz_distro_releases';
    $reject_msg = function_exists('rmbz_admin_reject_reason_label')
        ? rmbz_admin_reject_reason_label($code)
        : $code;
    if ( $note ) $reject_msg .= ' — ' . $note;

    $manifest = [];
    $rejected_count = 0;

    foreach ( $ids as $rid ) {
        $current = $wpdb->get_row( $wpdb->prepare("SELECT id, status, rejection_reason FROM $t WHERE id = %d", $rid) );
        if ( ! $current ) continue;

        $wpdb->update( $t,
            [ 'status' => 'rejected', 'rejection_reason' => $reject_msg ],
            [ 'id' => $rid ],
            [ '%s', '%s' ],
            [ '%d' ]
        );

        if ( function_exists('rmbz_admin_log_status_change') ) {
            rmbz_admin_log_status_change( $rid, $current->status, 'rejected', $reject_msg );
        }
        do_action('rmbz_distro_status_changed', $rid, $current->status, 'rejected');

        $manifest[] = [
            'id'              => $rid,
            'prev_status'     => $current->status,
            'prev_rejection'  => $current->rejection_reason,
        ];
        $rejected_count++;
    }

    $undo_token = '';
    if ( $rejected_count > 0 ) {
        $undo_token = wp_generate_password( 24, false, false );
        set_transient(
            'rmbz_rel_undo_' . $undo_token,
            [
                'action'   => 'bulk_reject',
                'manifest' => $manifest,
            ],
            5 * MINUTE_IN_SECONDS
        );
    }

    $url = admin_url('admin.php?page=rmbz-admin-distribution&tab=approval&msg=bulk_rejected&n=' . $rejected_count);
    if ( $undo_token ) $url .= '&undo=' . $undo_token;
    wp_safe_redirect( $url );
    exit;
}
add_action('admin_post_rmbz_release_bulk_reject', 'rmbz_admin_release_bulk_reject_handler');


/* ============================================================================
 * [1.5.181] UNDO HANDLER — reverter bulk approve / reject
 *
 * Lê manifest do transient, repõe status anterior, apaga transient.
 * ============================================================================ */
function rmbz_admin_release_undo_handler() {
    if ( ! current_user_can('manage_options') ) {
        wp_send_json_error( [ 'msg' => 'no_permission' ], 403 );
    }
    if ( ! isset($_POST['_nonce']) || ! wp_verify_nonce( $_POST['_nonce'], 'rmbz_release_undo' ) ) {
        wp_send_json_error( [ 'msg' => 'nonce_invalid' ], 403 );
    }

    $token = sanitize_text_field( $_POST['undo_token'] ?? '' );
    if ( empty($token) ) {
        wp_send_json_error( [ 'msg' => 'invalid_token' ], 400 );
    }

    $key  = 'rmbz_rel_undo_' . $token;
    $data = get_transient( $key );
    if ( empty($data) || ! is_array($data) ) {
        wp_send_json_error( [ 'msg' => 'expired_or_invalid' ], 410 );
    }
    delete_transient( $key ); // impede double-undo

    global $wpdb;
    $t = $wpdb->prefix . 'rmbz_distro_releases';
    $manifest = isset($data['manifest']) ? (array) $data['manifest'] : [];
    $action   = $data['action'] ?? '';
    $reverted = 0;

    $wpdb->query('START TRANSACTION');
    try {
        foreach ( $manifest as $m ) {
            $rid         = (int) ( $m['id'] ?? 0 );
            $prev_status = $m['prev_status'] ?? '';
            if ( $rid <= 0 || empty($prev_status) ) continue;

            $update = [ 'status' => $prev_status ];
            $fmt    = [ '%s' ];

            // Para reject, restaurar também a rejection_reason anterior
            if ( $action === 'bulk_reject' && array_key_exists('prev_rejection', $m) ) {
                $update['rejection_reason'] = $m['prev_rejection'];
                $fmt[] = '%s';
            }

            $wpdb->update( $t, $update, [ 'id' => $rid ], $fmt, [ '%d' ] );
            do_action('rmbz_distro_status_changed', $rid,
                $action === 'bulk_approve' ? 'approved' : 'rejected',
                $prev_status
            );
            $reverted++;
        }
        $wpdb->query('COMMIT');
    } catch ( Exception $e ) {
        $wpdb->query('ROLLBACK');
        error_log('[1MZ] Bulk undo falhou: ' . $e->getMessage());
        wp_send_json_error( [ 'msg' => 'rollback' ], 500 );
    }

    wp_send_json_success( [ 'reverted' => $reverted, 'action' => $action ] );
}
add_action('wp_ajax_rmbz_release_undo', 'rmbz_admin_release_undo_handler');


/* ============================================================================
 * [1.5.192] HANDLER AJAX — gravar ISRC editado de uma faixa
 *
 * Recebe: track_id + isrc + nonce
 * Devolve: success ou error com motivo
 *
 * Validações:
 *   - Permissão admin
 *   - Nonce válido (específico do track_id)
 *   - Track existe
 *   - Release não está live/distribuido (gate de status)
 *   - Formato ISRC válido (12 chars CCXYZNNNNN) ou vazio (limpar)
 *   - ISRC não duplicado em outra faixa de outra release
 *
 * Side effects:
 *   - UPDATE rmbz_distro_tracks SET isrc_code = X
 *   - Log no histórico de status (audit trail) — opcional
 * ============================================================================ */
function rmbz_admin_track_isrc_save_handler() {
    if ( ! current_user_can('manage_options') ) {
        wp_send_json_error( [ 'msg' => 'Sem permissão' ], 403 );
    }

    $track_id = (int) ( $_POST['track_id'] ?? 0 );
    if ( $track_id <= 0 ) {
        wp_send_json_error( [ 'msg' => 'ID de faixa inválido' ], 400 );
    }

    if ( ! isset($_POST['_nonce']) || ! wp_verify_nonce( $_POST['_nonce'], 'rmbz_track_isrc_save_' . $track_id ) ) {
        wp_send_json_error( [ 'msg' => 'Nonce inválido' ], 403 );
    }

    // Normalizar ISRC: uppercase + remover não-alphanum
    $isrc_raw = (string) ( $_POST['isrc'] ?? '' );
    $isrc = strtoupper( preg_replace('/[^A-Z0-9]/i', '', $isrc_raw) );

    // Permitir vazio (limpar) ou exactamente 12 chars
    if ( $isrc !== '' && strlen($isrc) !== 12 ) {
        wp_send_json_error( [ 'msg' => 'ISRC tem que ter 12 caracteres alfanuméricos' ], 400 );
    }

    // Validar formato CCXYZNNNNN se não vazio.
    // [1.5.193] Versão simplificada — 2 letras (país) + 10 alfanum.
    // ISRC standard tem subdivisão registrant/ano/designação mas distribuidores
    // reais variam. Melhor permissivo aqui.
    if ( $isrc !== '' && ! preg_match('/^[A-Z]{2}[A-Z0-9]{10}$/', $isrc) ) {
        wp_send_json_error( [ 'msg' => 'Formato inválido. Esperado: 2 letras de país (ex: BG) + 10 caracteres alfanuméricos. Total: 12 caracteres.' ], 400 );
    }

    global $wpdb;
    $t_tracks   = $wpdb->prefix . 'rmbz_distro_tracks';
    $t_releases = $wpdb->prefix . 'rmbz_distro_releases';

    // Buscar track + release
    $track = $wpdb->get_row( $wpdb->prepare(
        "SELECT t.id, t.release_id, t.isrc_code AS current_isrc, t.track_title, r.status AS release_status, r.id AS rel_id
         FROM $t_tracks t
         LEFT JOIN $t_releases r ON t.release_id = r.id
         WHERE t.id = %d",
        $track_id
    ) );

    if ( ! $track ) {
        wp_send_json_error( [ 'msg' => 'Faixa não encontrada' ], 404 );
    }

    // Gate de status — não permitir editar se já está nas lojas
    if ( in_array( $track->release_status, ['live','distribuido'], true ) ) {
        wp_send_json_error( [ 'msg' => 'Faixa já está nas lojas — ISRC não pode ser alterado' ], 403 );
    }

    // Verificar duplicado (só se isrc não vazio)
    if ( $isrc !== '' ) {
        $existing = $wpdb->get_row( $wpdb->prepare(
            "SELECT t.id, t.track_title, r.id AS rid, r.title AS rtitle
             FROM $t_tracks t
             LEFT JOIN $t_releases r ON t.release_id = r.id
             WHERE t.isrc_code = %s AND t.id != %d
             LIMIT 1",
            $isrc, $track_id
        ) );
        if ( $existing ) {
            wp_send_json_error( [
                'msg' => sprintf( 'ISRC já usado por "%s" (release #%d)',
                    $existing->track_title ?: '(sem título)',
                    (int) $existing->rid
                ),
            ], 409 );
        }
    }

    // Sem mudança real?
    $current = strtoupper( preg_replace('/[^A-Z0-9]/i', '', (string) $track->current_isrc) );
    if ( $current === $isrc ) {
        wp_send_json_success( [ 'msg' => 'Sem alterações', 'isrc' => $isrc ] );
    }

    // Gravar
    $updated = $wpdb->update(
        $t_tracks,
        [ 'isrc_code' => $isrc ],
        [ 'id' => $track_id ],
        [ '%s' ],
        [ '%d' ]
    );

    if ( $updated === false ) {
        wp_send_json_error( [ 'msg' => 'Erro ao gravar na base de dados' ], 500 );
    }

    // Audit trail — registar no histórico de status como nota
    if ( function_exists('rmbz_admin_log_status_change') && $track->rel_id ) {
        $note = sprintf(
            'ISRC da faixa "%s" editado manualmente: %s → %s',
            $track->track_title ?: '(sem título)',
            $current ?: '(vazio)',
            $isrc ?: '(vazio)'
        );
        rmbz_admin_log_status_change( (int) $track->rel_id, $track->release_status, $track->release_status, $note );
    }

    wp_send_json_success( [ 'msg' => 'Guardado', 'isrc' => $isrc ] );
}
add_action('wp_ajax_rmbz_track_isrc_save', 'rmbz_admin_track_isrc_save_handler');


/* ============================================================================
 * [1.5.196] HANDLER AJAX — gravar campo editável do RELEASE
 *
 * Sistema unificado para edição inline de múltiplos campos.
 * Recebe: release_id + field + value + nonce
 * Devolve: success (com display_value formatado) ou error
 *
 * Campos permitidos (whitelist):
 *   - title          (string, max 200)
 *   - release_date   (date YYYY-MM-DD)
 *   - primary_genre  (string, da lista de géneros conhecidos)
 *   - secondary_genre, label_name, language (futuros)
 *
 * Validações:
 *   - Permissão admin
 *   - Nonce válido (específico do release_id)
 *   - Release existe
 *   - Status NÃO é live/distribuido (gate absoluto)
 *   - Field está na whitelist
 *   - Valor passa validação específica do campo
 *
 * Side effects:
 *   - UPDATE rmbz_distro_releases SET <field> = <value>
 *   - Log no histórico (audit trail)
 * ============================================================================ */
function rmbz_admin_release_field_save_handler() {
    if ( ! current_user_can('manage_options') ) {
        wp_send_json_error( [ 'msg' => 'Sem permissão' ], 403 );
    }

    $release_id = (int) ( $_POST['release_id'] ?? 0 );
    if ( $release_id <= 0 ) {
        wp_send_json_error( [ 'msg' => 'ID de lançamento inválido' ], 400 );
    }

    if ( ! isset($_POST['_nonce']) || ! wp_verify_nonce( $_POST['_nonce'], 'rmbz_release_field_save_' . $release_id ) ) {
        wp_send_json_error( [ 'msg' => 'Nonce inválido' ], 403 );
    }

    $field = sanitize_key( $_POST['field'] ?? '' );
    $value_raw = (string) ( $_POST['value'] ?? '' );

    // Whitelist de campos editáveis e respectiva validação/sanitização
    $allowed_fields = [
        'title' => [
            'type' => 'text',
            'maxlength' => 200,
            'format' => '%s',
        ],
        'release_date' => [
            'type' => 'date',
            'format' => '%s',
        ],
        'primary_genre' => [
            'type' => 'genre',
            'maxlength' => 100,
            'format' => '%s',
        ],
        'secondary_genre' => [
            'type' => 'genre',
            'maxlength' => 100,
            'format' => '%s',
        ],
        'label_name' => [
            'type' => 'text',
            'maxlength' => 200,
            'format' => '%s',
        ],
        'language' => [
            'type' => 'text',
            'maxlength' => 50,
            'format' => '%s',
        ],
    ];

    if ( ! isset( $allowed_fields[ $field ] ) ) {
        wp_send_json_error( [ 'msg' => 'Campo não permitido: ' . $field ], 400 );
    }
    $cfg = $allowed_fields[ $field ];

    global $wpdb;
    $t_releases = $wpdb->prefix . 'rmbz_distro_releases';

    // Buscar release
    $release = $wpdb->get_row( $wpdb->prepare(
        "SELECT id, status, title FROM $t_releases WHERE id = %d",
        $release_id
    ) );
    if ( ! $release ) {
        wp_send_json_error( [ 'msg' => 'Lançamento não encontrado' ], 404 );
    }

    // Gate absoluto: live/distribuido bloqueados
    if ( in_array( $release->status, ['live','distribuido'], true ) ) {
        wp_send_json_error( [ 'msg' => 'Lançamento nas lojas — edição bloqueada' ], 403 );
    }

    // Validar/sanitizar valor consoante o tipo
    $value = '';
    $display_value = '';
    switch ( $cfg['type'] ) {
        case 'text':
            $value = sanitize_text_field( $value_raw );
            if ( ! empty( $cfg['maxlength'] ) && mb_strlen( $value ) > $cfg['maxlength'] ) {
                wp_send_json_error( [ 'msg' => 'Valor muito longo (máximo ' . $cfg['maxlength'] . ' caracteres)' ], 400 );
            }
            $display_value = $value !== '' ? $value : '—';
            break;

        case 'date':
            $value = trim( $value_raw );
            if ( $value !== '' ) {
                // Validar formato YYYY-MM-DD
                if ( ! preg_match('/^\d{4}-\d{2}-\d{2}$/', $value) ) {
                    wp_send_json_error( [ 'msg' => 'Data inválida — formato esperado YYYY-MM-DD' ], 400 );
                }
                $ts = strtotime( $value );
                if ( ! $ts || $ts < strtotime('1900-01-01') || $ts > strtotime('+10 years') ) {
                    wp_send_json_error( [ 'msg' => 'Data fora dos limites razoáveis' ], 400 );
                }
                $display_value = date( 'd/m/Y', $ts );
            } else {
                $display_value = '—';
            }
            break;

        case 'genre':
            $value = sanitize_text_field( $value_raw );
            if ( ! empty( $cfg['maxlength'] ) && mb_strlen( $value ) > $cfg['maxlength'] ) {
                wp_send_json_error( [ 'msg' => 'Género muito longo' ], 400 );
            }
            $display_value = $value !== '' ? $value : '—';
            break;

        default:
            wp_send_json_error( [ 'msg' => 'Tipo de campo desconhecido' ], 500 );
    }

    // Sem mudança real?
    $current_value = $wpdb->get_var( $wpdb->prepare(
        "SELECT $field FROM $t_releases WHERE id = %d",
        $release_id
    ) );
    if ( (string) $current_value === (string) $value ) {
        wp_send_json_success( [ 'msg' => 'Sem alterações', 'display_value' => $display_value ] );
    }

    // Gravar
    $updated = $wpdb->update(
        $t_releases,
        [ $field => $value ],
        [ 'id' => $release_id ],
        [ $cfg['format'] ],
        [ '%d' ]
    );

    if ( $updated === false ) {
        wp_send_json_error( [ 'msg' => 'Erro ao gravar na base de dados' ], 500 );
    }

    // Audit trail
    if ( function_exists('rmbz_admin_log_status_change') ) {
        $note = sprintf(
            'Campo "%s" do release editado por admin: %s → %s',
            $field,
            $current_value !== null && $current_value !== '' ? $current_value : '(vazio)',
            $value !== '' ? $value : '(vazio)'
        );
        rmbz_admin_log_status_change( $release_id, $release->status, $release->status, $note );
    }

    wp_send_json_success( [
        'msg' => 'Guardado',
        'value' => $value,
        'display_value' => $display_value,
    ] );
}
add_action('wp_ajax_rmbz_release_field_save', 'rmbz_admin_release_field_save_handler');
