<?php
// includes/distribution/distribution-platforms.php
//
// Módulo de plataformas e territórios por lançamento.
// Carregar no 1mz-for-artists.php depois de distribution-schema-patch.php.
//
// O que faz:
//   - Define as listas de DSPs suportados, territórios ISO e serviços exclusivos.
//   - Garante a tabela rmbz_distro_release_platforms (uma linha por release).
//   - Regista AJAX para salvar as escolhas do passo 2 do wizard.
//   - Fornece helpers para o wizard, para a view admin e para o importador
//     saber que plataformas estão aprovadas.
//
// Nota sobre aprovação de serviços exclusivos:
//   O artista pode PEDIR (opt_in) YouTube Content ID, Facebook Monetization e
//   TikTok Monetization, mas o valor final (approved/rejected) só é definido
//   pelo admin. Enquanto pendente, o release pode ir para as lojas normais,
//   mas NÃO é enviado para estes três serviços até o admin aprovar.

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

/* ============================================================================
 * CATÁLOGO DE DSPs
 * ============================================================================
 *
 * Ordem: Tier 1 (essenciais) → Tier 2 (regionais relevantes) → Tier 3 (nicho).
 * slug = identificador curto (usamos em BD); nome = label no UI; tier = 1|2|3.
 * A Tier 1 está sempre pré-selecionada. O artista pode desmarcar se quiser.
 * ============================================================================ */
/**
 * Catálogo BUILT-IN de DSPs — lista interna fixa que vem com o plugin.
 *
 * IMPORTANTE [1.5.144]: esta função é APENAS o seed inicial. Quando o módulo
 * de gestão de catálogo (rmbz_dsp_catalog table) está activo, o catálogo
 * efectivo é lido da BD (built-in importadas + custom adicionadas pelo admin).
 * Para o catálogo "vivo", usa rmbz_distro_dsp_catalog() abaixo.
 */
function rmbz_distro_dsp_catalog_builtin() {
    return [
        // Tier 1 — essenciais
        'spotify'       => [ 'name' => 'Spotify',              'tier' => 1 ],
        'apple_music'   => [ 'name' => 'Apple Music',          'tier' => 1 ],
        'youtube_music' => [ 'name' => 'YouTube Music',        'tier' => 1 ],
        'amazon_music'  => [ 'name' => 'Amazon Music',         'tier' => 1 ],
        'deezer'        => [ 'name' => 'Deezer',               'tier' => 1 ],
        'tidal'         => [ 'name' => 'Tidal',                'tier' => 1 ],
        'tiktok'        => [ 'name' => 'TikTok (discovery)',   'tier' => 1 ],
        'instagram'     => [ 'name' => 'Instagram / Facebook', 'tier' => 1 ],

        // Tier 2 — relevante para mercado africano e lusófono
        'boomplay'      => [ 'name' => 'Boomplay (África)',    'tier' => 2 ],
        'audiomack'     => [ 'name' => 'Audiomack',            'tier' => 2 ],
        'anghami'       => [ 'name' => 'Anghami (MENA)',       'tier' => 2 ],
        'jiosaavn'      => [ 'name' => 'JioSaavn (Índia)',     'tier' => 2 ],
        'pandora'       => [ 'name' => 'Pandora (US)',         'tier' => 2 ],
        'iheartradio'   => [ 'name' => 'iHeartRadio (US)',     'tier' => 2 ],

        // Tier 3 — Ásia, audiófilo, nicho
        'kkbox'         => [ 'name' => 'KKBOX',                'tier' => 3 ],
        'line_music'    => [ 'name' => 'LINE Music',           'tier' => 3 ],
        'netease'       => [ 'name' => 'NetEase Cloud',        'tier' => 3 ],
        'tencent'       => [ 'name' => 'Tencent Music',        'tier' => 3 ],
        'joox'          => [ 'name' => 'JOOX',                 'tier' => 3 ],
        'qobuz'         => [ 'name' => 'Qobuz (hi-res)',       'tier' => 3 ],
        '7digital'      => [ 'name' => '7digital',             'tier' => 3 ],
        'gracenote'     => [ 'name' => 'Gracenote',            'tier' => 3 ],
        'resso'         => [ 'name' => 'Resso',                'tier' => 3 ],
        'imusica'       => [ 'name' => 'iMusica',              'tier' => 3 ],
    ];
}

/**
 * Catálogo VIVO de DSPs — utilizado por todo o sistema.
 *
 * [1.5.144] Refactorizado: agora delega para rmbz_store_get_catalog() que lê
 * da tabela rmbz_dsp_catalog (com fallback para built-in se a tabela não
 * existir, p.ex. antes do install correr).
 *
 * Comportamento por defeito: SÓ lojas activas (is_active=1).
 * Para obter incluindo as desactivadas (UI admin), passa $only_active=false.
 */
function rmbz_distro_dsp_catalog( $only_active = true ) {
    if ( function_exists('rmbz_store_get_catalog') ) {
        $cat = rmbz_store_get_catalog( $only_active );
        if ( ! empty($cat) ) return $cat;
    }
    return rmbz_distro_dsp_catalog_builtin();
}

/**
 * Devolve apenas os slugs da Tier 1 (pré-seleção por defeito).
 */
function rmbz_distro_dsp_default_selection() {
    $out = [];
    foreach ( rmbz_distro_dsp_catalog() as $slug => $meta ) {
        if ( $meta['tier'] === 1 ) $out[] = $slug;
    }
    return $out;
}

/**
 * Serviços exclusivos — precisam de aprovação manual do admin.
 * Cada um tem o texto de aviso detalhado (copiado/adaptado do layout Amadea).
 */
function rmbz_distro_exclusive_services() {
    return [
        'youtube_content_id' => [
            'name'  => 'YouTube Content ID + YouTube Music',
            'short' => 'Reclame e monetize uso da sua música em vídeos de terceiros no YouTube.',
            'notice' => "O YouTube Content ID é um SERVIÇO EXCLUSIVO. Ao aceitar, concede à 1MZ direitos exclusivos para monetizar todas as suas gravações no YouTube.\n\n⚠️ NÃO ENTREGUE as mesmas gravações a outra empresa em paralelo — só uma distribuidora pode monetizar uma gravação em Content ID. Entregar em duplicado vai causar conflitos e bloqueio.\n\nNÃO pode submeter para monetização:\n• Clipes ou discursos de domínio público\n• Samples de bibliotecas de áudio, efeitos sonoros, loops (ex: GarageBand)\n• Conteúdo de terceiros sem licença exclusiva\n• Versões karaoke ou covers\n• Faixas de compilações ou \"various artists\"\n\nAo aceitar, declara que possui todos os direitos sobre as gravações e que não as entregou a outra distribuidora para monetização no YouTube.",
        ],
        'facebook_monetization' => [
            'name'  => 'Facebook / Instagram monetization',
            'short' => 'Monetize o uso da sua música em vídeos e Stories.',
            'notice' => "Facebook/Instagram Monetization é um SERVIÇO EXCLUSIVO. Só uma distribuidora pode monetizar uma gravação neste sistema.\n\nSemelhante ao Content ID mas sem aviso visual (sem claim nem ad). Quando entregarmos a sua música ao Facebook, os utilizadores poderão adicioná-la aos seus vídeos e stories.\n\n⚠️ Este serviço ainda está em rollout — a sua música pode ficar BLOQUEADA em alguns países até o Facebook lançar totalmente. Quando for lançado em pleno, a política é monetizar, não bloquear.\n\nNÃO pode submeter:\n• Conteúdo de domínio público\n• Samples de bibliotecas, efeitos, loops de produção\n• Música ambiente/meditação/yoga/sleep\n• Production Library Music (stock, licenciada não-exclusivamente)\n• Conteúdo de terceiros sem licença exclusiva\n• Versões karaoke ou covers\n• Compilações/various artists\n• Spoken Word / fala sem melodia\n• Obras já entregues a outra distribuidora para monetização no Facebook\n\nViolações podem levar a bloqueio permanente da sua conta.",
        ],
        'tiktok_monetization' => [
            'name'  => 'TikTok monetization',
            'short' => 'Monetize quando terceiros criam vídeos usando a sua música.',
            'notice' => "TikTok Monetization é um SERVIÇO EXCLUSIVO. Só uma distribuidora pode monetizar uma gravação. NÃO ENTREGUE em paralelo a outra empresa.\n\nSemelhante ao Content ID — quando entregarmos ao TikTok, os utilizadores poderão usar a sua música em novos vídeos. O modelo de monetização é baseado em vídeos CRIADOS, não em plays.\n\nNÃO pode submeter:\n• Conteúdo de domínio público\n• Sons genéricos ou muito comuns (aplausos, ruído branco, drum loops simples, campainhas, risos, fala, diálogos de TV/filme)\n• Beats ou sons não-exclusivos\n• Múltiplas gravações numa faixa (DJ mixes, álbuns completos, compilações)\n• Conteúdo licenciado a si em base não-exclusiva\n• Soundalikes ou karaoke\n• Música clássica de domínio público\n• Versões live muito próximas da gravação original\n• Remixes onde não possui a versão original\n• Re-recordings ou remasters sem controlo total\n• Áudio onde não controla 100% dos direitos\n\nViolações podem levar a bloqueio permanente da sua conta no serviço.",
        ],
    ];
}

/**
 * Lista completa de territórios ISO-3166 agrupados por região.
 * Devolve array de [ 'region_key' => [ 'label' => ..., 'countries' => [code => name] ] ].
 */
