<?php
/**
 * [1.5.211] FINGERPRINTING DE DETECÇÃO DE PLÁGIO
 *
 * MÓDULO MVP — Detecção básica e gratuita de plágio em faixas submetidas.
 *
 * O QUE FAZ:
 *   1. SHA256 do MP3 → detecta upload duplicado (mesmo ficheiro 2x)
 *   2. Chromaprint fingerprint → detecta faixas acusticamente idênticas mesmo
 *      que o ficheiro tenha sido re-encoded ou tenha tags diferentes
 *   3. Comparação interna 1MZ → detecta artista a copiar de outro artista
 *      dentro do próprio catálogo da 1MZ
 *   4. AcoustID lookup (grátis) → detecta faixas conhecidas no MusicBrainz
 *      (~50M tracks; cobertura forte para música ocidental conhecida, fraca
 *      para afrobeats moderno e africana)
 *
 * O QUE NÃO FAZ:
 *   - NÃO é Content ID. Não detecta beats roubados nem samples curtos.
 *   - NÃO acede a Spotify/Apple Music/YouTube (APIs privadas).
 *   - Cobertura limitada para artistas africanos não-globais.
 *
 * REQUISITOS DO SERVIDOR:
 *   - Binary `fpcalc` instalado (Chromaprint). Em Ubuntu/Debian:
 *     `apt install libchromaprint-tools`
 *   - PHP cURL extension (verificada antes de usar)
 *   - Permissão para exec() (alguns hosts shared restringem)
 *
 * CONFIGURAÇÃO:
 *   - API key opcional do AcoustID em Settings (gratuita em
 *     https://acoustid.org/api-key — 1 minuto de registo).
 *   - Sem API key, fase AcoustID é skipped mas comparação interna funciona.
 */

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

// =============================================================================
// SCHEMA
// =============================================================================

/**
 * Cria/actualiza tabela rmbz_distro_track_fingerprints.
 * Idempotente — corre em admin_init.
 */
function rmbz_fp_install_schema() {
    global $wpdb;
    $stored = get_option('rmbz_fp_schema_version', '0');
    if ( version_compare( $stored, '1.0', '>=' ) ) return;

    $t = $wpdb->prefix . 'rmbz_distro_track_fingerprints';
    $charset = $wpdb->get_charset_collate();

    require_once ABSPATH . 'wp-admin/includes/upgrade.php';

    $sql = "CREATE TABLE $t (
        id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
        track_id BIGINT UNSIGNED NOT NULL,
        sha256 CHAR(64) DEFAULT NULL,
        chromaprint_fp LONGTEXT DEFAULT NULL,
        chromaprint_duration INT DEFAULT NULL,
        acoustid_id VARCHAR(64) DEFAULT NULL,
        acoustid_score FLOAT DEFAULT NULL,
        matched_artist VARCHAR(255) DEFAULT NULL,
        matched_title VARCHAR(255) DEFAULT NULL,
        matched_release VARCHAR(255) DEFAULT NULL,
        scan_status VARCHAR(20) DEFAULT 'pending',
        scan_error TEXT DEFAULT NULL,
        risk_level VARCHAR(20) DEFAULT NULL,
        risk_notes TEXT DEFAULT NULL,
        scanned_by BIGINT UNSIGNED DEFAULT NULL,
        created_at DATETIME NOT NULL,
        updated_at DATETIME DEFAULT NULL,
        KEY idx_track (track_id),
        KEY idx_sha (sha256),
        KEY idx_acoustid (acoustid_id),
        KEY idx_risk (risk_level)
    ) $charset;";

    dbDelta( $sql );
    update_option( 'rmbz_fp_schema_version', '1.0' );
}
add_action( 'admin_init', 'rmbz_fp_install_schema', 7 );

// =============================================================================
// HELPERS
// =============================================================================

/**
 * Verifica se o servidor tem capacidade técnica para correr o módulo.
 * Devolve array com diagnóstico — útil para mostrar ao admin se algo falha.
 */
