<?php
// includes/admin/admin-unclaimed-royalties.php
// Rewritten for rich metadata display

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

/* ============================================================================
 * PÁGINA "NÃO RECLAMADOS" — Black Box com metadata rica
 * ============================================================================ */
function rmbz_render_unclaimed_royalties_page() {
    global $wpdb;
    $t_unclaimed = $wpdb->prefix . 'rmbz_distro_unclaimed';

    // Processar atribuição manual
    if ( isset($_POST['action']) && $_POST['action'] === 'assign_royalty' ) {
        check_admin_referer('rmbz_assign_royalty_nonce');
        rmbz_handle_manual_assignment();
    }

    // Filtros
    $f_search = isset($_GET['u_search']) ? sanitize_text_field($_GET['u_search']) : '';
    $f_artist = isset($_GET['u_artist']) ? sanitize_text_field($_GET['u_artist']) : '';
    $f_min    = isset($_GET['u_min']) ? (float) $_GET['u_min'] : 0;

    $where = ["status = 'pending'"];
    $params = [];
    if ( $f_search ) {
        $where[] = "(isrc LIKE %s OR track_title LIKE %s OR artist_name LIKE %s OR upc_code LIKE %s)";
        $like = '%' . $wpdb->esc_like($f_search) . '%';
        $params[] = $like; $params[] = $like; $params[] = $like; $params[] = $like;
    }
    if ( $f_artist ) {
        $where[] = "artist_name LIKE %s";
        $params[] = '%' . $wpdb->esc_like($f_artist) . '%';
    }
    if ( $f_min > 0 ) {
        $where[] = "amount >= %f";
        $params[] = $f_min;
    }
    $where_sql = implode(' AND ', $where);

    // Agregar por ISRC (pode ter múltiplos períodos)
    $sql = "SELECT
                isrc,
                MAX(track_title)   AS track_title,
                MAX(artist_name)   AS artist_name,
                MAX(album)         AS album,
                MAX(label)         AS label,
                MAX(upc_code)      AS upc_code,
                SUM(amount)        AS total_amount,
                SUM(streams_total) AS total_streams,
                SUM(line_count)    AS total_lines,
                MIN(report_date)   AS first_date,
                MAX(report_date)   AS last_date,
                GROUP_CONCAT(DISTINCT platform ORDER BY platform SEPARATOR ', ') AS platforms_csv,
                GROUP_CONCAT(DISTINCT country  ORDER BY country  SEPARATOR ', ') AS countries_csv,
                COUNT(id) AS rows_in_group
            FROM $t_unclaimed
            WHERE $where_sql
            GROUP BY isrc
            ORDER BY total_amount DESC
            LIMIT 200";
    $groups = $params ? $wpdb->get_results( $wpdb->prepare($sql, $params) ) : $wpdb->get_results($sql);

    // Totais agregados
    $sql_total = "SELECT
                    SUM(amount) AS holding,
                    SUM(streams_total) AS streams,
                    COUNT(DISTINCT isrc) AS uniq_isrcs,
                    COUNT(DISTINCT artist_name) AS uniq_artists
                  FROM $t_unclaimed WHERE status = 'pending'";
    $tot = $wpdb->get_row($sql_total);
    $total_holding = (float) ($tot->holding ?? 0);
    $total_streams = (int)   ($tot->streams ?? 0);
    $total_isrcs   = (int)   ($tot->uniq_isrcs ?? 0);
    $total_artists = (int)   ($tot->uniq_artists ?? 0);

    // Top artistas por valor retido (para sugerir onde está o dinheiro maior)
    $top_artists = $wpdb->get_results(
        "SELECT artist_name, SUM(amount) AS total, COUNT(DISTINCT isrc) AS tracks_count
         FROM $t_unclaimed
         WHERE status = 'pending' AND artist_name IS NOT NULL AND artist_name != ''
         GROUP BY artist_name
         ORDER BY total DESC
         LIMIT 5"
    ) ?: [];

    ?>
    <div class="rmbz-bb-wrap">

        <div class="rmbz-bb-header">
            <div>
                <div class="kicker">Caixa forte · Black Box</div>
                <h1>Royalties não reclamados</h1>
                <p>Estes valores foram importados, mas o ISRC não existe na base de faixas 1MZ. Atribui a um artista para creditar a wallet.</p>
            </div>
        </div>

        <div class="rmbz-bb-kpis">
            <div class="rmbz-bb-kpi red">
                <div class="lbl">Total retido</div>
                <div class="val">$<?php echo number_format($total_holding, 2); ?></div>
                <div class="sub">USD · já líquido (70% do bruto)</div>
            </div>
            <div class="rmbz-bb-kpi blue">
                <div class="lbl">Streams totais</div>
                <div class="val"><?php echo rmbz_bb_fmt_compact($total_streams); ?></div>
                <div class="sub">em <?php echo $total_isrcs; ?> faixas</div>
            </div>
            <div class="rmbz-bb-kpi purple">
                <div class="lbl">Artistas únicos</div>
                <div class="val"><?php echo $total_artists; ?></div>
                <div class="sub">identificados no CSV</div>
            </div>
            <div class="rmbz-bb-kpi amber">
                <div class="lbl">ISRCs distintos</div>
                <div class="val"><?php echo $total_isrcs; ?></div>
                <div class="sub">músicas diferentes</div>
            </div>
        </div>

        <?php
        // [1.5.165] Verificar se há linhas em unclaimed que correspondem a
        // matches já aprovados (lixo histórico). Se houver, mostrar botão
        // de cleanup retroactivo.
        $t_match_chk = $wpdb->prefix . 'rmbz_distro_match_review';
        $orphan_count = 0;
        $orphan_amount = 0;
        if ( $wpdb->get_var("SHOW TABLES LIKE '$t_match_chk'") === $t_match_chk ) {
            $orphan_check = $wpdb->get_row(
                "SELECT COUNT(*) AS cnt, COALESCE(SUM(u.amount), 0) AS amt
                 FROM {$t_unclaimed} u
                 INNER JOIN {$t_match_chk} mr
                    ON mr.csv_isrc = u.isrc
                    AND DATE_FORMAT(STR_TO_DATE(CONCAT(LEFT(mr.report_date, 7), '-01'), '%Y-%m-%d'), '%Y-%m-%d') = u.report_date
                 WHERE u.status = 'pending'
                   AND mr.status = 'approved'"
            );
            $orphan_count  = (int) ($orphan_check->cnt ?? 0);
            $orphan_amount = (float) ($orphan_check->amt ?? 0);
        }
        ?>

        <?php if ( $orphan_count > 0 ): ?>
            <div class="rmbz-bb-card" style="border:1px solid rgba(245,158,11,0.4); background:rgba(245,158,11,0.06);">
                <div class="card-head">
                    <strong style="color:#f59e0b;">⚠ Lixo histórico detectado</strong>
                </div>
                <p style="margin:8px 0; color:#d4d4d4;">
                    Há <strong><?php echo $orphan_count; ?></strong> linha(s) marcadas como "Não Reclamado"
                    (total <strong>$<?php echo number_format($orphan_amount, 2); ?></strong>) que correspondem a matches
                    JÁ APROVADOS em <em>Matches a Rever</em>. O dinheiro JÁ foi atribuído aos artistas — estas linhas são
                    lixo visual de aprovações anteriores ao fix 1.5.165.
                </p>
                <p style="margin:8px 0;">
                    Esta acção é segura e idempotente: só marca linhas com status='pending' que têm match aprovado.
                </p>
                <form method="post" action="<?php echo esc_url( admin_url('admin-post.php') ); ?>" style="margin-top:12px;">
                    <input type="hidden" name="action" value="rmbz_unclaimed_backfill_assigned">
                    <?php wp_nonce_field('rmbz_unclaimed_backfill_assigned'); ?>
                    <button type="submit" class="button button-primary">
                        🧹 Limpar (<?php echo $orphan_count; ?>)
                    </button>
                </form>
            </div>
        <?php endif; ?>

        <?php if ( ! empty($top_artists) ): ?>
            <div class="rmbz-bb-card">
                <div class="card-head">
                    <strong>💡 Top artistas com dinheiro retido</strong>
                    <span>clique para filtrar</span>
                </div>
                <div class="top-artists">
                    <?php foreach ( $top_artists as $a ):
                        $url = add_query_arg('u_artist', $a->artist_name);
                    ?>
                        <a href="<?php echo esc_url($url); ?>" class="artist-chip">
                            <strong><?php echo esc_html($a->artist_name ?: '—'); ?></strong>
                            <span>$<?php echo number_format($a->total, 2); ?></span>
                            <small><?php echo $a->tracks_count; ?> faixa(s)</small>
                        </a>
                    <?php endforeach; ?>
                </div>
            </div>
        <?php endif; ?>

        <form method="get" class="rmbz-bb-filters">
            <input type="hidden" name="page" value="rmbz-admin-distribution">
            <input type="hidden" name="tab" value="unclaimed">
            <div class="fg">
                <label>Pesquisar</label>
                <input type="text" name="u_search" value="<?php echo esc_attr($f_search); ?>" placeholder="ISRC, título, artista, UPC...">
            </div>
            <div class="fg">
                <label>Só artista</label>
                <input type="text" name="u_artist" value="<?php echo esc_attr($f_artist); ?>" placeholder="Nome parcial">
            </div>
            <div class="fg">
                <label>Valor mínimo ($)</label>
                <input type="number" name="u_min" value="<?php echo esc_attr($f_min); ?>" step="0.01" placeholder="0.00" style="width:100px;">
            </div>
            <div class="fa">
                <button type="submit" class="button button-primary">🔍 Filtrar</button>
                <a href="?page=rmbz-admin-distribution&tab=unclaimed" class="button">Limpar</a>
            </div>
        </form>

        <?php if ( empty($groups) ): ?>
            <div class="rmbz-bb-empty">
                <div class="icon">✓</div>
                <h2>Tudo limpo!</h2>
                <p>Nenhum valor pendente com os filtros actuais.</p>
            </div>
        <?php else: ?>
            <div class="rmbz-bb-list">
            <?php foreach ( $groups as $g ):
                $period_label = $g->first_date === $g->last_date
                    ? date('m/Y', strtotime($g->first_date))
                    : date('m/Y', strtotime($g->first_date)) . ' → ' . date('m/Y', strtotime($g->last_date));
            ?>
                <div class="bb-card">
                    <div class="bb-card-left">
                        <div class="bb-title">
                            <strong><?php echo esc_html( $g->track_title ?: '(sem título)' ); ?></strong>
                            <?php if ( ! empty($g->artist_name) ): ?>
                                <span class="artist">por <?php echo esc_html($g->artist_name); ?></span>
                            <?php endif; ?>
                        </div>
                        <div class="bb-meta">
                            <?php if ( ! empty($g->album) ): ?>
                                <span class="meta-item">💿 <?php echo esc_html($g->album); ?></span>
                            <?php endif; ?>
                            <?php if ( ! empty($g->label) ): ?>
                                <span class="meta-item">🏷 <?php echo esc_html($g->label); ?></span>
                            <?php endif; ?>
                            <span class="meta-item">📅 <?php echo esc_html($period_label); ?></span>
                        </div>
                        <div class="bb-codes">
                            <code class="code-isrc" title="ISRC"><?php echo esc_html($g->isrc); ?></code>
                            <?php if ( ! empty($g->upc_code) ): ?>
                                <code class="code-upc" title="UPC/EAN"><?php echo esc_html($g->upc_code); ?></code>
                            <?php endif; ?>
                        </div>
                        <?php if ( ! empty($g->platforms_csv) || ! empty($g->countries_csv) ): ?>
                            <div class="bb-distrib">
                                <?php if ( ! empty($g->platforms_csv) ): ?>
                                    <span><strong>Lojas:</strong> <?php echo esc_html( rmbz_bb_truncate($g->platforms_csv, 60) ); ?></span>
                                <?php endif; ?>
                                <?php if ( ! empty($g->countries_csv) ): ?>
                                    <span><strong>Países:</strong> <?php echo esc_html( rmbz_bb_truncate($g->countries_csv, 40) ); ?></span>
                                <?php endif; ?>
                            </div>
                        <?php endif; ?>
                    </div>

                    <div class="bb-card-right">
                        <div class="bb-amount">
                            <strong>$<?php echo number_format($g->total_amount, 2); ?></strong>
                            <small>USD</small>
                        </div>
                        <div class="bb-stats">
                            <?php if ( $g->total_streams > 0 ): ?>
                                <span>🎧 <?php echo rmbz_bb_fmt_compact($g->total_streams); ?> streams</span>
                            <?php endif; ?>
                            <span>📊 <?php echo (int) $g->total_lines; ?> linha(s)</span>
                        </div>
                        <form method="post" action="<?php echo esc_url( add_query_arg( [ 'page' => 'rmbz-admin-distribution', 'tab' => 'unclaimed' ], admin_url('admin.php') ) ); ?>" class="bb-assign">
                            <input type="hidden" name="action" value="assign_royalty">
                            <input type="hidden" name="isrc_to_assign" value="<?php echo esc_attr($g->isrc); ?>">
                            <?php wp_nonce_field('rmbz_assign_royalty_nonce'); ?>
                            <input type="text" name="artist_phone" placeholder="Telemóvel 1MZ do artista" required pattern="[0-9+]+" title="Apenas dígitos e +">
                            <button type="submit" class="button button-primary"
                                onclick="return confirm('Atribuir $<?php echo number_format($g->total_amount, 2); ?> USD da faixa <?php echo esc_js($g->track_title ?: $g->isrc); ?> ao artista cujo telemóvel introduziu? Esta acção é irreversível.');">
                                💰 Atribuir
                            </button>
                        </form>
                    </div>
                </div>
            <?php endforeach; ?>
            </div>
            <?php if ( count($groups) >= 200 ): ?>
                <p style="text-align:center; color:var(--rmbz-text-faint, #888); margin-top:20px;">Mostrando primeiros 200 resultados. Use filtros para refinar.</p>
            <?php endif; ?>
        <?php endif; ?>

    </div>

    <style>
    .rmbz-bb-wrap {
        /* [1.5.178] Removido max-width:1400px para ocupar toda a largura
           disponível em monitores grandes. */
        width: 100%;
        max-width: 100%;
        /* [1.5.165] Tipografia DS — fallback para system fonts */
        font-family: var(--rmbz-font-body, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);
    }
    .rmbz-bb-header { margin: 20px 0 20px 0; }
    .rmbz-bb-header .kicker { color: var(--rmbz-text-faint, #888); font-size: 10px; text-transform: uppercase; letter-spacing: 1.2px; }
    .rmbz-bb-header h1 {
        font-size: 22px; margin: 2px 0 4px 0; font-weight: 500;
        color: var(--rmbz-text-strong, #222);
        /* [1.5.165] Font display para identidade visual consistente */
        font-family: var(--rmbz-font-display, inherit);
    }
    .rmbz-bb-header p { color: var(--rmbz-text-muted, #666); margin: 0; font-size: 13px; }

    .rmbz-bb-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 12px; margin-bottom: 16px; }
    .rmbz-bb-kpi { background: var(--rmbz-bg-card, #fff); border: 1px solid var(--rmbz-border-light, #e5e5e5); border-left: 3px solid #ccc; border-radius: 8px; padding: 14px 16px; }
    .rmbz-bb-kpi.red    { border-left-color: var(--rmbz-danger, #ef4444); }
    .rmbz-bb-kpi.blue   { border-left-color: var(--rmbz-info, #3b82f6); }
    .rmbz-bb-kpi.amber  { border-left-color: var(--rmbz-brand, #f0b90b); }
    .rmbz-bb-kpi.purple { border-left-color: var(--rmbz-accent, #a855f7); }
    .rmbz-bb-kpi .lbl { font-size: 10px; color: var(--rmbz-text-faint, #888); text-transform: uppercase; letter-spacing: 0.3px; font-weight: 600; }
    .rmbz-bb-kpi .val { font-size: 24px; font-weight: 500; color: var(--rmbz-text-strong, #222); margin: 6px 0 2px 0; line-height: 1.1; }
    .rmbz-bb-kpi.red .val { color: var(--rmbz-danger-strong, #b91c1c); }
    .rmbz-bb-kpi .sub { font-size: 11px; color: var(--rmbz-text-muted, #666); }

    .rmbz-bb-card { background: var(--rmbz-bg-card, #fff); border: 1px solid var(--rmbz-border-light, #e5e5e5); border-radius: 8px; padding: 14px 16px; margin-bottom: 12px; }
    .rmbz-bb-card .card-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px; }
    .rmbz-bb-card .card-head strong { font-size: 13px; color: var(--rmbz-text-strong, #222); }
    .rmbz-bb-card .card-head span { font-size: 11px; color: var(--rmbz-text-faint, #888); }
    .top-artists { display: flex; gap: 8px; flex-wrap: wrap; }
    .top-artists .artist-chip { display: flex; flex-direction: column; padding: 8px 12px; background: #f8f9fa; border: 1px solid var(--rmbz-border-light, #e5e5e5); border-radius: 6px; text-decoration: none; color: var(--rmbz-text-strong, #222); min-width: 140px; transition: all 0.15s; }
    .top-artists .artist-chip:hover { border-color: var(--rmbz-accent, #a855f7); background: #faf7fd; }
    .top-artists .artist-chip strong { font-size: 12px; color: var(--rmbz-text-strong, #222); }
    .top-artists .artist-chip span { font-size: 13px; color: var(--rmbz-accent, #a855f7); font-weight: 600; margin: 2px 0; }
    .top-artists .artist-chip small { font-size: 10px; color: var(--rmbz-text-faint, #888); }

    .rmbz-bb-filters { background: var(--rmbz-bg-card, #fff); border: 1px solid var(--rmbz-border-light, #e5e5e5); border-radius: 8px; padding: 12px 14px; margin-bottom: 16px; display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
    .rmbz-bb-filters .fg label { display: block; font-size: 10px; color: var(--rmbz-text-muted, #666); text-transform: uppercase; font-weight: 600; margin-bottom: 4px; }
    .rmbz-bb-filters .fg input { padding: 6px 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 13px; min-width: 180px; }
    .rmbz-bb-filters .fa { margin-left: auto; display: flex; gap: 6px; }

    .rmbz-bb-empty { text-align: center; padding: 60px 20px; background: var(--rmbz-bg-card, #fff); border-radius: 8px; border: 1px solid var(--rmbz-border-light, #e5e5e5); }
    .rmbz-bb-empty .icon { font-size: 48px; color: var(--rmbz-success, #10b981); }
    .rmbz-bb-empty h2 { color: var(--rmbz-success, #10b981); margin: 10px 0; }
    .rmbz-bb-empty p { color: var(--rmbz-text-muted, #666); }

    .rmbz-bb-list { display: flex; flex-direction: column; gap: 10px; }
    .bb-card { background: var(--rmbz-bg-card, #fff); border: 1px solid var(--rmbz-border-light, #e5e5e5); border-radius: 8px; padding: 14px 16px; display: grid; grid-template-columns: 1fr 320px; gap: 16px; align-items: start; }
    @media (max-width: 900px) { .bb-card { grid-template-columns: 1fr; } }

    .bb-title strong { font-size: 15px; color: var(--rmbz-text-strong, #222); }
    .bb-title .artist { color: var(--rmbz-text-muted, #666); font-size: 12px; margin-left: 6px; }
    .bb-meta { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 6px; font-size: 12px; color: var(--rmbz-text-secondary, #555); }
    .bb-meta .meta-item { white-space: nowrap; }
    .bb-codes { margin-top: 8px; display: flex; gap: 6px; flex-wrap: wrap; }
    .bb-codes code { background: #f5f5f5; padding: 3px 8px; border-radius: 3px; font-family: monospace; font-size: 11px; }
    .bb-codes .code-isrc { background: #e8f4fd; color: #1a5490; font-weight: 600; }
    .bb-codes .code-upc { background: #f0f0f0; color: var(--rmbz-text-secondary, #555); }
    .bb-distrib { margin-top: 8px; font-size: 11px; color: var(--rmbz-text-muted, #666); line-height: 1.6; }
    .bb-distrib span { display: block; }
    .bb-distrib strong { color: var(--rmbz-text-primary, #444); font-weight: 600; }

    .bb-card-right { border-left: 1px solid #f0f0f0; padding-left: 16px; }
    @media (max-width: 900px) { .bb-card-right { border-left: none; border-top: 1px solid #f0f0f0; padding-left: 0; padding-top: 12px; } }
    .bb-amount { text-align: right; }
    .bb-amount strong { font-size: 22px; color: var(--rmbz-success-strong, #059669); display: block; line-height: 1.1; }
    .bb-amount small { font-size: 10px; color: var(--rmbz-text-faint, #888); text-transform: uppercase; }
    .bb-stats { display: flex; justify-content: flex-end; gap: 10px; margin-top: 6px; font-size: 11px; color: var(--rmbz-text-muted, #666); flex-wrap: wrap; }
    .bb-assign { margin-top: 10px; display: flex; gap: 6px; }
    .bb-assign input { flex: 1; padding: 6px 10px; border: 1px solid #ddd; border-radius: 4px; font-size: 12px; }
    .bb-assign button { white-space: nowrap; }
    </style>
    <?php
}


/* ============================================================================
 * HANDLER — atribuição manual
 * ============================================================================ */
/* ============================================================================
 * HANDLER — atribuição manual
 * Corrige valores retidos do Black Box para a wallet de um artista 1MZ.
 * ============================================================================ */
function rmbz_handle_manual_assignment() {
    global $wpdb;

    // Segurança — permissão + nonce
    if ( ! current_user_can('manage_options') ) {
        echo '<div class="notice notice-error is-dismissible"><p><strong>Erro:</strong> Sem permissão para atribuir royalties.</p></div>';
        return;
    }
    if ( ! isset($_POST['_wpnonce']) || ! wp_verify_nonce( $_POST['_wpnonce'], 'rmbz_assign_royalty_nonce' ) ) {
        echo '<div class="notice notice-error is-dismissible"><p><strong>Erro de segurança:</strong> nonce inválido. Recarregue a página e tente novamente.</p></div>';
        return;
    }

    $isrc  = strtoupper( trim( sanitize_text_field( $_POST['isrc_to_assign'] ?? '' ) ) );
    $phone = preg_replace('/[^0-9+]/', '', (string) ($_POST['artist_phone'] ?? ''));

    if ( empty($isrc) || empty($phone) ) {
        echo '<div class="notice notice-error is-dismissible"><p><strong>Erro:</strong> ISRC e telemóvel são obrigatórios.</p></div>';
        return;
    }

    // 1. Verificar se artista existe
    $artist = $wpdb->get_row( $wpdb->prepare(
        "SELECT id, user_nome, user_telemovel FROM {$wpdb->prefix}rmbz_wallets WHERE user_telemovel = %s LIMIT 1",
        $phone
    ) );
    if ( ! $artist ) {
        echo '<div class="notice notice-error is-dismissible"><p><strong>Erro:</strong> Artista <code>' . esc_html($phone) . '</code> não encontrado na base de wallets. Verifique se o artista já criou conta.</p></div>';
        return;
    }

    // 2. Verificar se há dinheiro pendente para este ISRC
    $t_unclaimed = $wpdb->prefix . 'rmbz_distro_unclaimed';
    $lines = $wpdb->get_results( $wpdb->prepare(
        "SELECT id, amount, track_title, artist_name, platform, country, report_date, streams_total, line_count
         FROM $t_unclaimed
         WHERE (isrc = %s OR isrc_code = %s) AND status = 'pending'",
        $isrc, $isrc
    ) );
    if ( empty($lines) ) {
        echo '<div class="notice notice-warning is-dismissible"><p><strong>Aviso:</strong> Nenhum valor pendente encontrado para o ISRC <code>' . esc_html($isrc) . '</code>. Talvez já tenha sido atribuído.</p></div>';
        return;
    }

    // 3. Somar totais
    $total_moved  = 0.0;
    $total_lines  = 0;
    $total_streams = 0;
    $track_title  = '';
    $ids_to_mark  = [];
    foreach ( $lines as $line ) {
        $total_moved   += (float) $line->amount;
        $total_lines   += (int) ($line->line_count ?? 1);
        $total_streams += (int) ($line->streams_total ?? 0);
        $ids_to_mark[]  = (int) $line->id;
        if ( empty($track_title) && ! empty($line->track_title) ) $track_title = $line->track_title;
    }

    if ( $total_moved <= 0 ) {
        echo '<div class="notice notice-warning is-dismissible"><p><strong>Aviso:</strong> Total é zero ou negativo. Nada para atribuir.</p></div>';
        return;
    }

    // 4. Transacção: marcar como claimed + creditar wallet + registar no ledger
    $wpdb->query('START TRANSACTION');

    try {
        // 4a. Marcar entradas como claimed (usando IDs específicos para evitar race condition)
        $placeholders = implode(',', array_fill(0, count($ids_to_mark), '%d'));
        $marked = $wpdb->query( $wpdb->prepare(
            "UPDATE $t_unclaimed
             SET status = 'claimed', claimed_by = %s, claimed_at = %s
             WHERE id IN ($placeholders) AND status = 'pending'",
            array_merge([ $phone, current_time('mysql') ], $ids_to_mark)
        ) );

        if ( $marked === false || $marked === 0 ) {
            throw new Exception('Falhou marcação das entradas como reclamadas. Talvez já tenham sido atribuídas por outra sessão.');
        }

        // 4b. Creditar wallet do artista (tabela stats)
        $table_stats = $wpdb->prefix . 'rmbz_distro_stats';
        $now = current_time('mysql');

        // UPSERT usando ON DUPLICATE KEY (requer UNIQUE em artist_telemovel)
        $r = $wpdb->query( $wpdb->prepare(
            "INSERT INTO $table_stats (artist_telemovel, total_streams, total_earnings, last_updated)
             VALUES (%s, %d, %f, %s)
             ON DUPLICATE KEY UPDATE
                total_earnings = total_earnings + VALUES(total_earnings),
                total_streams  = total_streams  + VALUES(total_streams),
                last_updated   = VALUES(last_updated)",
            $phone, $total_streams, $total_moved, $now
        ) );

        if ( $r === false ) {
            throw new Exception('Falhou actualização da wallet do artista: ' . $wpdb->last_error);
        }

        // 4c. Ledger — registo da operação para auditoria
        $desc = "Recuperação Black Box — ISRC: $isrc";
        if ( $track_title ) $desc .= " · $track_title";
        $desc .= " · $total_lines linha(s) agregada(s)";
        if ( $total_streams > 0 ) $desc .= " · " . number_format($total_streams) . " stream(s)";

        $table_ledger = $wpdb->prefix . 'rmbz_distro_ledger';
        $ledger_ok = $wpdb->insert( $table_ledger, [
            'artist_telemovel'  => $phone,
            'amount'            => $total_moved,
            'currency'          => 'USD',
            'original_amount'   => $total_moved,
            'original_currency' => 'USD',
            'exchange_rate'     => 1.0,
            'source_name'       => 'Black Box Recovery',
            'reporting_period'  => date('Y-m'),
            'type'              => 'manual_claim',
            'description'       => $desc,
            'reference_id'      => 'CLAIM_' . $isrc . '_' . date('YmdHis'),
            'isrc'              => $isrc,                          // [DS 1.5.115]
            'created_at'        => $now,
        ] );

        if ( $ledger_ok === false ) {
            throw new Exception('Falhou registo no ledger: ' . $wpdb->last_error);
        }

        $wpdb->query('COMMIT');

    } catch ( Exception $e ) {
        $wpdb->query('ROLLBACK');
        echo '<div class="notice notice-error is-dismissible"><p><strong>Erro na atribuição:</strong> ' . esc_html($e->getMessage()) . '</p><p>Nenhuma alteração foi guardada (rollback).</p></div>';
        return;
    }

    // ─────────────────────────────────────────────────────────────────────
    // [1.5.166] PROPAGAR ISRC PARA A FAIXA DO ARTISTA (heurística)
    // ─────────────────────────────────────────────────────────────────────
    // Tenta encontrar uma faixa do artista que corresponda ao título do
    // CSV. Se houver match único + faixa sem ISRC → gravar para próximos
    // imports fazerem match automático sem ir parar à revisão.
    //
    // Critérios para gravar:
    //   1. Artista tem APENAS UMA faixa com título exacto (case-insensitive)
    //   2. Essa faixa está SEM ISRC (NULL ou vazio)
    //
    // Se houver mais que uma faixa com mesmo título, ou faixa já tem ISRC,
    // não tocar — caso ambíguo deve ser resolvido manualmente.
    // ─────────────────────────────────────────────────────────────────────
    $isrc_propagated = false;
    if ( ! empty( $isrc ) && ! empty( $track_title ) ) {
        $t_tracks   = $wpdb->prefix . 'rmbz_distro_tracks';
        $t_releases = $wpdb->prefix . 'rmbz_distro_releases';

        // Procurar faixas do artista com título igual e SEM ISRC
        $candidates = $wpdb->get_results( $wpdb->prepare(
            "SELECT t.id, t.isrc_code, t.track_title
             FROM $t_tracks t
             INNER JOIN $t_releases r ON r.id = t.release_id
             WHERE r.artist_telemovel = %s
               AND LOWER(t.track_title) = LOWER(%s)",
            $phone, $track_title
        ) );

        if ( count($candidates) === 1 ) {
            $candidate = $candidates[0];
            if ( empty($candidate->isrc_code) ) {
                $upd = $wpdb->update( $t_tracks,
                    [ 'isrc_code' => $isrc ],
                    [ 'id' => (int) $candidate->id ],
                    [ '%s' ],
                    [ '%d' ]
                );
                if ( $upd !== false && $upd > 0 ) {
                    $isrc_propagated = true;
                }
            }
        }
    }

    // 5. Sucesso
    echo '<div class="notice notice-success is-dismissible" style="border-left-color:var(--rmbz-success, #10b981);">'
       . '<p><strong>✓ Atribuição concluída!</strong> '
       . '<strong>$' . number_format($total_moved, 4) . ' USD</strong> '
       . ( $track_title ? 'da faixa <strong>' . esc_html($track_title) . '</strong> ' : '' )
       . '(ISRC <code>' . esc_html($isrc) . '</code>) '
       . 'foram transferidos para <strong>' . esc_html($artist->user_nome) . '</strong> '
       . '(<code>' . esc_html($phone) . '</code>).</p>';

    if ( $isrc_propagated ) {
        echo '<p style="font-size:12px; color:#10b981; margin-top:4px;">'
           . '✓ ISRC <code>' . esc_html($isrc) . '</code> guardado na faixa <strong>' . esc_html($track_title) . '</strong> do artista — próximos imports fazem match automático.'
           . '</p>';
    }

    echo '<p style="font-size:12px; color:var(--rmbz-text-muted, #666); margin-top:4px;">'
       . count($ids_to_mark) . ' registo(s) marcado(s) como reclamado(s). '
       . 'Operação guardada no ledger para auditoria.</p>'
       . '</div>';
}


/* ============================================================================
 * HELPERS
 * ============================================================================ */
function rmbz_bb_fmt_compact( $n ) {
    $n = (int) $n;
    if ( $n >= 1000000 ) return number_format( $n / 1000000, 1 ) . 'M';
    if ( $n >= 1000 )    return number_format( $n / 1000, 1 ) . 'K';
    return number_format( $n );
}

function rmbz_bb_truncate( $s, $max = 60 ) {
    $s = trim((string) $s);
    if ( mb_strlen($s) <= $max ) return $s;
    return mb_substr($s, 0, $max - 1) . '…';
}