function rmbz_distro_territory_regions() {
    return [
        'lusophone' => [
            'label' => '🌐 Lusófonos (CPLP)',
            'countries' => [
                'MZ' => 'Moçambique',
                'PT' => 'Portugal',
                'BR' => 'Brasil',
                'AO' => 'Angola',
                'CV' => 'Cabo Verde',
                'GW' => 'Guiné-Bissau',
                'ST' => 'São Tomé e Príncipe',
                'TL' => 'Timor-Leste',
                'GQ' => 'Guiné Equatorial',
            ],
        ],
        'africa' => [
            'label' => '🌍 África',
            'countries' => [
                'DZ' => 'Argélia', 'BJ' => 'Benim', 'BW' => 'Botsuana',
                'BF' => 'Burquina Faso', 'BI' => 'Burundi', 'CM' => 'Camarões',
                'TD' => 'Chade', 'KM' => 'Comores', 'CG' => 'Congo',
                'CD' => 'Congo (RDC)', 'CI' => 'Costa do Marfim', 'DJ' => 'Djibouti',
                'EG' => 'Egito', 'ER' => 'Eritreia', 'SZ' => 'Essuatíni',
                'ET' => 'Etiópia', 'GA' => 'Gabão', 'GM' => 'Gâmbia',
                'GH' => 'Gana', 'GN' => 'Guiné', 'KE' => 'Quénia',
                'LS' => 'Lesoto', 'LR' => 'Libéria', 'LY' => 'Líbia',
                'MG' => 'Madagáscar', 'MW' => 'Maláui', 'ML' => 'Mali',
                'MR' => 'Mauritânia', 'MU' => 'Maurícia', 'MA' => 'Marrocos',
                'NA' => 'Namíbia', 'NE' => 'Níger', 'NG' => 'Nigéria',
                'RW' => 'Ruanda', 'SN' => 'Senegal', 'SC' => 'Seicheles',
                'SL' => 'Serra Leoa', 'SO' => 'Somália', 'ZA' => 'África do Sul',
                'SS' => 'Sudão do Sul', 'SD' => 'Sudão', 'TZ' => 'Tanzânia',
                'TG' => 'Togo', 'TN' => 'Tunísia', 'UG' => 'Uganda',
                'ZM' => 'Zâmbia', 'ZW' => 'Zimbabué', 'CF' => 'República Centro-Africana',
            ],
        ],
        'europe' => [
            'label' => '🇪🇺 Europa',
            'countries' => [
                'AL' => 'Albânia', 'AD' => 'Andorra', 'AT' => 'Áustria',
                'BY' => 'Bielorrússia', 'BE' => 'Bélgica', 'BA' => 'Bósnia e Herzegovina',
                'BG' => 'Bulgária', 'HR' => 'Croácia', 'CY' => 'Chipre',
                'CZ' => 'Chéquia', 'DK' => 'Dinamarca', 'EE' => 'Estónia',
                'FI' => 'Finlândia', 'FR' => 'França', 'DE' => 'Alemanha',
                'GR' => 'Grécia', 'HU' => 'Hungria', 'IS' => 'Islândia',
                'IE' => 'Irlanda', 'IT' => 'Itália', 'XK' => 'Kosovo',
                'LV' => 'Letónia', 'LI' => 'Liechtenstein', 'LT' => 'Lituânia',
                'LU' => 'Luxemburgo', 'MT' => 'Malta', 'MD' => 'Moldávia',
                'MC' => 'Mónaco', 'ME' => 'Montenegro', 'NL' => 'Holanda',
                'MK' => 'Macedónia do Norte', 'NO' => 'Noruega', 'PL' => 'Polónia',
                'RO' => 'Roménia', 'RU' => 'Rússia', 'SM' => 'San Marino',
                'RS' => 'Sérvia', 'SK' => 'Eslováquia', 'SI' => 'Eslovénia',
                'ES' => 'Espanha', 'SE' => 'Suécia', 'CH' => 'Suíça',
                'TR' => 'Turquia', 'UA' => 'Ucrânia', 'GB' => 'Reino Unido',
                'VA' => 'Vaticano',
            ],
        ],
        'americas' => [
            'label' => '🌎 Américas',
            'countries' => [
                'AG' => 'Antígua e Barbuda', 'AR' => 'Argentina', 'BS' => 'Bahamas',
                'BB' => 'Barbados', 'BZ' => 'Belize', 'BO' => 'Bolívia',
                'CA' => 'Canadá', 'CL' => 'Chile', 'CO' => 'Colômbia',
                'CR' => 'Costa Rica', 'CU' => 'Cuba', 'DM' => 'Dominica',
                'DO' => 'República Dominicana', 'EC' => 'Equador', 'SV' => 'El Salvador',
                'GD' => 'Granada', 'GT' => 'Guatemala', 'GY' => 'Guiana',
                'HT' => 'Haiti', 'HN' => 'Honduras', 'JM' => 'Jamaica',
                'MX' => 'México', 'NI' => 'Nicarágua', 'PA' => 'Panamá',
                'PY' => 'Paraguai', 'PE' => 'Peru', 'KN' => 'São Cristóvão e Neves',
                'LC' => 'Santa Lúcia', 'VC' => 'São Vicente e Granadinas',
                'SR' => 'Suriname', 'TT' => 'Trindade e Tobago',
                'US' => 'Estados Unidos', 'UY' => 'Uruguai', 'VE' => 'Venezuela',
            ],
        ],
        'asia' => [
            'label' => '🌏 Ásia',
            'countries' => [
                'AF' => 'Afeganistão', 'AM' => 'Arménia', 'AZ' => 'Azerbaijão',
                'BH' => 'Barém', 'BD' => 'Bangladesh', 'BT' => 'Butão',
                'BN' => 'Brunei', 'KH' => 'Camboja', 'CN' => 'China',
                'GE' => 'Geórgia', 'IN' => 'Índia', 'ID' => 'Indonésia',
                'IR' => 'Irão', 'IQ' => 'Iraque', 'IL' => 'Israel',
                'JP' => 'Japão', 'JO' => 'Jordânia', 'KZ' => 'Cazaquistão',
                'KW' => 'Kuwait', 'KG' => 'Quirguistão', 'LA' => 'Laos',
                'LB' => 'Líbano', 'MY' => 'Malásia', 'MV' => 'Maldivas',
                'MN' => 'Mongólia', 'MM' => 'Mianmar', 'NP' => 'Nepal',
                'KP' => 'Coreia do Norte', 'OM' => 'Omã', 'PK' => 'Paquistão',
                'PS' => 'Palestina', 'PH' => 'Filipinas', 'QA' => 'Catar',
                'SA' => 'Arábia Saudita', 'SG' => 'Singapura', 'KR' => 'Coreia do Sul',
                'LK' => 'Sri Lanka', 'SY' => 'Síria', 'TW' => 'Taiwan',
                'TJ' => 'Tajiquistão', 'TH' => 'Tailândia', 'TR' => 'Turquia',
                'TM' => 'Turquemenistão', 'AE' => 'Emirados Árabes Unidos',
                'UZ' => 'Uzbequistão', 'VN' => 'Vietname', 'YE' => 'Iémen',
                'HK' => 'Hong Kong', 'MO' => 'Macau',
            ],
        ],
        'oceania' => [
            'label' => '🏝️ Oceânia',
            'countries' => [
                'AU' => 'Austrália', 'FJ' => 'Fiji', 'KI' => 'Kiribati',
                'MH' => 'Ilhas Marshall', 'FM' => 'Micronésia', 'NR' => 'Nauru',
                'NZ' => 'Nova Zelândia', 'PW' => 'Palau', 'PG' => 'Papua-Nova Guiné',
                'WS' => 'Samoa', 'SB' => 'Ilhas Salomão', 'TO' => 'Tonga',
                'TV' => 'Tuvalu', 'VU' => 'Vanuatu',
            ],
        ],
    ];
}

/**
 * Lista plana de todos os territórios (para validação).
 */
function rmbz_distro_territory_list() {
    $out = [];
    foreach ( rmbz_distro_territory_regions() as $region ) {
        foreach ( $region['countries'] as $code => $name ) {
            $out[$code] = $name;
        }
    }
    return $out;
}


/* ============================================================================
 * SCHEMA
 * ============================================================================ */

function rmbz_distro_platforms_maybe_install() {
    $stored = get_option('rmbz_platforms_schema_v', '0');
    // [FEAT 1.5.14] Bump 1.1 -> 1.2: novas colunas de conflito
    // (yt/fb/tt _conflict_url e _conflict_source).
    if ( version_compare( $stored, '1.2', '<' ) ) {
        rmbz_distro_platforms_install_table();
        update_option( 'rmbz_platforms_schema_v', '1.2' );
    }
}
add_action( 'admin_init', 'rmbz_distro_platforms_maybe_install', 6 );
add_action( 'init',       'rmbz_distro_platforms_maybe_install', 6 );