function rmbz_fp_check_environment() {
    $checks = [
        'fpcalc'    => false,
        'fpcalc_path' => '',
        'curl'      => function_exists('curl_init'),
        'exec'      => function_exists('exec') && ! in_array('exec', explode(',', ini_get('disable_functions')), true),
        'api_key'   => '',
    ];

    if ( $checks['exec'] ) {
        // Tenta encontrar fpcalc no PATH
        $output = [];
        $rc = 0;
        @exec('which fpcalc 2>/dev/null', $output, $rc);
        if ( $rc === 0 && ! empty($output[0]) ) {
            $checks['fpcalc']      = true;
            $checks['fpcalc_path'] = trim($output[0]);
        } else {
            // Tenta paths comuns
            $candidates = [ '/usr/bin/fpcalc', '/usr/local/bin/fpcalc', '/opt/homebrew/bin/fpcalc' ];
            foreach ( $candidates as $c ) {
                if ( @is_executable($c) ) {
                    $checks['fpcalc']      = true;
                    $checks['fpcalc_path'] = $c;
                    break;
                }
            }
        }
    }

    $checks['api_key'] = trim( (string) get_option('rmbz_fp_acoustid_key', '') );

    return $checks;
}

/**
 * Calcula SHA256 do ficheiro.
 * Streaming-aware — funciona bem mesmo com MP3s grandes.
 */
function rmbz_fp_calc_sha256( $file_path ) {
    if ( ! @is_readable($file_path) ) return null;
    $hash = @hash_file('sha256', $file_path);
    return $hash ?: null;
}

/**
 * Calcula fingerprint Chromaprint chamando o binary fpcalc.
 * Devolve ['fp' => string, 'duration' => int] ou null.
 *
 * Output esperado de fpcalc:
 *   FILE=/path/to/file.mp3
 *   DURATION=180
 *   FINGERPRINT=AQADtMsUS...long_string...
 */
function rmbz_fp_calc_chromaprint( $file_path ) {
    $env = rmbz_fp_check_environment();
    if ( ! $env['fpcalc'] || ! $env['exec'] ) return null;
    if ( ! @is_readable($file_path) ) return null;

    $cmd = escapeshellcmd($env['fpcalc_path']) . ' ' . escapeshellarg($file_path) . ' 2>&1';
    $output = [];
    $rc = 0;
    @exec($cmd, $output, $rc);

    if ( $rc !== 0 || empty($output) ) return null;

    $fp = null;
    $duration = null;
    foreach ( $output as $line ) {
        if ( strpos($line, 'FINGERPRINT=') === 0 ) {
            $fp = substr($line, strlen('FINGERPRINT='));
        } elseif ( strpos($line, 'DURATION=') === 0 ) {
            $duration = (int) substr($line, strlen('DURATION='));
        }
    }

    if ( ! $fp ) return null;

    return [
        'fp'       => $fp,
        'duration' => $duration ?: 0,
    ];
}

/**
 * Lookup AcoustID (API gratuita).
 * Devolve match ou null.
 *
 * @param string $fp        Fingerprint Chromaprint
 * @param int    $duration  Duração em segundos
 * @param string $api_key   API key gratuita do AcoustID
 * @return array|null { acoustid_id, score, artist, title, release }
 */
function rmbz_fp_acoustid_lookup( $fp, $duration, $api_key ) {
    if ( ! function_exists('curl_init') ) return null;
    if ( empty($fp) || empty($duration) || empty($api_key) ) return null;

    // AcoustID API: https://acoustid.org/webservice
    $url = 'https://api.acoustid.org/v2/lookup';
    $params = [
        'client'      => $api_key,
        'meta'        => 'recordings+releasegroups+compress',
        'duration'    => (int) $duration,
        'fingerprint' => $fp,
    ];

    $ch = curl_init();
    curl_setopt_array($ch, [
        CURLOPT_URL            => $url,
        CURLOPT_POST           => true,
        CURLOPT_POSTFIELDS     => http_build_query($params),
        CURLOPT_RETURNTRANSFER => true,
        CURLOPT_TIMEOUT        => 15,
        CURLOPT_USERAGENT      => '1MZForArtists/1.5.211',
        CURLOPT_HTTPHEADER     => ['Content-Type: application/x-www-form-urlencoded'],
    ]);
    $body = curl_exec($ch);
    $err  = curl_error($ch);
    $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    curl_close($ch);

    if ( $err || $code !== 200 || empty($body) ) return null;

    $json = json_decode($body, true);
    if ( ! is_array($json) || ($json['status'] ?? '') !== 'ok' ) return null;

    $results = $json['results'] ?? [];
    if ( empty($results) ) return null;

    // Pegar o resultado de maior score
    usort($results, function($a, $b) {
        return ($b['score'] ?? 0) <=> ($a['score'] ?? 0);
    });
    $top = $results[0];

    // Extrair primeiro recording com nome
    $artist = '';
    $title  = '';
    $release = '';
    if ( ! empty($top['recordings']) ) {
        foreach ( $top['recordings'] as $rec ) {
            if ( ! empty($rec['title']) ) $title = $rec['title'];
            if ( ! empty($rec['artists']) ) {
                $artist_names = array_map(function($a) { return $a['name'] ?? ''; }, $rec['artists']);
                $artist = implode(', ', array_filter($artist_names));
            }
            if ( ! empty($rec['releasegroups']) ) {
                $release = $rec['releasegroups'][0]['title'] ?? '';
            }
            if ( $artist && $title ) break;
        }
    }

    return [
        'acoustid_id' => $top['id'] ?? '',
        'score'       => (float) ($top['score'] ?? 0),
        'artist'      => $artist,
        'title'       => $title,
        'release'     => $release,
    ];
}