function rmbz_distro_platforms_install_table() {
    global $wpdb;
    $charset_collate = $wpdb->get_charset_collate();

    $sql = "CREATE TABLE {$wpdb->prefix}rmbz_distro_release_platforms (
        id bigint(20) NOT NULL AUTO_INCREMENT,
        release_id bigint(20) NOT NULL,
        territory_mode varchar(20) DEFAULT 'worldwide' NOT NULL,
        territory_list longtext,
        dsp_list longtext,
        user_confirmed tinyint(1) DEFAULT 0 NOT NULL,
        yt_content_id_status varchar(20) DEFAULT 'not_requested' NOT NULL,
        fb_monet_status varchar(20) DEFAULT 'not_requested' NOT NULL,
        tt_monet_status varchar(20) DEFAULT 'not_requested' NOT NULL,
        yt_content_id_decision_note text,
        fb_monet_decision_note text,
        tt_monet_decision_note text,
        yt_content_id_conflict_url varchar(500) DEFAULT NULL,
        fb_monet_conflict_url varchar(500) DEFAULT NULL,
        tt_monet_conflict_url varchar(500) DEFAULT NULL,
        yt_content_id_conflict_source varchar(255) DEFAULT NULL,
        fb_monet_conflict_source varchar(255) DEFAULT NULL,
        tt_monet_conflict_source varchar(255) DEFAULT NULL,
        decided_by varchar(60) DEFAULT NULL,
        decided_at datetime DEFAULT NULL,
        created_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
        updated_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
        PRIMARY KEY (id),
        UNIQUE KEY uniq_release (release_id),
        KEY idx_ytcid (yt_content_id_status),
        KEY idx_fb (fb_monet_status),
        KEY idx_tt (tt_monet_status)
    ) $charset_collate;";

    require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
    dbDelta( $sql );

    $table = $wpdb->prefix . 'rmbz_distro_release_platforms';
    $cols  = $wpdb->get_col( "SHOW COLUMNS FROM $table" );

    // Garantir que a coluna existe em instalações antigas
    if ( ! in_array('user_confirmed', (array) $cols, true) ) {
        $wpdb->query( "ALTER TABLE $table ADD COLUMN user_confirmed tinyint(1) DEFAULT 0 NOT NULL AFTER dsp_list" );
    }

    // [FEAT 1.5.14] Colunas para suporte a estado 'conflict' nos serviços exclusivos.
    // Guardam URL da evidência (ex: vídeo YouTube onde a música já aparece distribuída
    // por outrém) e nome do distribuidor/dono suspeito. A nota existente do serviço
    // (yt_content_id_decision_note, etc.) é reutilizada como descrição do conflito.
    $conflict_columns = [
        'yt_content_id_conflict_url'    => "varchar(500) DEFAULT NULL",
        'fb_monet_conflict_url'         => "varchar(500) DEFAULT NULL",
        'tt_monet_conflict_url'         => "varchar(500) DEFAULT NULL",
        'yt_content_id_conflict_source' => "varchar(255) DEFAULT NULL",
        'fb_monet_conflict_source'      => "varchar(255) DEFAULT NULL",
        'tt_monet_conflict_source'      => "varchar(255) DEFAULT NULL",
    ];
    foreach ( $conflict_columns as $col_name => $col_def ) {
        if ( ! in_array($col_name, (array) $cols, true) ) {
            $wpdb->query( "ALTER TABLE $table ADD COLUMN $col_name $col_def" );
        }
    }
}


/* ============================================================================
 * HELPERS (para o wizard, admin-views, importador)
 * ============================================================================ */

/**
 * Devolve (e cria se preciso) a linha de plataformas de um release.
 * Cria com os valores default (Tier 1 seleccionada, worldwide, exclusivos não pedidos).
 */
function rmbz_distro_get_platforms( $release_id ) {
    global $wpdb;
    $table = $wpdb->prefix . 'rmbz_distro_release_platforms';

    // Defensive: se a tabela não existir, instalar antes de fazer SELECT.
    // Evita o fatal "Table doesn't exist" que acontece quando:
    //   - BD foi apagada e plugin reactivado sem visitar wp-admin
    //   - Ficheiro chamado em frontend antes de qualquer hook admin_init
    //   - Nova instalação incompleta
    if ( $wpdb->get_var("SHOW TABLES LIKE '$table'") !== $table ) {
        if ( function_exists('rmbz_distro_platforms_maybe_install') ) {
            rmbz_distro_platforms_maybe_install();
        }
        // Se mesmo assim não existe, devolver objecto vazio mas válido
        if ( $wpdb->get_var("SHOW TABLES LIKE '$table'") !== $table ) {
            $fallback = new stdClass();
            $fallback->release_id      = $release_id;
            $fallback->territory_mode  = 'worldwide';
            $fallback->territory_list  = '[]';
            $fallback->dsp_list        = '[]';
            $fallback->_dsp_list       = [];
            $fallback->_territory_list = [];
            return $fallback;
        }
    }

    $row = $wpdb->get_row( $wpdb->prepare(
        "SELECT * FROM $table WHERE release_id = %d", $release_id
    ) );

    if ( ! $row ) {
        $wpdb->insert( $table, [
            'release_id'     => $release_id,
            'territory_mode' => 'worldwide',
            'territory_list' => wp_json_encode([]),
            'dsp_list'       => wp_json_encode( rmbz_distro_dsp_default_selection() ),
        ] );
        $row = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM $table WHERE release_id = %d", $release_id
        ) );
    }

    // Decode defensivo
    $row->_dsp_list       = json_decode( $row->dsp_list ?: '[]', true ) ?: [];
    $row->_territory_list = json_decode( $row->territory_list ?: '[]', true ) ?: [];
    return $row;
}

/**
 * Verdadeiro se o release pode ser entregue a um serviço exclusivo específico.
 * Usado pelo admin na decisão de "enviar para lojas".
 *
 * @param string $service 'yt_content_id' | 'fb_monet' | 'tt_monet'
 */
function rmbz_distro_exclusive_is_approved( $release_id, $service ) {
    $col = $service . '_status';
    $allowed = ['yt_content_id_status', 'fb_monet_status', 'tt_monet_status'];
    if ( ! in_array( $col, $allowed, true ) ) return false;

    $platforms = rmbz_distro_get_platforms( $release_id );
    return $platforms->{$col} === 'approved';
}


/* ============================================================================
 * AJAX: salvar escolhas do passo 2 do wizard
 * ============================================================================ */

function rmbz_ajax_save_release_platforms() {
    if ( ! check_ajax_referer('rmbz_distro_nonce', 'nonce', false) ) {
        wp_send_json_error('Segurança.', 403);
    }
    if ( ! function_exists('rmbz_is_user_logged_in') || ! rmbz_is_user_logged_in() ) {
        wp_send_json_error('Sessão expirada.', 401);
    }

    $telemovel  = rmbz_get_current_user_telemovel();
    $release_id = isset($_POST['release_id']) ? absint($_POST['release_id']) : 0;
    if ( $release_id <= 0 ) wp_send_json_error('Release inválido.');

    global $wpdb;
    $table_r = $wpdb->prefix . 'rmbz_distro_releases';
    $owner = $wpdb->get_row( $wpdb->prepare(
        "SELECT id, status FROM $table_r WHERE id = %d AND artist_telemovel = %s",
        $release_id, $telemovel
    ) );
    if ( ! $owner ) wp_send_json_error('Release não encontrado.', 404);
    if ( ! in_array( (string) $owner->status, ['incomplete', 'draft', 'returned'], true ) ) {
        wp_send_json_error('Este lançamento já foi submetido e não pode ser editado.', 403);
    }

    // Territórios: 3 modos
    //   'worldwide'         — todos os países
    //   'worldwide_except'  — todos excepto os listados
    //   'selected'          — apenas os listados
    $valid_modes = ['worldwide', 'worldwide_except', 'selected'];
    $territory_mode = isset($_POST['territory_mode']) && in_array($_POST['territory_mode'], $valid_modes, true)
        ? $_POST['territory_mode'] : 'worldwide';

    $territory_list = [];
    if ( in_array($territory_mode, ['selected','worldwide_except'], true)
         && ! empty($_POST['territories']) && is_array($_POST['territories']) ) {
        $valid_codes = array_keys( rmbz_distro_territory_list() );
        foreach ( $_POST['territories'] as $code ) {
            $code = strtoupper( sanitize_text_field($code) );
            if ( in_array($code, $valid_codes, true) ) $territory_list[] = $code;
        }
        if ( $territory_mode === 'selected' && empty($territory_list) ) {
            wp_send_json_error('Selecione pelo menos um país ou escolha "Worldwide".');
        }
        if ( $territory_mode === 'worldwide_except' && empty($territory_list) ) {
            // Se escolheu "excluir" mas não marcou nada, trata como worldwide normal
            $territory_mode = 'worldwide';
        }
    }

    // DSPs
    $dsp_list = [];
    $valid_dsps = array_keys( rmbz_distro_dsp_catalog() );
    if ( ! empty($_POST['dsps']) && is_array($_POST['dsps']) ) {
        foreach ( $_POST['dsps'] as $slug ) {
            $slug = sanitize_key( $slug );
            if ( in_array($slug, $valid_dsps, true) ) $dsp_list[] = $slug;
        }
    }
    if ( empty($dsp_list) ) {
        wp_send_json_error('Selecione pelo menos uma loja.');
    }

    // Exclusivos: artista só pode PEDIR (requested) ou NÃO pedir (not_requested).
    $yt_opt = ! empty($_POST['yt_content_id_optin']) ? 'requested' : 'not_requested';
    $fb_opt = ! empty($_POST['fb_monet_optin'])      ? 'requested' : 'not_requested';
    $tt_opt = ! empty($_POST['tt_monet_optin'])      ? 'requested' : 'not_requested';

    // Não sobrescrever decisões admin já tomadas
    $current = rmbz_distro_get_platforms( $release_id );
    $update = [
        'territory_mode' => $territory_mode,
        'territory_list' => wp_json_encode( $territory_list ),
        'dsp_list'       => wp_json_encode( array_values( array_unique($dsp_list) ) ),
        'user_confirmed' => 1,
        'updated_at'     => current_time('mysql'),
    ];

    if ( in_array( $current->yt_content_id_status, ['not_requested','requested'], true ) ) {
        $update['yt_content_id_status'] = $yt_opt;
    }
    if ( in_array( $current->fb_monet_status, ['not_requested','requested'], true ) ) {
        $update['fb_monet_status'] = $fb_opt;
    }
    if ( in_array( $current->tt_monet_status, ['not_requested','requested'], true ) ) {
        $update['tt_monet_status'] = $tt_opt;
    }

    $wpdb->update(
        $wpdb->prefix . 'rmbz_distro_release_platforms',
        $update,
        [ 'release_id' => $release_id ]
    );

    // [OPTIN-FB-2] Listar quais exclusivos ficaram em estado 'requested' após o save,
    // para o cliente confirmar visualmente o que foi de facto registado.
    $exclusives_requested = [];
    if ( ($update['yt_content_id_status'] ?? null) === 'requested' ) $exclusives_requested[] = 'YouTube Content ID';
    if ( ($update['fb_monet_status']      ?? null) === 'requested' ) $exclusives_requested[] = 'Facebook/Instagram';
    if ( ($update['tt_monet_status']      ?? null) === 'requested' ) $exclusives_requested[] = 'TikTok';

    wp_send_json_success([
        'message'              => 'Lojas e serviços guardados.',
        'dsp_count'            => count($dsp_list),
        'territory_count'      => $territory_mode === 'worldwide' ? 'worldwide' : count($territory_list),
        'exclusives_requested' => $exclusives_requested,
    ]);
}
add_action( 'wp_ajax_rmbz_save_release_platforms', 'rmbz_ajax_save_release_platforms' );
add_action( 'wp_ajax_nopriv_rmbz_save_release_platforms', 'rmbz_ajax_save_release_platforms' );