/**
 * Compara fingerprint contra catálogo interno 1MZ.
 * Não usa Chromaprint similarity (complexo) — usa hash buckets / prefix match
 * que apanha matches exactos e quase-exactos (re-encodes).
 *
 * Para detecção mais avançada (cosine similarity de fingerprints), exigia uma
 * extensão C ou Python. Para MVP, prefix match dos primeiros 100 chars do fp
 * é razoável — se 100 chars batem, é praticamente impossível ser por acaso.
 */
function rmbz_fp_compare_internal( $fp, $exclude_track_id = 0 ) {
    global $wpdb;
    if ( empty($fp) || strlen($fp) < 100 ) return [];

    $t  = $wpdb->prefix . 'rmbz_distro_track_fingerprints';
    $tt = $wpdb->prefix . 'rmbz_distro_tracks';
    $tr = $wpdb->prefix . 'rmbz_distro_releases';
    $tw = $wpdb->prefix . 'rmbz_wallets';

    $prefix = substr($fp, 0, 100);

    $rows = $wpdb->get_results( $wpdb->prepare(
        "SELECT f.track_id,
                f.chromaprint_fp,
                f.chromaprint_duration,
                tt.track_title,
                tr.title AS release_title,
                tr.artist_telemovel,
                w.user_nome AS artist_name
         FROM $t f
         INNER JOIN $tt tt ON tt.id = f.track_id
         LEFT JOIN $tr tr ON tr.id = tt.release_id
         LEFT JOIN $tw w ON w.user_telemovel = tr.artist_telemovel
         WHERE f.chromaprint_fp IS NOT NULL
           AND f.track_id != %d
           AND LEFT(f.chromaprint_fp, 100) = %s
         LIMIT 20",
        (int) $exclude_track_id,
        $prefix
    ) );

    $matches = [];
    foreach ( (array) $rows as $r ) {
        // Calcular similaridade simples — % de chars iguais nos primeiros 200
        $sample_a = substr($fp, 0, 200);
        $sample_b = substr($r->chromaprint_fp, 0, 200);
        $len = min( strlen($sample_a), strlen($sample_b) );
        if ( $len < 50 ) continue;
        $matching = 0;
        for ( $i = 0; $i < $len; $i++ ) {
            if ( $sample_a[$i] === $sample_b[$i] ) $matching++;
        }
        $similarity = round(($matching / $len) * 100);

        $matches[] = [
            'track_id'     => (int) $r->track_id,
            'track_title'  => $r->track_title,
            'release_title' => $r->release_title,
            'artist_name'  => $r->artist_name ?: $r->artist_telemovel,
            'similarity'   => $similarity,
        ];
    }

    usort($matches, function($a, $b) {
        return $b['similarity'] <=> $a['similarity'];
    });

    return $matches;
}

// =============================================================================
// SCAN PRINCIPAL
// =============================================================================

/**
 * Faz o scan completo duma track.
 * Devolve array com resultado e popula a tabela.
 *
 * @param int $track_id ID da track em rmbz_distro_tracks
 * @return array { status, sha256, chromaprint, internal_matches, acoustid, risk_level, error? }
 */
function rmbz_fp_scan_track( $track_id ) {
    global $wpdb;
    $track_id = (int) $track_id;
    if ( $track_id <= 0 ) return [ 'status' => 'failed', 'error' => 'track_id inválido' ];

    $tt = $wpdb->prefix . 'rmbz_distro_tracks';
    $track = $wpdb->get_row( $wpdb->prepare(
        "SELECT id, audio_file, track_title, release_id FROM $tt WHERE id = %d",
        $track_id
    ) );

    if ( ! $track ) return [ 'status' => 'failed', 'error' => 'Track não encontrada' ];
    if ( empty($track->audio_file) ) return [ 'status' => 'failed', 'error' => 'Track sem ficheiro de áudio' ];

    // Resolver path absoluto
    $upload_dir = wp_upload_dir();
    $audio_path = $track->audio_file;

    // Se for URL, converter para path local
    if ( strpos($audio_path, 'http') === 0 ) {
        $audio_path = str_replace( $upload_dir['baseurl'], $upload_dir['basedir'], $audio_path );
    } elseif ( $audio_path[0] !== '/' ) {
        $audio_path = $upload_dir['basedir'] . '/' . ltrim($audio_path, '/');
    }

    if ( ! @is_readable($audio_path) ) {
        return [ 'status' => 'failed', 'error' => 'Ficheiro de áudio não acessível: ' . esc_html($audio_path) ];
    }

    $env = rmbz_fp_check_environment();
    $now = current_time('mysql');

    // 1. SHA256 (sempre disponível)
    $sha256 = rmbz_fp_calc_sha256( $audio_path );

    // 2. Chromaprint (se disponível)
    $chromaprint = null;
    $chromaprint_error = '';
    if ( $env['fpcalc'] ) {
        $chromaprint = rmbz_fp_calc_chromaprint( $audio_path );
        if ( ! $chromaprint ) {
            $chromaprint_error = 'fpcalc falhou — formato não suportado ou ficheiro corrompido';
        }
    } else {
        $chromaprint_error = 'fpcalc não instalado no servidor (apt install libchromaprint-tools)';
    }

    // 3. Comparação interna
    $internal_matches = [];
    if ( $chromaprint ) {
        $internal_matches = rmbz_fp_compare_internal( $chromaprint['fp'], $track_id );
    }

    // 4. AcoustID lookup (se há API key)
    $acoustid = null;
    $acoustid_error = '';
    if ( $chromaprint && ! empty($env['api_key']) ) {
        $acoustid = rmbz_fp_acoustid_lookup( $chromaprint['fp'], $chromaprint['duration'], $env['api_key'] );
        if ( ! $acoustid ) {
            $acoustid_error = 'AcoustID lookup vazio ou falhou (API down ou faixa não conhecida)';
        }
    } elseif ( ! $chromaprint ) {
        $acoustid_error = 'Sem fingerprint Chromaprint, AcoustID não pode ser tentado';
    } else {
        $acoustid_error = 'Sem API key AcoustID (configurar em Settings)';
    }

    // 5. SHA256 duplicate check — exact file
    $duplicate_track = null;
    if ( $sha256 ) {
        $t = $wpdb->prefix . 'rmbz_distro_track_fingerprints';
        $duplicate_track = $wpdb->get_var( $wpdb->prepare(
            "SELECT track_id FROM $t WHERE sha256 = %s AND track_id != %d LIMIT 1",
            $sha256, $track_id
        ) );
    }

    // 6. Calcular risk_level
    $risk_level = 'low';
    $risk_notes = [];
    if ( $duplicate_track ) {
        $risk_level = 'critical';
        $risk_notes[] = 'Ficheiro idêntico (SHA256) já existe na track #' . (int) $duplicate_track;
    }
    if ( ! empty($internal_matches) && $internal_matches[0]['similarity'] >= 95 ) {
        if ( $risk_level !== 'critical' ) $risk_level = 'high';
        $risk_notes[] = 'Match acústico interno: ' . $internal_matches[0]['similarity'] . '% com "' . $internal_matches[0]['track_title'] . '" de ' . $internal_matches[0]['artist_name'];
    } elseif ( ! empty($internal_matches) && $internal_matches[0]['similarity'] >= 80 ) {
        if ( ! in_array($risk_level, ['critical', 'high']) ) $risk_level = 'medium';
        $risk_notes[] = 'Possível match acústico interno: ' . $internal_matches[0]['similarity'] . '% com "' . $internal_matches[0]['track_title'] . '"';
    }
    if ( $acoustid && $acoustid['score'] >= 0.8 ) {
        if ( ! in_array($risk_level, ['critical', 'high']) ) $risk_level = 'high';
        $risk_notes[] = 'Match no MusicBrainz: ' . $acoustid['artist'] . ' — ' . $acoustid['title'] . ' (score ' . round($acoustid['score'] * 100) . '%)';
    } elseif ( $acoustid && $acoustid['score'] >= 0.5 ) {
        if ( ! in_array($risk_level, ['critical', 'high']) ) $risk_level = 'medium';
        $risk_notes[] = 'Possível match no MusicBrainz: ' . $acoustid['artist'] . ' — ' . $acoustid['title'] . ' (score ' . round($acoustid['score'] * 100) . '%)';
    }

    if ( empty($risk_notes) ) {
        $risk_notes[] = 'Sem matches detectados nas bases acessíveis. NOTA: cobertura limitada — Content ID/Spotify não consultados.';
    }

    // 7. Guardar na BD
    $t = $wpdb->prefix . 'rmbz_distro_track_fingerprints';

    // Apagar registo anterior desta track (sempre re-scan completo)
    $wpdb->delete( $t, [ 'track_id' => $track_id ], [ '%d' ] );

    $wpdb->insert( $t, [
        'track_id'             => $track_id,
        'sha256'               => $sha256,
        'chromaprint_fp'       => $chromaprint['fp'] ?? null,
        'chromaprint_duration' => $chromaprint['duration'] ?? null,
        'acoustid_id'          => $acoustid['acoustid_id'] ?? null,
        'acoustid_score'       => $acoustid['score'] ?? null,
        'matched_artist'       => $acoustid['artist'] ?? null,
        'matched_title'        => $acoustid['title'] ?? null,
        'matched_release'      => $acoustid['release'] ?? null,
        'scan_status'          => 'done',
        'scan_error'           => $chromaprint_error . ( $chromaprint_error && $acoustid_error ? ' | ' : '' ) . $acoustid_error,
        'risk_level'           => $risk_level,
        'risk_notes'           => implode("\n", $risk_notes),
        'scanned_by'           => get_current_user_id(),
        'created_at'           => $now,
        'updated_at'           => $now,
    ] );

    return [
        'status'           => 'done',
        'sha256'           => $sha256,
        'chromaprint'      => $chromaprint,
        'internal_matches' => $internal_matches,
        'acoustid'         => $acoustid,
        'duplicate_track'  => $duplicate_track,
        'risk_level'       => $risk_level,
        'risk_notes'       => $risk_notes,
        'errors'           => [
            'chromaprint' => $chromaprint_error,
            'acoustid'    => $acoustid_error,
        ],
    ];
}