/* ============================================================================
 * ADMIN: decidir sobre serviços exclusivos
 * ============================================================================ */

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

    $release_id = isset($_POST['release_id']) ? absint($_POST['release_id']) : 0;
    $service    = sanitize_key( $_POST['service'] ?? '' );
    $decision   = sanitize_key( $_POST['decision'] ?? '' );
    $note       = sanitize_textarea_field( $_POST['note'] ?? '' );
    // [FEAT 1.5.14] Campos adicionais para estado 'conflict'
    $conflict_url    = isset($_POST['conflict_url']) ? esc_url_raw( trim( (string) $_POST['conflict_url'] ) ) : '';
    $conflict_source = isset($_POST['conflict_source']) ? sanitize_text_field( (string) $_POST['conflict_source'] ) : '';

    $valid_services = [
        'yt_content_id' => 'yt_content_id_status',
        'fb_monet'      => 'fb_monet_status',
        'tt_monet'      => 'tt_monet_status',
    ];
    if ( ! isset( $valid_services[$service] ) ) wp_die('Serviço inválido.');
    // [FEAT 1.5.14] Adicionado 'conflict' aos estados aceites.
    if ( ! in_array( $decision, ['approved','rejected','conflict'], true ) ) wp_die('Decisão inválida.');

    // Se conflict, a nota é obrigatória
    if ( $decision === 'conflict' && trim($note) === '' ) {
        wp_die('Para marcar conflito é obrigatório descrever o motivo na nota.');
    }

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

    $col          = $valid_services[$service];
    $note_col     = str_replace('_status', '_decision_note', $col);
    $conflict_url_col    = str_replace('_status', '_conflict_url',    $col);
    $conflict_source_col = str_replace('_status', '_conflict_source', $col);

    $update_data = [
        $col          => $decision,
        $note_col     => $note,
        'decided_by'  => wp_get_current_user()->user_login,
        'decided_at'  => current_time('mysql'),
        'updated_at'  => current_time('mysql'),
    ];

    // URL e fonte do conflito: guardar se decisão for 'conflict', limpar senão.
    if ( $decision === 'conflict' ) {
        $update_data[$conflict_url_col]    = $conflict_url;
        $update_data[$conflict_source_col] = $conflict_source;
    } else {
        $update_data[$conflict_url_col]    = null;
        $update_data[$conflict_source_col] = null;
    }

    $wpdb->update( $table, $update_data, [ 'release_id' => $release_id ] );

    // Notificar o artista se o módulo de notificações estiver disponível
    if ( function_exists('rmbz_add_notification') ) {
        $release = $wpdb->get_row( $wpdb->prepare(
            "SELECT artist_telemovel, title FROM {$wpdb->prefix}rmbz_distro_releases WHERE id = %d",
            $release_id
        ) );
        if ( $release ) {
            $services_lbl = [
                'yt_content_id' => 'YouTube Content ID',
                'fb_monet'      => 'Facebook monetization',
                'tt_monet'      => 'TikTok monetization',
            ];
            if ( $decision === 'approved' ) {
                $msg = sprintf( '✅ %s aprovado para "%s".', $services_lbl[$service], $release->title );
            } elseif ( $decision === 'rejected' ) {
                $msg = sprintf( '❌ %s rejeitado para "%s". Motivo: %s', $services_lbl[$service], $release->title, $note ?: 'não especificado' );
            } else { // conflict
                $msg = sprintf(
                    '⚠️ Conflito detectado em %s para "%s". A música parece já estar registada por outro distribuidor/titular%s. Contacte-nos para resolver.',
                    $services_lbl[$service],
                    $release->title,
                    $conflict_source ? ' (' . $conflict_source . ')' : ''
                );
            }
            rmbz_add_notification( $release->artist_telemovel, $msg );
        }
    }

    wp_safe_redirect( add_query_arg( ['msg' => 'exclusive_decided'], wp_get_referer() ) );
    exit;
}
add_action( 'admin_post_rmbz_decide_exclusive', 'rmbz_admin_decide_exclusive_service' );


/* ============================================================================
 * WIZARD STEP 2 — conteúdo interno (chamado por distribution-wizard.php)
 * ============================================================================
 * Esta função é o INTERIOR do passo 2 — não inclui wrapper nem header,
 * porque esses são fornecidos pelo novo wizard. Estilos próprios das secções
 * são auto-contidos.
 * ============================================================================ */