/**
 * Lê o último scan duma track.
 */
function rmbz_fp_get_latest_scan( $track_id ) {
    global $wpdb;
    $t = $wpdb->prefix . 'rmbz_distro_track_fingerprints';
    return $wpdb->get_row( $wpdb->prepare(
        "SELECT * FROM $t WHERE track_id = %d ORDER BY created_at DESC LIMIT 1",
        (int) $track_id
    ) );
}

// =============================================================================
// AJAX HANDLER
// =============================================================================

function rmbz_fp_ajax_scan_track() {
    if ( ! current_user_can('manage_options') ) {
        wp_send_json_error('Permissão insuficiente.', 403);
    }
    check_ajax_referer('rmbz_fp_scan', 'nonce');

    $track_id = (int) ($_POST['track_id'] ?? 0);
    if ( $track_id <= 0 ) wp_send_json_error('track_id inválido.', 400);

    // Set time limit defensivo — scan pode demorar (especialmente AcoustID lookup)
    @set_time_limit(60);

    $result = rmbz_fp_scan_track( $track_id );

    if ( $result['status'] === 'failed' ) {
        wp_send_json_error( $result['error'] ?? 'Scan falhou.', 500 );
    }

    // Render HTML do resultado para inserir directamente no UI
    ob_start();
    rmbz_fp_render_scan_result( $track_id, $result );
    $html = ob_get_clean();

    wp_send_json_success([
        'risk_level' => $result['risk_level'],
        'html'       => $html,
    ]);
}
add_action( 'wp_ajax_rmbz_fp_scan_track', 'rmbz_fp_ajax_scan_track' );

// =============================================================================
// UI — RENDER DO RESULTADO
// =============================================================================

/**
 * Render HTML do resultado dum scan.
 * Usado tanto pelo AJAX como pela renderização inicial (scan já existente).
 */
function rmbz_fp_render_scan_result( $track_id, $result ) {
    if ( ! is_array($result) ) {
        // Pode ser objecto da BD — converter
        $row = (object) $result;
        $result = [
            'risk_level'       => $row->risk_level ?? 'low',
            'sha256'           => $row->sha256 ?? null,
            'chromaprint'      => $row->chromaprint_fp ? [ 'fp' => $row->chromaprint_fp, 'duration' => (int) ($row->chromaprint_duration ?? 0) ] : null,
            'acoustid'         => $row->acoustid_id ? [
                'acoustid_id' => $row->acoustid_id,
                'score'       => (float) ($row->acoustid_score ?? 0),
                'artist'      => $row->matched_artist ?? '',
                'title'       => $row->matched_title ?? '',
                'release'     => $row->matched_release ?? '',
            ] : null,
            'risk_notes'       => $row->risk_notes ? explode("\n", $row->risk_notes) : [],
            'internal_matches' => [], // não persistido — só no scan ao vivo
        ];
    }

    $risk_label_color = [
        'critical' => [ 'label' => '⛔ CRÍTICO', 'bg' => '#fef2f2', 'border' => '#dc2626', 'text' => '#991b1b' ],
        'high'     => [ 'label' => '🚨 ALTO',   'bg' => '#fff7ed', 'border' => '#ea580c', 'text' => '#9a3412' ],
        'medium'   => [ 'label' => '⚠ MÉDIO',  'bg' => '#fffbeb', 'border' => '#f59e0b', 'text' => '#854d0e' ],
        'low'      => [ 'label' => '✓ BAIXO',  'bg' => '#ecfdf5', 'border' => '#10b981', 'text' => '#065f46' ],
    ];
    $rl = $result['risk_level'] ?? 'low';
    $rc = $risk_label_color[$rl] ?? $risk_label_color['low'];
    ?>
    <div class="rmbz-fp-result" style="background:<?php echo esc_attr($rc['bg']); ?>; border:1px solid <?php echo esc_attr($rc['border']); ?>; border-left:4px solid <?php echo esc_attr($rc['border']); ?>; border-radius:6px; padding:14px 16px; margin:10px 0;">
        <div style="display:flex; justify-content:space-between; align-items:center; gap:12px; flex-wrap:wrap;">
            <div>
                <strong style="color:<?php echo esc_attr($rc['text']); ?>; font-size:14px;">
                    Risco: <?php echo esc_html($rc['label']); ?>
                </strong>
            </div>
            <small style="color:#666;">
                Limitações: <em>cobertura básica (MusicBrainz + interno). Não substitui Content ID.</em>
            </small>
        </div>

        <?php if ( ! empty($result['risk_notes']) ): ?>
            <ul style="margin:10px 0 6px 18px; padding:0; color:<?php echo esc_attr($rc['text']); ?>; font-size:13px; line-height:1.5;">
                <?php foreach ( (array) $result['risk_notes'] as $note ): ?>
                    <li><?php echo esc_html($note); ?></li>
                <?php endforeach; ?>
            </ul>
        <?php endif; ?>

        <details style="margin-top:8px;">
            <summary style="cursor:pointer; color:#666; font-size:12px;">▶ Detalhes técnicos</summary>
            <table style="width:100%; margin-top:8px; font-size:12px; background:#fff; border:1px solid #e5e7eb; border-radius:4px; padding:0; border-collapse:collapse;">
                <?php if ( ! empty($result['sha256']) ): ?>
                    <tr><td style="padding:6px 10px; border-bottom:1px solid #f0f0f0; color:#888; width:140px;">SHA256</td><td style="padding:6px 10px; border-bottom:1px solid #f0f0f0; font-family:monospace; word-break:break-all;"><?php echo esc_html($result['sha256']); ?></td></tr>
                <?php endif; ?>
                <?php if ( ! empty($result['chromaprint']['duration']) ): ?>
                    <tr><td style="padding:6px 10px; border-bottom:1px solid #f0f0f0; color:#888;">Duração detectada</td><td style="padding:6px 10px; border-bottom:1px solid #f0f0f0;"><?php echo (int) $result['chromaprint']['duration']; ?>s</td></tr>
                <?php endif; ?>
                <?php if ( ! empty($result['acoustid']) ): ?>
                    <tr><td style="padding:6px 10px; border-bottom:1px solid #f0f0f0; color:#888;">AcoustID</td><td style="padding:6px 10px; border-bottom:1px solid #f0f0f0;"><a href="https://acoustid.org/track/<?php echo esc_attr($result['acoustid']['acoustid_id']); ?>" target="_blank"><?php echo esc_html($result['acoustid']['acoustid_id']); ?></a> (score <?php echo round($result['acoustid']['score'] * 100); ?>%)</td></tr>
                    <?php if ( $result['acoustid']['artist'] ): ?>
                        <tr><td style="padding:6px 10px; border-bottom:1px solid #f0f0f0; color:#888;">Match externo</td><td style="padding:6px 10px; border-bottom:1px solid #f0f0f0;"><strong><?php echo esc_html($result['acoustid']['artist']); ?></strong> — <?php echo esc_html($result['acoustid']['title']); ?><?php if ($result['acoustid']['release']): ?> <em>(<?php echo esc_html($result['acoustid']['release']); ?>)</em><?php endif; ?></td></tr>
                    <?php endif; ?>
                <?php endif; ?>
                <?php if ( ! empty($result['internal_matches']) ): ?>
                    <tr><td style="padding:6px 10px; border-bottom:1px solid #f0f0f0; color:#888; vertical-align:top;">Matches internos</td><td style="padding:6px 10px; border-bottom:1px solid #f0f0f0;">
                        <?php foreach ( $result['internal_matches'] as $im ): ?>
                            <div><strong><?php echo (int) $im['similarity']; ?>%</strong> — <?php echo esc_html($im['track_title']); ?> <small style="color:#888;">(<?php echo esc_html($im['artist_name']); ?>)</small></div>
                        <?php endforeach; ?>
                    </td></tr>
                <?php endif; ?>
                <?php if ( ! empty($result['errors']['chromaprint']) || ! empty($result['errors']['acoustid']) ): ?>
                    <tr><td style="padding:6px 10px; color:#888;">Avisos</td><td style="padding:6px 10px; color:#856404; font-size:11px;">
                        <?php if ( ! empty($result['errors']['chromaprint']) ): ?>
                            ⚠ Chromaprint: <?php echo esc_html($result['errors']['chromaprint']); ?><br>
                        <?php endif; ?>
                        <?php if ( ! empty($result['errors']['acoustid']) ): ?>
                            ⚠ AcoustID: <?php echo esc_html($result['errors']['acoustid']); ?>
                        <?php endif; ?>
                    </td></tr>
                <?php endif; ?>
            </table>
        </details>
    </div>
    <?php
}