function rmbz_render_wizard_step2_inner( $release_id ) {
    if ( ! $release_id ) {
        echo '<div class="rmbz-s2-locked-msg">' . esc_html__( 'Salve o passo 1 primeiro.', '1mz-for-artists' ) . '</div>';
        return;
    }

    $platforms  = rmbz_distro_get_platforms( $release_id );
    $catalog    = rmbz_distro_dsp_catalog();
    $exclusives = rmbz_distro_exclusive_services();
    $countries  = rmbz_distro_territory_list();

    $selected_dsps      = $platforms->_dsp_list;
    $selected_countries = $platforms->_territory_list;
    $territory_mode     = $platforms->territory_mode;

    $yt_status = $platforms->yt_content_id_status;
    $fb_status = $platforms->fb_monet_status;
    $tt_status = $platforms->tt_monet_status;

    // [DS 1.5.48] Badge gerado via classes CSS (era HTML inline com cores
    // hardcoded). Os 4 estados estão definidos no <style> abaixo como
    // .rmbz-s2-status-badge--{status}.
    $status_badge = function( $status ) {
        $labels = [
            'approved'  => '✓ APROVADO',
            'rejected'  => '✗ REJEITADO',
            'requested' => '⏳ EM REVISÃO',
        ];
        if ( isset( $labels[ $status ] ) ) {
            return sprintf(
                '<span class="rmbz-s2-status-badge rmbz-s2-status-badge--%s">%s</span>',
                esc_attr( $status ),
                esc_html( $labels[ $status ] )
            );
        }
        return '<span class="rmbz-s2-status-badge rmbz-s2-status-badge--none">não solicitado</span>';
    };

    ?>

    <div class="rmbz-s2-section">
        <h4 class="rmbz-s2-h">🌍 Territórios</h4>
        <p class="rmbz-s2-desc">Onde tem direitos para lançar a obra?</p>

        <div class="rmbz-s2-cards three">
            <label class="rmbz-s2-card <?php echo $territory_mode === 'worldwide' ? 'sel' : ''; ?>" data-mode="worldwide">
                <input type="radio" name="rmbz_territory_mode" value="worldwide" <?php checked($territory_mode, 'worldwide'); ?>>
                <div>
                    <strong>🌐 Todo o mundo</strong>
                    <small>Recomendado</small>
                </div>
            </label>
            <label class="rmbz-s2-card <?php echo $territory_mode === 'worldwide_except' ? 'sel' : ''; ?>" data-mode="worldwide_except">
                <input type="radio" name="rmbz_territory_mode" value="worldwide_except" <?php checked($territory_mode, 'worldwide_except'); ?>>
                <div>
                    <strong>🌐 ➖ Excluir</strong>
                    <small>Mundo excepto alguns</small>
                </div>
            </label>
            <label class="rmbz-s2-card <?php echo $territory_mode === 'selected' ? 'sel' : ''; ?>" data-mode="selected">
                <input type="radio" name="rmbz_territory_mode" value="selected" <?php checked($territory_mode, 'selected'); ?>>
                <div>
                    <strong>📍 Escolher países</strong>
                    <small>Apenas os marcados</small>
                </div>
            </label>
        </div>

        <div id="rmbz-countries-wrap" style="display:<?php echo in_array($territory_mode, ['selected','worldwide_except'], true) ? 'block' : 'none'; ?>;">

            <div class="rmbz-s2-countries-mode-hint" id="rmbz-countries-hint">
                <?php if ( $territory_mode === 'worldwide_except' ): ?>
                    <strong>⚠️ Modo exclusão:</strong> os países que marcar abaixo serão <u>excluídos</u>. Os não marcados recebem a música.
                <?php else: ?>
                    <strong>✓ Modo seleção:</strong> apenas os países marcados abaixo receberão a música.
                <?php endif; ?>
            </div>

            <div class="rmbz-s2-countries-search">
                <input type="text" id="rmbz-countries-search" placeholder="🔍 Procurar país..." autocomplete="off">
                <div class="rmbz-s2-countries-actions">
                    <button type="button" class="tiny-chip" onclick="rmbzRegionToggleAll(true)">✓ Marcar todos</button>
                    <button type="button" class="tiny-chip" onclick="rmbzRegionToggleAll(false)">✗ Desmarcar todos</button>
                </div>
            </div>

            <div class="rmbz-s2-regions">
                <?php
                $regions = rmbz_distro_territory_regions();
                foreach ( $regions as $region_key => $region ):
                    $region_codes = array_keys($region['countries']);
                    $selected_in_region = array_intersect($region_codes, $selected_countries);
                    $region_count = count($selected_in_region);
                    $region_total = count($region_codes);
                    $is_open = $region_count > 0;
                ?>
                    <details class="rmbz-s2-region" <?php echo $is_open ? 'open' : ''; ?>>
                        <summary>
                            <span class="region-label"><?php echo esc_html($region['label']); ?></span>
                            <span class="region-count">
                                <span class="region-sel"><?php echo $region_count; ?></span>/<?php echo $region_total; ?>
                            </span>
                            <button type="button" class="tiny-chip" onclick="event.preventDefault(); event.stopPropagation(); rmbzRegionToggle('<?php echo esc_js($region_key); ?>', true)">tudo</button>
                            <button type="button" class="tiny-chip" onclick="event.preventDefault(); event.stopPropagation(); rmbzRegionToggle('<?php echo esc_js($region_key); ?>', false)">nada</button>
                        </summary>
                        <div class="rmbz-s2-region-countries" data-region="<?php echo esc_attr($region_key); ?>">
                            <?php foreach ( $region['countries'] as $code => $name ): ?>
                                <label class="country-item" data-name="<?php echo esc_attr(strtolower($name)); ?>" data-code="<?php echo esc_attr(strtolower($code)); ?>">
                                    <input type="checkbox" name="rmbz_territories[]" value="<?php echo esc_attr($code); ?>"
                                           data-region="<?php echo esc_attr($region_key); ?>"
                                           <?php checked( in_array($code, $selected_countries, true) ); ?>>
                                    <span class="country-name"><?php echo esc_html($name); ?></span>
                                    <span class="country-code"><?php echo esc_html($code); ?></span>
                                </label>
                            <?php endforeach; ?>
                        </div>
                    </details>
                <?php endforeach; ?>
            </div>
        </div>
    </div>

    <div class="rmbz-s2-section">
        <div class="rmbz-s2-section-head">
            <div>
                <h4 class="rmbz-s2-h">📻 <?php esc_html_e( 'Lojas e plataformas', '1mz-for-artists' ); ?></h4>
                <p class="rmbz-s2-desc">
                    <?php
                    printf(
                        /* translators: %1$d = seleccionadas, %2$d = total */
                        esc_html__( '%1$s de %2$d seleccionadas', '1mz-for-artists' ),
                        '<span id="rmbz-dsp-count-num">' . count( $selected_dsps ) . '</span>',
                        count( $catalog )
                    );
                    ?>
                </p>
            </div>
            <div class="rmbz-s2-chips">
                <button type="button" class="chip active" onclick="rmbzDspToggleAll(true, this)"><?php esc_html_e( 'Todas', '1mz-for-artists' ); ?></button>
                <button type="button" class="chip" onclick="rmbzDspToggleAll(false, this)"><?php esc_html_e( 'Nenhuma', '1mz-for-artists' ); ?></button>
                <button type="button" class="chip" onclick="rmbzDspSelectTier(1, this)"><?php esc_html_e( 'Só essenciais', '1mz-for-artists' ); ?></button>
            </div>
        </div>

        <div class="rmbz-s2-dsp-box">
            <?php
            $tiers = [
                1 => [ 'label' => 'Essenciais — cobrem 95% dos streams globais', 'color' => '#f0b90b' ],
                2 => [ 'label' => 'Regionais — relevantes para a sua audiência',  'color' => '#3498db' ],
                3 => [ 'label' => 'Nicho e Ásia — especializadas',                 'color' => '#9b59b6' ],
            ];
            foreach ( $tiers as $tier => $info ): ?>
                <div class="rmbz-s2-tier">
                    <div class="rmbz-s2-tier-h" style="--tc:<?php echo esc_attr($info['color']); ?>;">
                        <span class="dot"></span>
                        Tier <?php echo $tier; ?> — <?php echo esc_html($info['label']); ?>
                    </div>
                    <div class="rmbz-s2-dsps">
                        <?php foreach ( $catalog as $slug => $meta ): ?>
                            <?php if ( $meta['tier'] !== $tier ) continue; ?>
                            <label class="rmbz-s2-dsp">
                                <input type="checkbox" class="rmbz-dsp-check" name="rmbz_dsps[]"
                                       data-tier="<?php echo $tier; ?>"
                                       value="<?php echo esc_attr($slug); ?>"
                                       <?php checked( in_array($slug, $selected_dsps, true) ); ?>>
                                <span><?php echo esc_html($meta['name']); ?></span>
                            </label>
                        <?php endforeach; ?>
                    </div>
                </div>
            <?php endforeach; ?>
        </div>
    </div>

    <div class="rmbz-s2-section">
        <h4 class="rmbz-s2-h">⚠️ Serviços exclusivos (opcional)</h4>
        <p class="rmbz-s2-desc">
            <?php
            printf(
                /* translators: %s = "direitos exclusivos" em destaque */
                esc_html__( 'Estes serviços exigem %s. Leia o aviso completo antes de aceitar. A equipa 1MZ revê e aprova cada pedido.', '1mz-for-artists' ),
                '<strong class="rmbz-s2-strong-brand">' . esc_html__( 'direitos exclusivos', '1mz-for-artists' ) . '</strong>'
            );
            ?>
        </p>

        <?php
        $service_map = [
            'yt_content_id'        => [ 'data' => $exclusives['youtube_content_id'],     'status' => $yt_status, 'note' => $platforms->yt_content_id_decision_note, 'optin_field' => 'yt_content_id_optin' ],
            'facebook_monetization'=> [ 'data' => $exclusives['facebook_monetization'],  'status' => $fb_status, 'note' => $platforms->fb_monet_decision_note,      'optin_field' => 'fb_monet_optin' ],
            'tiktok_monetization'  => [ 'data' => $exclusives['tiktok_monetization'],    'status' => $tt_status, 'note' => $platforms->tt_monet_decision_note,      'optin_field' => 'tt_monet_optin' ],
        ];

        foreach ( $service_map as $key => $svc ):
            $is_locked = in_array( $svc['status'], ['approved','rejected'], true );
            $is_requested = $svc['status'] === 'requested';
        ?>
            <div class="rmbz-s2-excl" data-service="<?php echo esc_attr($key); ?>">
                <div class="rmbz-s2-excl-head">
                    <div class="rmbz-s2-excl-meta">
                        <div class="rmbz-s2-excl-titlerow">
                            <strong><?php echo esc_html($svc['data']['name']); ?></strong>
                            <?php echo $status_badge($svc['status']); ?>
                        </div>
                        <p><?php echo esc_html($svc['data']['short']); ?></p>
                    </div>
                    <button type="button" class="rmbz-s2-toggle"><?php esc_html_e( 'Ler aviso', '1mz-for-artists' ); ?> ▼</button>
                </div>

                <div class="rmbz-s2-excl-body" style="display:none;">
                    <div class="rmbz-s2-notice"><?php echo esc_html($svc['data']['notice']); ?></div>

                    <?php if ( $is_locked ): ?>
                        <div class="rmbz-s2-decision <?php echo $svc['status']; ?>">
                            <strong>Decisão da administração: <?php echo esc_html(strtoupper($svc['status'])); ?></strong>
                            <?php if ( $svc['note'] ): ?>
                                <p><?php echo esc_html($svc['note']); ?></p>
                            <?php endif; ?>
                        </div>
                    <?php else: ?>
                        <label class="rmbz-s2-optin">
                            <input type="checkbox"
                                   class="rmbz-s2-optin-cb"
                                   name="rmbz_<?php echo esc_attr($svc['optin_field']); ?>"
                                   value="1"
                                   <?php checked( $is_requested ); ?>
                                   disabled
                                   data-must-read="1">
                            <span>
                                <strong class="rmbz-s2-optin-strong"><?php esc_html_e( 'Li o aviso completo e aceito', '1mz-for-artists' ); ?></strong>
                                <?php
                                printf(
                                    /* translators: %s = nome do serviço (ex: YouTube Content ID) */
                                    esc_html__( 'conceder direitos exclusivos à 1MZ para %s. Declaro que possuo todos os direitos e que esta obra não foi entregue a outra distribuidora para este serviço.', '1mz-for-artists' ),
                                    esc_html( $svc['data']['name'] )
                                );
                                ?>
                                <br><small class="rmbz-s2-optin-hint"><?php esc_html_e( 'A activação só acontece após revisão e aprovação pela equipa 1MZ.', '1mz-for-artists' ); ?></small>
                            </span>
                        </label>
                    <?php endif; ?>
                </div>
            </div>
        <?php endforeach; ?>
    </div>

    <div class="rmbz-w-step-foot">
        <span class="rmbz-w-status" id="rmbz-w-status-2"></span>
        <button type="button" class="rmbz-w-btn primary" id="btn-save-step-2">CONFIRMAR E CONTINUAR →</button>
    </div>

    <style>
    /* [DS 1.5.48] CSS do passo 2 do wizard tokenizado.
     * Estrutura preservada (todas as classes .rmbz-s2-*). Mantém funções
     * globais JS (rmbzDspToggleAll, rmbzDspSelectTier, rmbzRegionToggle,
     * rmbzRegionToggleAll) e endpoint AJAX rmbz_save_release_platforms.
     * Adiciona classes novas (.rmbz-s2-section-head, .rmbz-s2-excl-meta,
     * .rmbz-s2-excl-titlerow, .rmbz-s2-status-badge, .rmbz-s2-strong-brand,
     * .rmbz-s2-optin-strong, .rmbz-s2-optin-hint, .rmbz-s2-locked-msg)
     * para substituir HTML com inline styles.
     */

    /* Mensagem inicial quando não há release_id */
    .rmbz-s2-locked-msg {
        padding: var(--rmbz-space-5);
        text-align: center;
        color: var(--rmbz-text-muted);
        font-size: var(--rmbz-text-sm);
    }

    /* Sections: cada bloco é uma secção semântica com divider */
    .rmbz-s2-section {
        margin-bottom: var(--rmbz-space-6);
        padding-bottom: var(--rmbz-space-6);
        border-bottom: 1px solid var(--rmbz-border-subtle);
    }
    .rmbz-s2-section:last-of-type {
        border-bottom: none;
        padding-bottom: 0;
    }

    .rmbz-s2-h {
        margin: 0 0 var(--rmbz-space-1) 0;
        font-family: var(--rmbz-font-display);
        font-size: var(--rmbz-text-sm);
        font-weight: var(--rmbz-weight-semibold);
        color: var(--rmbz-text-primary);
    }

    .rmbz-s2-desc {
        margin: 0 0 var(--rmbz-space-3) 0;
        color: var(--rmbz-text-muted);
        font-size: var(--rmbz-text-xs);
        line-height: var(--rmbz-leading-relaxed);
    }

    /* Header de secção com toolbar à direita */
    .rmbz-s2-section-head {
        display: flex;
        justify-content: space-between;
        align-items: center;
        flex-wrap: wrap;
        gap: var(--rmbz-space-3);
        margin-bottom: var(--rmbz-space-3);
    }

    /* Strong dourado em descrições — usado no "direitos exclusivos" */
    .rmbz-s2-strong-brand {
        color: var(--rmbz-brand);
        font-weight: var(--rmbz-weight-semibold);
    }

    /* === TERRITÓRIOS === */
    /* Cards radio grandes para escolher modo (Todo o mundo / Excluir / Escolher) */
    .rmbz-s2-cards {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: var(--rmbz-space-3);
    }
    .rmbz-s2-cards.three {
        grid-template-columns: 1fr 1fr 1fr;
    }
    @media (max-width: 500px) {
        .rmbz-s2-cards,
        .rmbz-s2-cards.three { grid-template-columns: 1fr; }
    }

    .rmbz-s2-card {
        display: block;
        padding: var(--rmbz-space-4);
        background: var(--rmbz-bg-input);
        border: 1px solid var(--rmbz-border-subtle);
        border-radius: var(--rmbz-radius-sm);
        cursor: pointer;
        transition: all var(--rmbz-duration-fast) var(--rmbz-ease-out);
    }
    .rmbz-s2-card:hover {
        border-color: var(--rmbz-border-strong);
    }
    .rmbz-s2-card.sel {
        background: var(--rmbz-brand-soft);
        border-color: var(--rmbz-brand);
    }
    .rmbz-s2-card input { display: none; }
    .rmbz-s2-card strong {
        display: block;
        font-family: var(--rmbz-font-body);
        font-size: var(--rmbz-text-sm);
        font-weight: var(--rmbz-weight-semibold);
        color: var(--rmbz-text-secondary);
    }
    .rmbz-s2-card.sel strong {
        color: var(--rmbz-brand);
    }
    .rmbz-s2-card small {
        color: var(--rmbz-text-muted);
        font-size: var(--rmbz-text-xs);
    }

    /* Aviso do modo (selecção vs exclusão) */
    .rmbz-s2-countries-mode-hint {
        background: var(--rmbz-brand-soft);
        border-left: 3px solid var(--rmbz-brand);
        padding: var(--rmbz-space-3) var(--rmbz-space-4);
        border-radius: 0 var(--rmbz-radius-sm) var(--rmbz-radius-sm) 0;
        color: var(--rmbz-text-secondary);
        font-size: var(--rmbz-text-xs);
        line-height: var(--rmbz-leading-relaxed);
        margin-top: var(--rmbz-space-4);
        margin-bottom: var(--rmbz-space-3);
    }

    /* Search box + actions */
    .rmbz-s2-countries-search {
        display: flex;
        gap: var(--rmbz-space-2);
        margin-bottom: var(--rmbz-space-3);
        flex-wrap: wrap;
        align-items: center;
    }
    .rmbz-s2-countries-search input {
        flex: 1;
        min-width: 180px;
        padding: var(--rmbz-space-2) var(--rmbz-space-3);
        background: var(--rmbz-bg-input);
        border: 1px solid var(--rmbz-border-subtle);
        border-radius: var(--rmbz-radius-sm);
        color: var(--rmbz-text-primary);
        font-family: var(--rmbz-font-body);
        font-size: var(--rmbz-text-xs);
        transition: border-color var(--rmbz-duration-fast) var(--rmbz-ease-out);
    }
    .rmbz-s2-countries-search input:focus {
        outline: none;
        border-color: var(--rmbz-brand);
        box-shadow: 0 0 0 3px rgba(240, 185, 11, 0.15);
    }
    .rmbz-s2-countries-actions {
        display: flex;
        gap: var(--rmbz-space-1);
        flex-wrap: wrap;
    }

    /* Tiny chip — botões pequenos para acções rápidas (marcar tudo, etc.) */
    .tiny-chip {
        background: var(--rmbz-bg-input);
        border: 1px solid var(--rmbz-border-subtle);
        color: var(--rmbz-text-muted);
        padding: var(--rmbz-space-1) var(--rmbz-space-3);
        border-radius: var(--rmbz-radius-pill);
        font-family: var(--rmbz-font-body);
        font-size: var(--rmbz-text-2xs);
        font-weight: var(--rmbz-weight-semibold);
        cursor: pointer;
        text-transform: uppercase;
        letter-spacing: var(--rmbz-tracking-wider);
        transition: all var(--rmbz-duration-fast) var(--rmbz-ease-out);
    }
    .tiny-chip:hover {
        border-color: var(--rmbz-brand);
        color: var(--rmbz-brand);
    }

    /* Lista de regiões (continentes/áreas) — cada uma é um <details> colapsável */
    .rmbz-s2-regions {
        display: flex;
        flex-direction: column;
        gap: var(--rmbz-space-2);
    }
    .rmbz-s2-region {
        background: var(--rmbz-bg-input);
        border: 1px solid var(--rmbz-border-subtle);
        border-radius: var(--rmbz-radius-sm);
        overflow: hidden;
    }
    .rmbz-s2-region[open] {
        border-color: var(--rmbz-border-strong);
    }
    .rmbz-s2-region > summary {
        padding: var(--rmbz-space-3) var(--rmbz-space-4);
        cursor: pointer;
        list-style: none;
        display: flex;
        align-items: center;
        gap: var(--rmbz-space-3);
        user-select: none;
    }
    .rmbz-s2-region > summary::-webkit-details-marker { display: none; }
    .rmbz-s2-region > summary::before {
        content: '▸';
        color: var(--rmbz-text-muted);
        font-size: var(--rmbz-text-2xs);
        transition: transform var(--rmbz-duration-fast) var(--rmbz-ease-out);
        flex-shrink: 0;
    }
    .rmbz-s2-region[open] > summary::before { transform: rotate(90deg); }

    .rmbz-s2-region .region-label {
        flex: 1;
        font-family: var(--rmbz-font-body);
        font-size: var(--rmbz-text-sm);
        font-weight: var(--rmbz-weight-semibold);
        color: var(--rmbz-text-secondary);
    }
    .rmbz-s2-region .region-count {
        background: var(--rmbz-bg-base);
        padding: var(--rmbz-space-1) var(--rmbz-space-2);
        border-radius: var(--rmbz-radius-pill);
        margin-right: var(--rmbz-space-1);
        font-family: var(--rmbz-font-mono);
        font-size: var(--rmbz-text-2xs);
        color: var(--rmbz-text-muted);
        font-variant-numeric: tabular-nums;
    }
    .rmbz-s2-region .region-count .region-sel {
        color: var(--rmbz-brand);
        font-weight: var(--rmbz-weight-bold);
    }

    .rmbz-s2-region-countries {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
        gap: 3px;
        padding: var(--rmbz-space-2) var(--rmbz-space-4) var(--rmbz-space-3) calc(var(--rmbz-space-6) + 6px);
        border-top: 1px solid var(--rmbz-border-subtle);
    }

    /* Item de país individual (checkbox + nome + código ISO) */
    .country-item {
        display: flex;
        align-items: center;
        gap: var(--rmbz-space-2);
        padding: var(--rmbz-space-1) var(--rmbz-space-2);
        border-radius: 3px;
        cursor: pointer;
        transition: background var(--rmbz-duration-fast) var(--rmbz-ease-out);
        font-size: var(--rmbz-text-xs);
    }
    .country-item:hover {
        background: var(--rmbz-bg-hover);
    }
    .country-item input {
        accent-color: var(--rmbz-brand);
        flex-shrink: 0;
    }
    .country-item input:checked ~ .country-name {
        color: var(--rmbz-brand);
    }
    .country-item .country-name {
        flex: 1;
        color: var(--rmbz-text-secondary);
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }
    .country-item .country-code {
        font-family: var(--rmbz-font-mono);
        font-size: var(--rmbz-text-2xs);
        color: var(--rmbz-text-muted);
        flex-shrink: 0;
    }
    .country-item.hidden { display: none; }

    /* === DSPs (LOJAS E PLATAFORMAS) === */
    /* Chips toolbar (Todas / Nenhuma / Só essenciais) */
    .rmbz-s2-chips {
        display: flex;
        gap: var(--rmbz-space-1);
        flex-wrap: wrap;
    }
    .rmbz-s2-chips .chip {
        padding: var(--rmbz-space-2) var(--rmbz-space-3);
        background: var(--rmbz-bg-input);
        color: var(--rmbz-text-muted);
        border: 1px solid var(--rmbz-border-subtle);
        border-radius: var(--rmbz-radius-pill);
        font-family: var(--rmbz-font-body);
        font-size: var(--rmbz-text-2xs);
        font-weight: var(--rmbz-weight-semibold);
        cursor: pointer;
        text-transform: uppercase;
        letter-spacing: var(--rmbz-tracking-wider);
        transition: all var(--rmbz-duration-fast) var(--rmbz-ease-out);
    }
    .rmbz-s2-chips .chip.active {
        background: var(--rmbz-brand);
        color: var(--rmbz-text-on-brand);
        border-color: var(--rmbz-brand);
    }
    .rmbz-s2-chips .chip:hover:not(.active) {
        color: var(--rmbz-text-primary);
        border-color: var(--rmbz-border-strong);
    }

    /* Box de DSPs com 3 tiers */
    .rmbz-s2-dsp-box {
        background: var(--rmbz-bg-input);
        border: 1px solid var(--rmbz-border-subtle);
        border-radius: var(--rmbz-radius-sm);
        padding: var(--rmbz-space-4);
    }
    .rmbz-s2-tier {
        margin-bottom: var(--rmbz-space-4);
    }
    .rmbz-s2-tier:last-child { margin-bottom: 0; }

    /* Header de tier — uppercase pequeno com cor própria (--tc passada via inline) */
    .rmbz-s2-tier-h {
        display: flex;
        align-items: center;
        gap: var(--rmbz-space-2);
        margin-bottom: var(--rmbz-space-2);
        padding-bottom: var(--rmbz-space-2);
        border-bottom: 1px dashed var(--rmbz-border-subtle);
        color: var(--tc, var(--rmbz-text-muted));
        font-family: var(--rmbz-font-body);
        font-size: var(--rmbz-text-2xs);
        text-transform: uppercase;
        letter-spacing: var(--rmbz-tracking-wider);
        font-weight: var(--rmbz-weight-bold);
    }
    .rmbz-s2-tier-h .dot {
        width: 6px;
        height: 6px;
        background: var(--tc, var(--rmbz-text-muted));
        border-radius: 50%;
    }

    /* Grid de DSPs individuais */
    .rmbz-s2-dsps {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
        gap: var(--rmbz-space-1);
    }
    .rmbz-s2-dsp {
        display: flex;
        align-items: center;
        gap: var(--rmbz-space-2);
        padding: var(--rmbz-space-1) var(--rmbz-space-2);
        background: var(--rmbz-bg-base);
        border-radius: var(--rmbz-radius-sm);
        cursor: pointer;
        transition: background var(--rmbz-duration-fast) var(--rmbz-ease-out);
    }
    .rmbz-s2-dsp:hover {
        background: var(--rmbz-bg-hover);
    }
    .rmbz-s2-dsp input {
        accent-color: var(--rmbz-brand);
    }
    .rmbz-s2-dsp span {
        color: var(--rmbz-text-secondary);
        font-size: var(--rmbz-text-xs);
    }

    /* === SERVIÇOS EXCLUSIVOS === */
    /* Cartões para YouTube Content ID, Facebook, TikTok monetization */
    .rmbz-s2-excl {
        background: var(--rmbz-danger-soft);
        border: 1px solid rgba(239, 68, 68, 0.3);
        border-radius: var(--rmbz-radius-sm);
        margin-bottom: var(--rmbz-space-2);
        overflow: hidden;
    }

    .rmbz-s2-excl-head {
        padding: var(--rmbz-space-3) var(--rmbz-space-4);
        display: flex;
        justify-content: space-between;
        align-items: center;
        gap: var(--rmbz-space-3);
        flex-wrap: wrap;
    }

    .rmbz-s2-excl-meta {
        flex: 1;
        min-width: 200px;
    }

    .rmbz-s2-excl-titlerow {
        display: flex;
        align-items: center;
        gap: var(--rmbz-space-2);
        flex-wrap: wrap;
    }

    .rmbz-s2-excl-head strong {
        color: var(--rmbz-text-primary);
        font-family: var(--rmbz-font-body);
        font-size: var(--rmbz-text-sm);
        font-weight: var(--rmbz-weight-semibold);
    }

    .rmbz-s2-excl-head p {
        margin: var(--rmbz-space-1) 0 0 0;
        color: var(--rmbz-text-muted);
        font-size: var(--rmbz-text-xs);
    }

    .rmbz-s2-toggle {
        background: var(--rmbz-bg-input);
        border: 1px solid var(--rmbz-border-subtle);
        color: var(--rmbz-text-secondary);
        padding: var(--rmbz-space-2) var(--rmbz-space-3);
        border-radius: var(--rmbz-radius-sm);
        font-size: var(--rmbz-text-xs);
        cursor: pointer;
        white-space: nowrap;
        transition: all var(--rmbz-duration-fast) var(--rmbz-ease-out);
    }
    .rmbz-s2-toggle:hover {
        color: var(--rmbz-brand);
        border-color: var(--rmbz-brand);
    }

    .rmbz-s2-excl-body {
        padding: var(--rmbz-space-4);
        background: var(--rmbz-bg-base);
        border-top: 1px solid rgba(239, 68, 68, 0.3);
    }

    /* Notice (texto longo do aviso, com scroll) */
    .rmbz-s2-notice {
        color: var(--rmbz-text-secondary);
        font-size: var(--rmbz-text-xs);
        line-height: var(--rmbz-leading-loose);
        white-space: pre-line;
        max-height: 220px;
        overflow-y: auto;
        padding: var(--rmbz-space-3);
        background: var(--rmbz-bg-input);
        border-radius: var(--rmbz-radius-sm);
        border: 1px solid var(--rmbz-border-subtle);
    }

    /* Opt-in: começa esmaecido até user fazer scroll do notice */
    .rmbz-s2-optin {
        display: flex;
        align-items: flex-start;
        gap: var(--rmbz-space-3);
        margin-top: var(--rmbz-space-3);
        padding: var(--rmbz-space-3);
        background: var(--rmbz-bg-input);
        border-radius: var(--rmbz-radius-sm);
        cursor: pointer;
        opacity: 0.55;
        transition: opacity var(--rmbz-duration-normal) var(--rmbz-ease-out);
    }
    .rmbz-s2-optin.unlocked { opacity: 1; }
    .rmbz-s2-optin input {
        accent-color: var(--rmbz-brand);
        margin-top: 2px;
        flex-shrink: 0;
    }
    .rmbz-s2-optin span {
        color: var(--rmbz-text-secondary);
        font-size: var(--rmbz-text-xs);
        line-height: var(--rmbz-leading-relaxed);
    }
    .rmbz-s2-optin-strong {
        color: var(--rmbz-brand);
        font-weight: var(--rmbz-weight-semibold);
    }
    .rmbz-s2-optin-hint {
        color: var(--rmbz-text-muted);
        display: inline-block;
        margin-top: var(--rmbz-space-1);
    }

    /* Status badge (substitui inline HTML) */
    .rmbz-s2-status-badge {
        display: inline-block;
        padding: var(--rmbz-space-1) var(--rmbz-space-3);
        border-radius: var(--rmbz-radius-pill);
        font-family: var(--rmbz-font-body);
        font-size: var(--rmbz-text-2xs);
        font-weight: var(--rmbz-weight-bold);
    }
    .rmbz-s2-status-badge--approved {
        background: var(--rmbz-success-soft);
        color: var(--rmbz-success);
    }
    .rmbz-s2-status-badge--rejected {
        background: var(--rmbz-danger-soft);
        color: var(--rmbz-danger);
    }
    .rmbz-s2-status-badge--requested {
        background: var(--rmbz-brand-soft);
        color: var(--rmbz-brand);
    }
    .rmbz-s2-status-badge--none {
        color: var(--rmbz-text-muted);
        font-size: var(--rmbz-text-xs);
        font-weight: var(--rmbz-weight-normal);
        background: transparent;
        padding: 0;
    }

    /* Decisão final (após admin aprovar/rejeitar) */
    .rmbz-s2-decision {
        margin-top: var(--rmbz-space-3);
        padding: var(--rmbz-space-3);
        border-radius: var(--rmbz-radius-sm);
        font-size: var(--rmbz-text-xs);
    }
    .rmbz-s2-decision.approved {
        background: var(--rmbz-success-soft);
        color: var(--rmbz-success);
    }
    .rmbz-s2-decision.rejected {
        background: var(--rmbz-danger-soft);
        color: var(--rmbz-danger);
    }
    .rmbz-s2-decision p {
        margin: var(--rmbz-space-1) 0 0 0;
        color: var(--rmbz-text-muted);
    }
    </style>

    <script>
    (function () {
        var releaseId = <?php echo (int)$release_id; ?>;
        var ajaxUrl   = '<?php echo esc_js( admin_url('admin-ajax.php') ); ?>';
        var nonce     = '<?php echo esc_js( wp_create_nonce('rmbz_distro_nonce') ); ?>';

        window.rmbzDspToggleAll = function (check, btn) {
            document.querySelectorAll('.rmbz-dsp-check').forEach(cb => cb.checked = !!check);
            updateChipsActive(btn);
            updateCount();
        };
        window.rmbzDspSelectTier = function (tier, btn) {
            document.querySelectorAll('.rmbz-dsp-check').forEach(cb => {
                cb.checked = parseInt(cb.dataset.tier, 10) === tier;
            });
            updateChipsActive(btn);
            updateCount();
        };
        function updateChipsActive(activeBtn) {
            document.querySelectorAll('.rmbz-s2-chips .chip').forEach(c => c.classList.remove('active'));
            if ( activeBtn ) activeBtn.classList.add('active');
        }
        function updateCount() {
            var n = document.querySelectorAll('.rmbz-dsp-check:checked').length;
            var el = document.getElementById('rmbz-dsp-count-num');
            if ( el ) el.innerText = n;
        }
        document.querySelectorAll('.rmbz-dsp-check').forEach(cb => cb.addEventListener('change', function() {
            updateCount();
            document.querySelectorAll('.rmbz-s2-chips .chip').forEach(c => c.classList.remove('active'));
        }));

        // ======= TERRITORIES =======
        function updateModeUI() {
            var mode = document.querySelector('input[name="rmbz_territory_mode"]:checked');
            if ( ! mode ) return;
            var val = mode.value;

            document.querySelectorAll('.rmbz-s2-card').forEach(c => c.classList.remove('sel'));
            var activeCard = document.querySelector('.rmbz-s2-card[data-mode="' + val + '"]');
            if ( activeCard ) activeCard.classList.add('sel');

            var wrap = document.getElementById('rmbz-countries-wrap');
            if ( val === 'worldwide' ) {
                wrap.style.display = 'none';
            } else {
                wrap.style.display = 'block';
                var hint = document.getElementById('rmbz-countries-hint');
                if ( hint ) {
                    if ( val === 'worldwide_except' ) {
                        hint.innerHTML = '<strong>⚠️ Modo exclusão:</strong> os países que marcar abaixo serão <u>excluídos</u>. Os não marcados recebem a música.';
                    } else {
                        hint.innerHTML = '<strong>✓ Modo seleção:</strong> apenas os países marcados abaixo receberão a música.';
                    }
                }
            }
        }
        document.querySelectorAll('input[name="rmbz_territory_mode"]').forEach(r => r.addEventListener('change', updateModeUI));

        function updateRegionCounts() {
            document.querySelectorAll('.rmbz-s2-region').forEach(region => {
                var total = region.querySelectorAll('input[type="checkbox"]').length;
                var sel   = region.querySelectorAll('input[type="checkbox"]:checked').length;
                var span  = region.querySelector('.region-sel');
                if ( span ) span.innerText = sel;
            });
        }
        document.querySelectorAll('.rmbz-s2-region input[type="checkbox"]').forEach(cb => cb.addEventListener('change', updateRegionCounts));

        window.rmbzRegionToggle = function (regionKey, check) {
            document.querySelectorAll('.rmbz-s2-region-countries[data-region="' + regionKey + '"] input[type="checkbox"]').forEach(cb => {
                cb.checked = !!check;
            });
            updateRegionCounts();
        };
        window.rmbzRegionToggleAll = function (check) {
            document.querySelectorAll('.rmbz-s2-region input[type="checkbox"]').forEach(cb => cb.checked = !!check);
            updateRegionCounts();
        };

        // Live search
        var searchInput = document.getElementById('rmbz-countries-search');
        if ( searchInput ) {
            searchInput.addEventListener('input', function () {
                var q = this.value.toLowerCase().trim();
                document.querySelectorAll('.country-item').forEach(function (item) {
                    var name = item.dataset.name || '';
                    var code = item.dataset.code || '';
                    var match = q === '' || name.indexOf(q) !== -1 || code.indexOf(q) !== -1;
                    item.classList.toggle('hidden', ! match);
                });
                if ( q !== '' ) {
                    document.querySelectorAll('.rmbz-s2-region').forEach(r => r.setAttribute('open', ''));
                }
            });
        }

        document.querySelectorAll('.rmbz-s2-excl').forEach(card => {
            var btn   = card.querySelector('.rmbz-s2-toggle');
            var body  = card.querySelector('.rmbz-s2-excl-body');
            var optin = card.querySelector('.rmbz-s2-optin-cb');
            var label = card.querySelector('.rmbz-s2-optin');
            var read  = 0, timer = null;

            if ( ! btn || ! body ) return;

            // [OPTIN-FB-1] Feedback visual instantâneo: ao marcar/desmarcar,
            // actualizar o badge de status no topo do card antes mesmo do save
            // do passo 2. Evita confusão "marquei mas continua a dizer não
            // solicitado". O badge volta ao normal se desmarcar.
            // O estado real só é gravado ao clicar em CONFIRMAR E CONTINUAR.
            if ( optin ) {
                var headRow  = card.querySelector('.rmbz-s2-excl-head > div');
                var badgeWrap = headRow ? headRow.querySelector('div') : null;
                var originalBadgeHTML = badgeWrap ? badgeWrap.innerHTML : null;

                function refreshBadge() {
                    if ( ! badgeWrap || originalBadgeHTML === null ) return;
                    // Manter o <strong> do nome (primeiro filho), só trocar o badge.
                    var strong = badgeWrap.querySelector('strong');
                    if ( ! strong ) return;
                    var newBadge;
                    if ( optin.checked ) {
                        newBadge = '<span class="rmbz-s2-status-badge rmbz-s2-status-badge--requested" title="Será enviado para revisão da equipa 1MZ ao clicar em CONFIRMAR E CONTINUAR">★ marcado — guardar para enviar</span>';
                    } else {
                        // Restaurar HTML original (mantém badge antigo do servidor).
                        badgeWrap.innerHTML = originalBadgeHTML;
                        return;
                    }
                    badgeWrap.innerHTML = '';
                    badgeWrap.appendChild(strong);
                    badgeWrap.insertAdjacentHTML('beforeend', ' ' + newBadge);
                }

                optin.addEventListener('change', function() {
                    refreshBadge();
                    // Sinalizar globalmente que há alterações por guardar.
                    if ( typeof window.rmbzPlatformsDirty === 'undefined' ) window.rmbzPlatformsDirty = true;
                    var status = document.getElementById('rmbz-w-status-2');
                    if ( status && optin.checked ) {
                        status.innerHTML = '<span class="rmbz-text-brand">⚠ Não esqueça de clicar em CONFIRMAR E CONTINUAR para guardar.</span>';
                    }
                });
            }

            btn.addEventListener('click', function() {
                var open = body.style.display === 'block';
                if ( open ) {
                    body.style.display = 'none';
                    btn.innerText = 'Ler aviso ▼';
                    if ( timer ) { clearInterval(timer); timer = null; }
                } else {
                    body.style.display = 'block';
                    btn.innerText = 'Fechar aviso ▲';
                    if ( ! optin || ! optin.disabled ) return;
                    timer = setInterval(function() {
                        read++;
                        if ( read >= 6 ) {
                            optin.disabled = false;
                            if ( label ) label.classList.add('unlocked');
                            clearInterval(timer);
                            timer = null;
                        }
                    }, 1000);
                }
            });
        });

        var btnSave = document.getElementById('btn-save-step-2');
        if ( btnSave ) {
            btnSave.addEventListener('click', function() {
                var status = document.getElementById('rmbz-w-status-2');
                btnSave.disabled = true; btnSave.innerText = 'A guardar...';
                status.innerHTML = '';

                var fd = new FormData();
                fd.append('action', 'rmbz_save_release_platforms');
                fd.append('nonce', nonce);
                fd.append('release_id', releaseId);

                var mode = document.querySelector('input[name="rmbz_territory_mode"]:checked');
                fd.append('territory_mode', mode ? mode.value : 'worldwide');

                document.querySelectorAll('input[name="rmbz_territories[]"]:checked').forEach(cb => {
                    fd.append('territories[]', cb.value);
                });
                document.querySelectorAll('.rmbz-dsp-check:checked').forEach(cb => {
                    fd.append('dsps[]', cb.value);
                });

                ['yt_content_id_optin','fb_monet_optin','tt_monet_optin'].forEach(function(n) {
                    var cb = document.querySelector('input[name="rmbz_' + n + '"]');
                    if ( cb && cb.checked && ! cb.disabled ) fd.append(n, '1');
                });

                fetch(ajaxUrl, { method: 'POST', body: fd })
                    .then(r => r.json())
                    .then(d => {
                        if ( d.success ) {
                            // [OPTIN-FB-2] Limpar dirty flag e mostrar quantos
                            // exclusivos foram pedidos (se algum), para feedback claro.
                            window.rmbzPlatformsDirty = false;
                            var extra = '';
                            if ( d.data.exclusives_requested && d.data.exclusives_requested.length ) {
                                extra = ' · ' + d.data.exclusives_requested.length + ' exclusivo(s) pedido(s)';
                            }
                            status.innerHTML = '<span class="rmbz-text-success">✓ ' + d.data.dsp_count + ' plataformas guardadas' + extra + '</span>';
                            setTimeout(function() {
                                window.location.href = '?distro_action=edit_release&id=' + releaseId;
                            }, 600);
                        } else {
                            btnSave.disabled = false;
                            btnSave.innerText = 'CONFIRMAR E CONTINUAR →';
                            status.innerHTML = '<span class="rmbz-text-danger">✗ ' + (d.data || 'Erro') + '</span>';
                        }
                    })
                    .catch(function() {
                        btnSave.disabled = false;
                        btnSave.innerText = 'CONFIRMAR E CONTINUAR →';
                        status.innerHTML = '<span class="rmbz-text-danger">✗ Erro de ligação</span>';
                    });
            });
        }
    })();
    </script>
    <?php
}