/**
 * Render do botão + área de resultado (chamado dentro de admin-distribution-releases.php).
 * Recebe um track_id e renderiza tudo necessário.
 */
function rmbz_fp_render_track_panel( $track_id ) {
    $track_id = (int) $track_id;
    if ( $track_id <= 0 ) return;

    $env = rmbz_fp_check_environment();
    $existing = rmbz_fp_get_latest_scan( $track_id );

    ?>
    <div class="rmbz-fp-panel" data-track-id="<?php echo esc_attr($track_id); ?>" style="margin-top:12px; padding:12px; background:#f9fafb; border:1px solid #e5e7eb; border-radius:6px;">
        <div style="display:flex; justify-content:space-between; align-items:center; gap:12px; margin-bottom:8px; flex-wrap:wrap;">
            <strong style="font-size:13px; color:#374151;">🔍 Detecção de plágio</strong>
            <button type="button" class="button rmbz-fp-scan-btn" style="font-size:12px;">
                <?php echo $existing ? '🔄 Re-scan' : '▶ Scan agora'; ?>
            </button>
        </div>

        <?php if ( ! $env['fpcalc'] ): ?>
            <div style="background:#fffbeb; border:1px solid #f59e0b; border-radius:4px; padding:8px 12px; font-size:12px; color:#854d0e;">
                ⚠ <strong>fpcalc</strong> não está instalado no servidor. Apenas SHA256 (duplicate exacto) funcionará.
                <br><small>Para detecção acústica, instalar: <code>apt install libchromaprint-tools</code></small>
            </div>
        <?php endif; ?>
        <?php if ( empty($env['api_key']) ): ?>
            <div style="background:#fef3f2; border:1px solid #fbbf24; border-radius:4px; padding:8px 12px; font-size:12px; color:#854d0e; margin-top:6px;">
                💡 Sem API key AcoustID — só comparação interna 1MZ. Adicionar key gratuita em <a href="<?php echo esc_url( admin_url('admin.php?page=rmbz-admin-distribution&tab=settings') ); ?>">Settings</a> (1 minuto, 100% grátis em <a href="https://acoustid.org/api-key" target="_blank">acoustid.org</a>).
            </div>
        <?php endif; ?>

        <div class="rmbz-fp-result-container" style="margin-top:8px;">
            <?php if ( $existing ): ?>
                <?php rmbz_fp_render_scan_result( $track_id, $existing ); ?>
                <small style="color:#888; font-size:11px;">Último scan: <?php echo esc_html( mysql2date('d/m/Y H:i', $existing->created_at) ); ?></small>
            <?php else: ?>
                <p style="color:#666; font-size:12px; margin:0; font-style:italic;">Sem scan feito ainda. Clica "Scan agora" para verificar plágio.</p>
            <?php endif; ?>
        </div>

        <div class="rmbz-fp-loading" style="display:none; margin-top:8px; padding:8px; text-align:center; color:#666; font-size:12px;">
            <span class="spinner is-active" style="float:none; margin:0 6px 0 0;"></span>
            A analisar... (10-20 segundos)
        </div>
    </div>
    <?php
}

/**
 * JS + CSS do panel — incluído uma vez por página.
 */
function rmbz_fp_render_assets() {
    static $rendered = false;
    if ( $rendered ) return;
    $rendered = true;
    ?>
    <script>
    (function() {
        document.addEventListener('click', function(e) {
            if ( ! e.target.matches('.rmbz-fp-scan-btn') ) return;
            e.preventDefault();

            var btn   = e.target;
            var panel = btn.closest('.rmbz-fp-panel');
            if ( ! panel ) return;

            var trackId = panel.dataset.trackId;
            var loading = panel.querySelector('.rmbz-fp-loading');
            var result  = panel.querySelector('.rmbz-fp-result-container');

            if ( ! confirm('Analisar plágio desta faixa? (10-20 segundos)') ) return;

            btn.disabled = true;
            btn.style.opacity = '0.6';
            loading.style.display = 'block';

            var fd = new FormData();
            fd.append('action', 'rmbz_fp_scan_track');
            fd.append('nonce', '<?php echo esc_js( wp_create_nonce('rmbz_fp_scan') ); ?>');
            fd.append('track_id', trackId);

            fetch('<?php echo esc_url( admin_url('admin-ajax.php') ); ?>', { method: 'POST', body: fd })
                .then(function(r) { return r.json(); })
                .then(function(res) {
                    btn.disabled = false;
                    btn.style.opacity = '1';
                    loading.style.display = 'none';
                    if ( ! res.success ) {
                        alert('Erro: ' + (res.data || 'desconhecido'));
                        return;
                    }
                    result.innerHTML = res.data.html;
                    btn.textContent = '🔄 Re-scan';
                })
                .catch(function(err) {
                    btn.disabled = false;
                    btn.style.opacity = '1';
                    loading.style.display = 'none';
                    alert('Erro de ligação: ' + err.message);
                });
        });
    })();
    </script>
    <?php
}
add_action( 'admin_footer', 'rmbz_fp_render_assets' );

// =============================================================================
// SETTINGS — API KEY
// =============================================================================

function rmbz_fp_register_setting() {
    register_setting( 'rmbz_distribution_settings', 'rmbz_fp_acoustid_key', [
        'type'              => 'string',
        'sanitize_callback' => 'sanitize_text_field',
        'default'           => '',
    ] );
}
add_action( 'admin_init', 'rmbz_fp_register_setting' );
