<?php
/**
 * includes/distribution/distribution-splits-frontend.php
 *
 * ============================================================================
 * INTERFACE FRONTEND DE SPLITS (artista) — 1.5.116
 * ============================================================================
 *
 * Substitui o placeholder "Funcionalidade de Splits em breve!" no botão
 * "🔧 Configurar Splits" da página de detalhe da release.
 *
 * Fluxo:
 *   1. Artista clica "🔧 Configurar Splits" numa release
 *   2. Modal abre listando todas as faixas da release
 *   3. Cada faixa mostra os splits actuais + botão "Editar splits"
 *   4. Clicar abre o editor inline para essa faixa
 *   5. Save via AJAX (`rmbz_splits_frontend_save`)
 *
 * Reusa toda a infra existente:
 *   - `rmbz_track_get_splits`, `rmbz_track_collaborator_roles`
 *   - Tabela `rmbz_track_splits`
 *   - Hook `rmbz_track_splits_saved` (classifica/notifica colaboradores)
 *   - Sistema de holdings (dinheiro retido até registo)
 *
 * Permissões:
 *   - Apenas o owner da release (artist_telemovel) pode configurar
 *   - Verificado via `rmbz_get_current_user_telemovel`
 */

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


/**
 * Verifica se o utilizador actual é dono da release.
 */
function rmbz_splits_user_owns_release( $release_id ) {
    if ( ! function_exists('rmbz_get_current_user_telemovel') ) return false;
    $tel = rmbz_get_current_user_telemovel();
    if ( empty($tel) ) return false;

    global $wpdb;
    $owner = $wpdb->get_var( $wpdb->prepare(
        "SELECT artist_telemovel FROM {$wpdb->prefix}rmbz_distro_releases WHERE id = %d",
        (int) $release_id
    ) );
    return ! empty($owner) && $owner === $tel;
}


/**
 * Devolve as faixas de uma release com seus splits associados.
 */
function rmbz_splits_get_release_tracks_with_splits( $release_id ) {
    global $wpdb;
    $tracks = $wpdb->get_results( $wpdb->prepare(
        "SELECT id, track_title, track_order, isrc_code, feat_artists
         FROM {$wpdb->prefix}rmbz_distro_tracks
         WHERE release_id = %d
         ORDER BY track_order ASC, id ASC",
        (int) $release_id
    ) );
    foreach ( (array) $tracks as $t ) {
        $t->splits = function_exists('rmbz_track_get_splits')
            ? rmbz_track_get_splits($t->id)
            : [];
    }
    return $tracks ?: [];
}


/**
 * [1.5.117] Emite um stub global de `rmbzOpenSplitsModal` que mostra uma
 * mensagem clara ao utilizador quando o modal NÃO foi renderizado nesta
 * página (ex: utilizador não é owner). Antes desta versão, clicar no
 * botão num cenário desses dava ReferenceError silencioso e parecia
 * que "nada acontecia".
 *
 * @param string $reason Mensagem amigável a mostrar via alert().
 */
function rmbz_splits_frontend_emit_disabled_stub( $reason ) {
    $reason_js = wp_json_encode( $reason );
    ?>
    <script>
    if (typeof window.rmbzOpenSplitsModal !== 'function') {
        window.rmbzOpenSplitsModal = function() {
            alert(<?php echo $reason_js; ?>);
        };
    }
    </script>
    <?php
}


/**
 * Renderiza o markup da modal e estilos (chamado no template
 * de single-view só quando o artista é owner).
 *
 * [1.5.117] Mesmo quando NÃO renderiza, emite um pequeno bloco de JS
 * que define `window.rmbzOpenSplitsModal` para mostrar uma mensagem
 * clara se o utilizador (ou outro código) acabar por chamar a função.
 * Também emite um comentário HTML diagnóstico explicando porquê.
 */
function rmbz_splits_frontend_render_modal( $release ) {
    if ( ! $release || empty($release->id) ) {
        echo "\n<!-- [1MZ Splits] Modal não renderizada: \$release inválido ou sem ID -->\n";
        rmbz_splits_frontend_emit_disabled_stub('Não foi possível identificar a release. Recarrega a página.');
        return;
    }
    if ( ! rmbz_splits_user_owns_release( $release->id ) ) {
        echo "\n<!-- [1MZ Splits] Modal não renderizada: utilizador não é owner da release {$release->id} -->\n";
        rmbz_splits_frontend_emit_disabled_stub('Apenas o artista dono da release pode configurar os splits.');
        return;
    }

    $tracks = rmbz_splits_get_release_tracks_with_splits( $release->id );
    $roles  = function_exists('rmbz_track_collaborator_roles')
        ? rmbz_track_collaborator_roles()
        : [ 'feature' => 'Featuring' ];
    $nonce  = wp_create_nonce( 'rmbz_splits_frontend_' . $release->id );

    // [1.5.120] Detectar fase actual da release.
    $phase = function_exists('rmbz_splits_get_release_phase')
        ? rmbz_splits_get_release_phase($release->id) : 'phase1';
    $can_edit_directly = function_exists('rmbz_splits_can_edit_directly')
        ? rmbz_splits_can_edit_directly($release->id) : true;

    // Rate-limit info para fase 1 (informativo no banner)
    $rate_info = null;
    if ( $phase === 'phase1' && function_exists('rmbz_splits_phase1_rate_check') ) {
        $rate_info = rmbz_splits_phase1_rate_check( $release->id );
    }
    ?>
    <!-- [1MZ Splits 1.5.120] Modal renderizada — fase: <?php echo esc_html($phase); ?> -->
    <div id="rmbz-splits-modal" class="rmbz-splits-fe-modal" aria-hidden="true">
        <div class="rmbz-splits-fe-overlay" data-close="1"></div>
        <div class="rmbz-splits-fe-box" role="dialog" aria-labelledby="rmbz-splits-fe-title">
            <div class="rmbz-splits-fe-header">
                <div>
                    <h3 id="rmbz-splits-fe-title">
                        <?php if ( $phase === 'phase3' ): ?>
                            🔒 Splits (alteração restrita)
                        <?php else: ?>
                            🤝 Configurar Splits
                        <?php endif; ?>
                    </h3>
                    <p class="rmbz-splits-fe-sub">
                        <?php echo esc_html( $release->title ?? '(sem título)' ); ?>
                    </p>
                </div>
                <button type="button" class="rmbz-splits-fe-close" data-close="1" aria-label="Fechar">×</button>
            </div>

            <div class="rmbz-splits-fe-body">
                <?php if ( empty($tracks) ): ?>
                    <p class="rmbz-splits-fe-empty">Esta release ainda não tem faixas.</p>
                <?php else: ?>
                    <?php // [1.5.120] Banner de fase ?>
                    <?php if ( $phase === 'phase3' ): ?>
                        <div class="rmbz-splits-fe-phase rmbz-splits-fe-phase--locked">
                            🔒 <strong>Esta release já gerou royalties.</strong>
                            Para proteger os colaboradores que já receberam ou têm dinheiro retido,
                            alterações directas estão bloqueadas. Podes <strong>pedir alteração</strong>
                            ao admin — ele vai avaliar caso a caso e decidir o que fazer com os
                            valores já alocados.
                        </div>
                    <?php elseif ( $phase === 'phase2' ): ?>
                        <div class="rmbz-splits-fe-phase rmbz-splits-fe-phase--warn">
                            ⚠ <strong>Esta release já está nas lojas.</strong>
                            Ainda não chegaram royalties, por isso podes editar livremente — mas
                            mudanças agora vão notificar colaboradores actuais e novos. Confirma
                            antes de guardar.
                        </div>
                    <?php elseif ( $phase === 'phase1' && $rate_info && $rate_info['count'] > 0 ): ?>
                        <div class="rmbz-splits-fe-phase rmbz-splits-fe-phase--info">
                            ℹ Já fizeste <strong><?php echo (int) $rate_info['count']; ?> de <?php echo (int) $rate_info['limit']; ?></strong>
                            alterações de splits desta release nos últimos 30 dias.
                        </div>
                    <?php endif; ?>

                    <p class="rmbz-splits-fe-intro">
                        Define como os royalties de cada faixa são divididos entre colaboradores.
                        A soma de todas as percentagens tem de ser <strong>100%</strong> (o teu próprio
                        share entra como "Artista principal"). Os colaboradores recebem notificação
                        e o dinheiro fica retido para eles até se registarem na 1MZ com o número
                        indicado.
                    </p>

                    <?php foreach ( $tracks as $t ):
                        $total_pct = 0.0;
                        foreach ( (array) $t->splits as $s ) $total_pct += (float) $s->percentage;
                        $is_balanced = ( abs($total_pct - 100) < 0.01 );
                        $has_splits  = ! empty($t->splits);
                    ?>
                        <div class="rmbz-splits-fe-track" data-track-id="<?php echo (int) $t->id; ?>">
                            <div class="rmbz-splits-fe-track-head">
                                <div class="rmbz-splits-fe-track-title-wrap">
                                    <strong><?php echo esc_html( $t->track_title ?: '(sem título)' ); ?></strong>
                                    <?php if ( ! empty($t->isrc_code) ): ?>
                                        <code class="rmbz-splits-fe-isrc"><?php echo esc_html($t->isrc_code); ?></code>
                                    <?php endif; ?>
                                </div>
                                <div>
                                    <?php if ( ! $has_splits ): ?>
                                        <span class="rmbz-splits-fe-status none">100% para ti</span>
                                    <?php elseif ( $is_balanced ): ?>
                                        <span class="rmbz-splits-fe-status ok">
                                            ✓ <?php echo count($t->splits); ?> colaborador<?php echo count($t->splits) === 1 ? '' : 'es'; ?>
                                        </span>
                                    <?php else: ?>
                                        <span class="rmbz-splits-fe-status warn">
                                            ⚠ Soma <?php echo number_format($total_pct, 2); ?>%
                                        </span>
                                    <?php endif; ?>
                                </div>
                            </div>

                            <?php if ( $has_splits ): ?>
                                <table class="rmbz-splits-fe-table">
                                    <thead>
                                        <tr>
                                            <th>Nome</th>
                                            <th>Telemóvel</th>
                                            <th>Função</th>
                                            <th style="text-align:right;">%</th>
                                            <th>Estado</th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        <?php foreach ( $t->splits as $s ): ?>
                                            <tr>
                                                <td><?php echo esc_html($s->collaborator_name); ?></td>
                                                <td>
                                                    <?php if ( ! empty($s->collaborator_telemovel) ): ?>
                                                        <code><?php echo esc_html($s->collaborator_telemovel); ?></code>
                                                    <?php else: ?>
                                                        <span class="muted">—</span>
                                                    <?php endif; ?>
                                                </td>
                                                <td><?php echo esc_html( $roles[$s->role] ?? $s->role ); ?></td>
                                                <td style="text-align:right;"><?php echo number_format((float) $s->percentage, 2); ?>%</td>
                                                <td>
                                                    <?php
                                                    $status_label = [
                                                        'pending'  => '⏳ A aguardar',
                                                        'accepted' => '✓ Aceite',
                                                        'rejected' => '✗ Rejeitado',
                                                        'external_hold' => '🔒 Retido (não registado)',
                                                    ];
                                                    echo esc_html( $status_label[$s->invite_status] ?? $s->invite_status );
                                                    ?>
                                                </td>
                                            </tr>
                                        <?php endforeach; ?>
                                    </tbody>
                                </table>
                            <?php endif; ?>

                            <?php // [1.5.120] Botão muda consoante fase ?>
                            <?php if ( $can_edit_directly ): ?>
                                <button type="button"
                                        class="rmbz-splits-fe-edit-btn"
                                        data-track-id="<?php echo (int) $t->id; ?>">
                                    ✏️ <?php echo $has_splits ? 'Editar splits' : 'Adicionar splits'; ?>
                                </button>
                            <?php else: ?>
                                <button type="button"
                                        class="rmbz-splits-fe-edit-btn rmbz-splits-fe-request-btn"
                                        data-track-id="<?php echo (int) $t->id; ?>">
                                    📩 Pedir alteração ao admin
                                </button>
                            <?php endif; ?>

                            <div class="rmbz-splits-fe-editor" hidden>
                                <div class="rmbz-splits-fe-editor-rows"></div>
                                <div class="rmbz-splits-fe-editor-actions">
                                    <button type="button" class="rmbz-splits-fe-add-row">+ Adicionar colaborador</button>
                                    <span class="rmbz-splits-fe-sum">Soma: <span class="rmbz-splits-fe-sum-val">0</span>%</span>
                                </div>
                                <p class="rmbz-splits-fe-hint">
                                    💡 O sistema preenche automaticamente uma linha "Tu próprio" com
                                    a percentagem que sobra (100% − soma dos colaboradores).
                                </p>

                                <?php // [1.5.120] Em Fase 3, pedir razão obrigatória antes de submeter ?>
                                <?php if ( ! $can_edit_directly ): ?>
                                    <div class="rmbz-splits-fe-reason-wrap">
                                        <label class="rmbz-splits-fe-reason-label">
                                            Razão da alteração <em>(mínimo 10 caracteres, será lida pelo admin)</em>:
                                        </label>
                                        <textarea class="rmbz-splits-fe-reason"
                                                  data-track-id="<?php echo (int) $t->id; ?>"
                                                  rows="3"
                                                  placeholder="Ex: O J.U deixou o projecto e vou substituir por outro colaborador. Aceito devolver as holdings já alocadas."></textarea>
                                    </div>
                                <?php endif; ?>

                                <?php // [1.5.120] Em Fase 2, pedir confirmação dupla ?>
                                <?php if ( $phase === 'phase2' ): ?>
                                    <div class="rmbz-splits-fe-confirm-wrap">
                                        <label>
                                            <input type="checkbox" class="rmbz-splits-fe-confirm-cb" data-track-id="<?php echo (int) $t->id; ?>">
                                            Confirmo que percebo que esta release já está nas lojas e quero mesmo alterar os splits.
                                        </label>
                                    </div>
                                <?php endif; ?>

                                <div class="rmbz-splits-fe-editor-buttons">
                                    <button type="button" class="rmbz-splits-fe-cancel">Cancelar</button>
                                    <?php if ( $can_edit_directly ): ?>
                                        <button type="button" class="rmbz-splits-fe-save"
                                                data-track-id="<?php echo (int) $t->id; ?>"
                                                data-phase="<?php echo esc_attr($phase); ?>">
                                            💾 Guardar
                                        </button>
                                    <?php else: ?>
                                        <button type="button" class="rmbz-splits-fe-request"
                                                data-track-id="<?php echo (int) $t->id; ?>">
                                            📩 Submeter pedido
                                        </button>
                                    <?php endif; ?>
                                </div>
                            </div>
                        </div>
                    <?php endforeach; ?>
                <?php endif; ?>
            </div>
        </div>
    </div>

    <script>
    /* [1.5.117] Definir rmbzOpenSplitsModal IMEDIATAMENTE no escopo global,
       ANTES do IIFE. Assim, mesmo que algum erro de JS (de outro script da
       página ou do próprio IIFE) interrompa a definição original dentro do
       IIFE, a função ainda existe globalmente e procura o modal no DOM no
       momento do clique. Antes da 1.5.117, a função era definida só dentro
       do IIFE — se este abortasse, o botão dava ReferenceError silencioso. */
    if (typeof window.rmbzOpenSplitsModal !== 'function') {
        window.rmbzOpenSplitsModal = function() {
            var m = document.getElementById('rmbz-splits-modal');
            if (!m) {
                console.error('[1MZ Splits] Modal #rmbz-splits-modal não encontrada no DOM. ' +
                    'Possível causa: render_modal não foi chamado (não és owner da release?) ' +
                    'ou houve erro de PHP a renderizar o markup.');
                alert('Não foi possível abrir o configurador de splits.\n\n' +
                    'Causa provável: a janela ainda não foi renderizada nesta página. ' +
                    'Tenta recarregar a página (F5). Se o problema persistir, contacta o suporte.');
                return;
            }
            m.classList.add('is-open');
            m.setAttribute('aria-hidden', 'false');
            document.body.style.overflow = 'hidden';
        };
    }
    (function(){
        var modal = document.getElementById('rmbz-splits-modal');
        if (!modal) {
            console.warn('[1MZ Splits] IIFE: modal não encontrado no DOM ainda.');
            return;
        }
        var nonce = <?php echo wp_json_encode($nonce); ?>;
        var releaseId = <?php echo (int) $release->id; ?>;
        var roles = <?php echo wp_json_encode($roles); ?>;
        var ownerTel = <?php echo wp_json_encode( function_exists('rmbz_get_current_user_telemovel') ? rmbz_get_current_user_telemovel() : '' ); ?>;
        var ajaxUrl = <?php echo wp_json_encode( admin_url('admin-ajax.php') ); ?>;

        // Estado por faixa: lista de splits em edição
        var editorState = {};

        // ─── Open / close modal ───
        // [1.5.117] Sobrescreve a definição global com a versão que tem closure
        // sobre o `modal` capturado (ligeiramente mais rápida — evita lookup).
        // [1.5.118] Move o modal directamente para <body> na primeira abertura.
        // Isto escapa qualquer ancestor com `transform`, `filter`, `perspective`
        // ou `contain` que contém o modal — a regra CSS é que `position:fixed`
        // se torna relativo a esses ancestors em vez de ao viewport. Sintoma
        // reportado pelo utilizador: "no PC o efeito não cobre toda a tela".
        var modalReparented = false;
        function reparentModalToBody() {
            if (modalReparented) return;
            if (modal.parentNode !== document.body) {
                document.body.appendChild(modal);
            }
            modalReparented = true;
        }
        window.rmbzOpenSplitsModal = function() {
            reparentModalToBody();
            modal.classList.add('is-open');
            modal.setAttribute('aria-hidden', 'false');
            document.body.style.overflow = 'hidden';
        };
        function closeModal() {
            modal.classList.remove('is-open');
            modal.setAttribute('aria-hidden', 'true');
            document.body.style.overflow = '';
        }
        modal.addEventListener('click', function(e){
            if (e.target.getAttribute('data-close') === '1') closeModal();
        });
        document.addEventListener('keydown', function(e){
            // [1.5.119] Antes era: if (e.key === 'Escape' && modal.classList.contains('is-open'))
            // mas WordPress estava a escapar o && para &#038;&#038; no output, partindo o parser
            // JS com SyntaxError. Reescrevemos com if aninhado — sem &&, sem problema.
            if (e.key !== 'Escape') return;
            if (!modal.classList.contains('is-open')) return;
            closeModal();
        });

        // ─── Editor logic ───
        function buildRoleOptions(selected) {
            var html = '';
            for (var k in roles) {
                if (Object.prototype.hasOwnProperty.call(roles, k)) {
                    html += '<option value="' + k + '"' + (k === selected ? ' selected' : '') + '>' + escapeHtml(roles[k]) + '</option>';
                }
            }
            return html;
        }
        function escapeHtml(s) {
            return String(s == null ? '' : s).replace(/[&<>"']/g, function(c){
                return ({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'})[c];
            });
        }

        function renderEditorRows(trackEl) {
            var trackId = trackEl.getAttribute('data-track-id');
            var rows = editorState[trackId] || [];
            var rowsContainer = trackEl.querySelector('.rmbz-splits-fe-editor-rows');
            rowsContainer.innerHTML = '';
            rows.forEach(function(row, idx){
                var div = document.createElement('div');
                div.className = 'rmbz-splits-fe-row';
                div.innerHTML =
                    '<input type="text" placeholder="Nome do colaborador" class="rmbz-splits-fe-input-name" value="' + escapeHtml(row.name) + '">' +
                    '<input type="text" placeholder="258XXXXXXXXX" class="rmbz-splits-fe-input-tel" value="' + escapeHtml(row.telemovel) + '">' +
                    '<select class="rmbz-splits-fe-input-role">' + buildRoleOptions(row.role || 'feature') + '</select>' +
                    '<input type="number" min="0" max="100" step="0.01" placeholder="%" class="rmbz-splits-fe-input-pct" value="' + escapeHtml(row.percentage) + '">' +
                    '<button type="button" class="rmbz-splits-fe-remove" title="Remover">×</button>';

                div.querySelector('.rmbz-splits-fe-input-name').addEventListener('input', function(e){
                    rows[idx].name = e.target.value;
                });
                div.querySelector('.rmbz-splits-fe-input-tel').addEventListener('input', function(e){
                    rows[idx].telemovel = e.target.value;
                });
                div.querySelector('.rmbz-splits-fe-input-role').addEventListener('change', function(e){
                    rows[idx].role = e.target.value;
                });
                div.querySelector('.rmbz-splits-fe-input-pct').addEventListener('input', function(e){
                    rows[idx].percentage = e.target.value;
                    updateSum(trackEl);
                });
                div.querySelector('.rmbz-splits-fe-remove').addEventListener('click', function(){
                    rows.splice(idx, 1);
                    renderEditorRows(trackEl);
                    updateSum(trackEl);
                });

                rowsContainer.appendChild(div);
            });
            updateSum(trackEl);
        }
        function updateSum(trackEl) {
            var trackId = trackEl.getAttribute('data-track-id');
            var rows = editorState[trackId] || [];
            var sum = 0;
            rows.forEach(function(r){ sum += parseFloat(r.percentage || 0) || 0; });
            var sumEl = trackEl.querySelector('.rmbz-splits-fe-sum-val');
            if (sumEl) {
                sumEl.textContent = sum.toFixed(2);
                sumEl.style.color = sum > 100 ? '#c0392b' : (sum === 0 ? '#888' : '#27ae60');
            }
        }

        // ─── Bind buttons ───
        document.querySelectorAll('.rmbz-splits-fe-edit-btn').forEach(function(btn){
            btn.addEventListener('click', function(){
                var trackEl = btn.closest('.rmbz-splits-fe-track');
                var trackId = btn.getAttribute('data-track-id');
                var editor = trackEl.querySelector('.rmbz-splits-fe-editor');

                // Inicializar editorState a partir da tabela visual (linhas existentes)
                if (!editorState[trackId]) {
                    var existing = [];
                    trackEl.querySelectorAll('.rmbz-splits-fe-table tbody tr').forEach(function(tr){
                        var tds = tr.querySelectorAll('td');
                        if (tds.length >= 4) {
                            var name = tds[0].textContent.trim();
                            var telCode = tds[1].querySelector('code');
                            var tel = telCode ? telCode.textContent.trim() : '';
                            // Role tem texto traduzido — guardamos slug a partir de roles invertido
                            var roleLabel = tds[2].textContent.trim();
                            var roleSlug = 'feature';
                            for (var k in roles) {
                                if (roles[k] === roleLabel) { roleSlug = k; break; }
                            }
                            var pctStr = tds[3].textContent.replace('%','').trim();
                            existing.push({
                                name: name,
                                telemovel: tel,
                                role: roleSlug,
                                percentage: pctStr,
                            });
                        }
                    });
                    editorState[trackId] = existing;
                }

                renderEditorRows(trackEl);
                editor.hidden = false;
                btn.style.display = 'none';
            });
        });

        document.querySelectorAll('.rmbz-splits-fe-add-row').forEach(function(btn){
            btn.addEventListener('click', function(){
                var trackEl = btn.closest('.rmbz-splits-fe-track');
                var trackId = trackEl.getAttribute('data-track-id');
                if (!editorState[trackId]) editorState[trackId] = [];
                editorState[trackId].push({ name: '', telemovel: '', role: 'feature', percentage: '' });
                renderEditorRows(trackEl);
            });
        });

        document.querySelectorAll('.rmbz-splits-fe-cancel').forEach(function(btn){
            btn.addEventListener('click', function(){
                var trackEl = btn.closest('.rmbz-splits-fe-track');
                var trackId = trackEl.getAttribute('data-track-id');
                delete editorState[trackId];
                trackEl.querySelector('.rmbz-splits-fe-editor').hidden = true;
                trackEl.querySelector('.rmbz-splits-fe-edit-btn').style.display = '';
            });
        });

        document.querySelectorAll('.rmbz-splits-fe-save').forEach(function(btn){
            btn.addEventListener('click', function(){
                var trackEl = btn.closest('.rmbz-splits-fe-track');
                var trackId = btn.getAttribute('data-track-id');
                // [1.5.119] Antes: r.name.trim() !== '' && parseFloat(r.percentage) > 0
                // WordPress escapa && → &#038;&#038; e parte o JS. Usamos função
                // explícita em vez de operador && para evitar o problema.
                var rows = (editorState[trackId] || []).filter(function(r){
                    var hasName = (r.name || '').trim() !== '';
                    if (!hasName) return false;
                    var hasPct = parseFloat(r.percentage) > 0;
                    return hasPct;
                });

                // Validação cliente: soma <= 100
                var sum = 0;
                rows.forEach(function(r){ sum += parseFloat(r.percentage || 0) || 0; });
                if (sum > 100.01) {
                    alert('A soma das percentagens é ' + sum.toFixed(2) + '% — não pode ultrapassar 100%.');
                    return;
                }
                // Validação cliente: telemóvel obrigatório
                for (var i = 0; i < rows.length; i++) {
                    if ((rows[i].telemovel || '').trim() === '') {
                        alert('Falta indicar o telemóvel de "' + rows[i].name + '".');
                        return;
                    }
                }

                // [1.5.120] Fase 2: exige confirmação dupla via checkbox.
                // Reescrito sem `&&` — ver nota 1.5.119 sobre WordPress escapar `&`.
                var phase = btn.getAttribute('data-phase') || '';
                if (phase === 'phase2') {
                    var cb = trackEl.querySelector('.rmbz-splits-fe-confirm-cb');
                    var needsConfirm = false;
                    if (cb) { if (!cb.checked) { needsConfirm = true; } }
                    if (needsConfirm) {
                        alert('Esta release já está nas lojas. Confirma a checkbox antes de guardar.');
                        return;
                    }
                }

                btn.disabled = true;
                btn.textContent = 'A guardar...';

                var formData = new FormData();
                formData.append('action', 'rmbz_splits_frontend_save');
                formData.append('nonce', nonce);
                formData.append('release_id', releaseId);
                formData.append('track_id', trackId);
                formData.append('splits', JSON.stringify(rows));

                fetch(ajaxUrl, { method: 'POST', body: formData, credentials: 'same-origin' })
                    .then(function(r){ return r.json(); })
                    .then(function(res){
                        // [1.5.119] Reescrito sem && — ver comentário acima.
                        var ok = false;
                        if (res) { if (res.success) { ok = true; } }
                        if (ok) {
                            // Recarregar a página para mostrar estado actualizado
                            location.reload();
                        } else {
                            var msg = 'falha desconhecida';
                            if (res) { if (res.data) { msg = res.data; } }
                            alert('Erro: ' + msg);
                            btn.disabled = false;
                            btn.textContent = '💾 Guardar';
                        }
                    })
                    .catch(function(err){
                        alert('Erro de rede: ' + err.message);
                        btn.disabled = false;
                        btn.textContent = '💾 Guardar';
                    });
            });
        });

        // [1.5.120] Handler do botão "📩 Submeter pedido" (Fase 3).
        // Submete um pedido de alteração para o admin avaliar em vez de
        // guardar directamente. Reusa o mesmo editor de splits.
        document.querySelectorAll('.rmbz-splits-fe-request').forEach(function(btn){
            btn.addEventListener('click', function(){
                var trackEl = btn.closest('.rmbz-splits-fe-track');
                var trackId = btn.getAttribute('data-track-id');

                // Recolhe a razão obrigatória.
                var reasonEl = trackEl.querySelector('.rmbz-splits-fe-reason');
                var reason = reasonEl ? reasonEl.value.trim() : '';
                if (reason.length < 10) {
                    alert('Descreve a razão da alteração (mínimo 10 caracteres). O admin precisa de saber porquê.');
                    if (reasonEl) reasonEl.focus();
                    return;
                }

                // Recolhe splits propostos (mesma lógica do save normal)
                var rows = (editorState[trackId] || []).filter(function(r){
                    var hasName = (r.name || '').trim() !== '';
                    if (!hasName) return false;
                    var hasPct = parseFloat(r.percentage) > 0;
                    return hasPct;
                });

                var sum = 0;
                rows.forEach(function(r){ sum += parseFloat(r.percentage || 0) || 0; });
                if (sum > 100.01) {
                    alert('A soma das percentagens é ' + sum.toFixed(2) + '% — não pode ultrapassar 100%.');
                    return;
                }

                for (var j = 0; j < rows.length; j++) {
                    if ((rows[j].telemovel || '').trim() === '') {
                        alert('Falta indicar o telemóvel de "' + rows[j].name + '".');
                        return;
                    }
                }

                btn.disabled = true;
                btn.textContent = 'A enviar pedido...';

                var formData = new FormData();
                formData.append('action', 'rmbz_splits_request_change');
                formData.append('nonce', nonce);
                formData.append('release_id', releaseId);
                formData.append('track_id', trackId);
                formData.append('reason', reason);
                formData.append('proposed_splits', JSON.stringify(rows));

                fetch(ajaxUrl, { method: 'POST', body: formData, credentials: 'same-origin' })
                    .then(function(r){ return r.json(); })
                    .then(function(res){
                        var ok = false;
                        if (res) { if (res.success) { ok = true; } }
                        if (ok) {
                            var reqId = '';
                            if (res.data) { if (res.data.request_id) { reqId = res.data.request_id; } }
                            alert('✅ Pedido enviado! O admin vai avaliar e contactar-te. ID do pedido: #' + reqId);
                            location.reload();
                        } else {
                            var msg = 'falha desconhecida';
                            if (res) { if (res.data) { msg = res.data; } }
                            alert('Erro: ' + msg);
                            btn.disabled = false;
                            btn.textContent = '📩 Submeter pedido';
                        }
                    })
                    .catch(function(err){
                        alert('Erro de rede: ' + err.message);
                        btn.disabled = false;
                        btn.textContent = '📩 Submeter pedido';
                    });
            });
        });
    })();
    </script>

    <style>
        /* ============================================================
           [1MZ Splits 1.5.118] Modal de configuração de splits
           Mudanças vs 1.5.117:
             - Overlay agora é `position:fixed` (era `absolute`).
             - Body do modal usa flex column estável; track-head empilha
               em mobile e organiza-se em 3 zonas (título / ISRC / status).
             - Botão "Adicionar/Editar splits" agora preenche e tem peso
               visual (era um link discreto).
             - Modal é movido para <body> via JS no abrir, para escapar
               de ancestors com `transform/filter/contain` que quebram
               o `position:fixed` (problema reportado: overlay não cobre
               o ecrã todo no PC).
           ============================================================ */
        .rmbz-splits-fe-modal {
            display:none; position:fixed; inset:0;
            z-index:999999;
        }
        .rmbz-splits-fe-modal.is-open { display:block; }
        .rmbz-splits-fe-overlay {
            /* [1.5.118] FIXED em vez de ABSOLUTE — garante cobertura total
               do viewport mesmo se o modal estiver dentro de um container
               com transform/filter (que quebra position:fixed dos filhos). */
            position:fixed; inset:0;
            background:rgba(0,0,0,0.72);
            backdrop-filter:blur(3px);
            -webkit-backdrop-filter:blur(3px);
            cursor:pointer;
        }
        .rmbz-splits-fe-box {
            position:relative;
            max-width:780px; width:calc(100% - 32px);
            margin:4vh auto;
            max-height:90vh; overflow:hidden;
            background:#1a1a1a; color:#eee;
            border-radius:12px;
            border:1px solid #333;
            box-shadow:0 20px 60px rgba(0,0,0,0.5);
            display:flex; flex-direction:column;
            animation:rmbzFeModalIn 0.2s ease-out;
        }
        @keyframes rmbzFeModalIn {
            from { opacity:0; transform:translateY(-12px); }
            to { opacity:1; transform:translateY(0); }
        }
        .rmbz-splits-fe-header {
            display:flex; align-items:flex-start; justify-content:space-between;
            gap:12px;
            padding:16px 20px;
            background:linear-gradient(135deg, #f0b90b 0%, #d4a30a 100%);
            color:#1a1a1a;
            flex-shrink:0;
        }
        .rmbz-splits-fe-header h3 { margin:0 0 4px; font-size:18px; font-weight:600; line-height:1.25; }
        .rmbz-splits-fe-sub { margin:0; font-size:13px; opacity:0.85; line-height:1.35; }
        .rmbz-splits-fe-close {
            background:transparent; border:0; cursor:pointer;
            font-size:28px; line-height:1; color:#1a1a1a;
            padding:0 6px; flex-shrink:0;
        }
        .rmbz-splits-fe-body {
            padding:20px; overflow-y:auto; flex:1;
        }
        .rmbz-splits-fe-intro {
            background:#222; border-left:3px solid #f0b90b;
            padding:12px 14px; border-radius:6px;
            font-size:13px; line-height:1.55; color:#ccc;
            margin:0 0 18px;
        }
        .rmbz-splits-fe-intro strong { color:#f0b90b; }
        .rmbz-splits-fe-empty {
            color:#888; text-align:center; padding:40px 0;
        }
        .rmbz-splits-fe-track {
            background:#222;
            border:1px solid #333;
            border-radius:8px;
            padding:16px;
            margin-bottom:14px;
        }
        /* [1.5.118] Header da track agora é grid responsivo:
           - Desktop: título à esquerda, status à direita.
           - Mobile: empilha (título cima, status baixo). */
        .rmbz-splits-fe-track-head {
            display:flex; flex-wrap:wrap;
            justify-content:space-between; align-items:flex-start;
            gap:10px;
            margin-bottom:12px;
        }
        .rmbz-splits-fe-track-title-wrap {
            flex:1 1 200px; min-width:0;
            display:flex; flex-direction:column; gap:6px;
        }
        .rmbz-splits-fe-track-title-wrap strong {
            font-size:15px; line-height:1.3; color:#fff;
            word-break:break-word;
        }
        .rmbz-splits-fe-isrc {
            font-size:11px; color:#888;
            background:#0a0a0a; padding:3px 8px; border-radius:3px;
            display:inline-block; align-self:flex-start;
            font-family:monospace;
        }
        .rmbz-splits-fe-status {
            font-size:12px; padding:5px 12px; border-radius:14px;
            white-space:nowrap; flex-shrink:0;
            line-height:1.3;
        }
        .rmbz-splits-fe-status.none { background:#2a2a2a; color:#bbb; }
        .rmbz-splits-fe-status.ok   { background:#0f4d2c; color:#7cf0a6; }
        .rmbz-splits-fe-status.warn { background:#5a3a0a; color:#f5c97a; }
        .rmbz-splits-fe-table {
            width:100%; border-collapse:collapse;
            font-size:13px; margin:8px 0;
        }
        .rmbz-splits-fe-table th, .rmbz-splits-fe-table td {
            padding:6px 8px; border-bottom:1px solid #2a2a2a;
            text-align:left;
        }
        .rmbz-splits-fe-table th { color:#888; font-weight:500; font-size:11px; text-transform:uppercase; }
        .rmbz-splits-fe-table td code { background:#0a0a0a; padding:2px 5px; border-radius:3px; color:#f0b90b; font-size:11px; }
        /* [1.5.118] Botão "Adicionar/Editar splits" com mais peso visual.
           Antes era um link tímido — agora é um CTA claro. */
        .rmbz-splits-fe-edit-btn {
            background:#f0b90b; color:#1a1a1a;
            border:0; padding:9px 18px;
            border-radius:6px; cursor:pointer;
            font-size:13px; font-weight:600;
            transition:all 0.15s;
            margin-top:4px;
        }
        .rmbz-splits-fe-edit-btn:hover {
            background:#d4a30a;
            transform:translateY(-1px);
            box-shadow:0 4px 10px rgba(240,185,11,0.25);
        }
        .rmbz-splits-fe-editor {
            margin-top:14px; padding-top:14px;
            border-top:1px dashed #333;
        }
        .rmbz-splits-fe-row {
            display:grid;
            grid-template-columns: 1.5fr 1.2fr 1fr 70px 30px;
            gap:8px; margin-bottom:8px; align-items:center;
        }
        .rmbz-splits-fe-row input, .rmbz-splits-fe-row select {
            background:#0a0a0a; color:#eee;
            border:1px solid #333; padding:6px 8px;
            border-radius:4px; font-size:13px;
            width:100%; box-sizing:border-box;
        }
        .rmbz-splits-fe-row input:focus, .rmbz-splits-fe-row select:focus {
            border-color:#f0b90b; outline:none;
        }
        .rmbz-splits-fe-remove {
            background:#3a1a1a; color:#f5a5a5;
            border:1px solid #5a2a2a; cursor:pointer;
            font-size:16px; line-height:1; padding:2px 0;
            border-radius:4px;
        }
        .rmbz-splits-fe-remove:hover { background:#5a2a2a; }
        .rmbz-splits-fe-editor-actions {
            display:flex; justify-content:space-between; align-items:center;
            margin:10px 0;
        }
        .rmbz-splits-fe-add-row {
            background:transparent; color:#888;
            border:1px dashed #444; padding:5px 12px;
            border-radius:4px; cursor:pointer; font-size:12px;
        }
        .rmbz-splits-fe-add-row:hover { color:#f0b90b; border-color:#f0b90b; }
        .rmbz-splits-fe-sum { font-size:13px; color:#888; }
        .rmbz-splits-fe-hint {
            font-size:11px; color:#888; margin:8px 0;
            font-style:italic;
        }
        .rmbz-splits-fe-editor-buttons {
            display:flex; gap:8px; justify-content:flex-end;
            margin-top:12px;
        }
        .rmbz-splits-fe-cancel {
            background:transparent; color:#888;
            border:1px solid #444; padding:7px 14px;
            border-radius:5px; cursor:pointer; font-size:13px;
        }
        .rmbz-splits-fe-save {
            background:#f0b90b; color:#1a1a1a;
            border:0; padding:7px 18px;
            border-radius:5px; cursor:pointer;
            font-size:13px; font-weight:600;
        }
        .rmbz-splits-fe-save:disabled { opacity:0.5; cursor:not-allowed; }
        .rmbz-splits-fe-save:hover:not(:disabled) { background:#d4a30a; }
        .muted { color:#888; }

        /* ============================================================
           [1.5.118] Mobile responsivo (≤640px).
           - Modal usa quase toda a largura.
           - Editor de linhas empilha em duas linhas (era grid de 5 cols).
           - Tabela de splits faz scroll horizontal se for muito larga.
           ============================================================ */
        @media (max-width: 640px) {
            .rmbz-splits-fe-box {
                width:calc(100% - 16px);
                margin:2vh auto;
                max-height:96vh;
                border-radius:10px;
            }
            .rmbz-splits-fe-header { padding:14px 16px; }
            .rmbz-splits-fe-header h3 { font-size:16px; }
            .rmbz-splits-fe-sub { font-size:12px; }
            .rmbz-splits-fe-body { padding:14px; }
            .rmbz-splits-fe-track { padding:14px; }

            /* Editor: 2 colunas em vez de 5 — nome+role na 1ª linha,
               telemovel+pct+remove na 2ª. */
            .rmbz-splits-fe-row {
                grid-template-columns: 1fr 1fr;
                grid-template-areas:
                    "name name"
                    "tel role"
                    "pct remove";
                gap:6px;
            }
            .rmbz-splits-fe-row .rmbz-splits-fe-input-name { grid-area: name; }
            .rmbz-splits-fe-row .rmbz-splits-fe-input-tel  { grid-area: tel; }
            .rmbz-splits-fe-row .rmbz-splits-fe-input-role { grid-area: role; }
            .rmbz-splits-fe-row .rmbz-splits-fe-input-pct  { grid-area: pct; }
            .rmbz-splits-fe-row .rmbz-splits-fe-remove     { grid-area: remove; }

            /* Tabela: scroll horizontal em ecrãs estreitos */
            .rmbz-splits-fe-table {
                display:block; overflow-x:auto;
                white-space:nowrap;
            }
        }

        /* ============================================================
           [1.5.120] Banners de fase, textarea de razão, checkbox de
           confirmação e botão de pedido. Os elementos só aparecem em
           fases específicas mas o CSS está sempre presente.
           ============================================================ */
        .rmbz-splits-fe-phase {
            padding:14px 16px;
            border-radius:8px;
            margin:0 0 16px;
            font-size:13px;
            line-height:1.55;
        }
        .rmbz-splits-fe-phase strong { display:inline; }
        .rmbz-splits-fe-phase--locked {
            background:rgba(192,57,43,0.12);
            border-left:4px solid #c0392b;
            color:#f5a5a5;
        }
        .rmbz-splits-fe-phase--locked strong { color:#ff8a8a; }
        .rmbz-splits-fe-phase--warn {
            background:rgba(240,185,11,0.10);
            border-left:4px solid #f0b90b;
            color:#f5c97a;
        }
        .rmbz-splits-fe-phase--warn strong { color:#ffd966; }
        .rmbz-splits-fe-phase--info {
            background:rgba(52,152,219,0.10);
            border-left:4px solid #3498db;
            color:#9cc9e8;
        }
        .rmbz-splits-fe-phase--info strong { color:#cfe6f5; }

        .rmbz-splits-fe-reason-wrap {
            margin:14px 0 10px;
        }
        .rmbz-splits-fe-reason-label {
            display:block; font-size:12px; color:#ccc;
            margin-bottom:6px;
        }
        .rmbz-splits-fe-reason-label em {
            color:#888; font-style:normal; font-size:11px;
        }
        .rmbz-splits-fe-reason {
            width:100%; box-sizing:border-box;
            background:#0a0a0a; color:#eee;
            border:1px solid #444; border-radius:5px;
            padding:8px 10px; font-size:13px;
            font-family:inherit; resize:vertical; min-height:60px;
        }
        .rmbz-splits-fe-reason:focus { border-color:#f0b90b; outline:none; }

        .rmbz-splits-fe-confirm-wrap {
            margin:12px 0;
            padding:10px 12px;
            background:rgba(240,185,11,0.08);
            border:1px solid rgba(240,185,11,0.3);
            border-radius:6px;
            font-size:12px;
            line-height:1.4;
            color:#ddd;
        }
        .rmbz-splits-fe-confirm-cb { margin-right:6px; }

        /* Botão "Pedir alteração" — visualmente diferente do edit normal */
        .rmbz-splits-fe-request-btn {
            background:#3498db !important;
            color:#fff !important;
        }
        .rmbz-splits-fe-request-btn:hover {
            background:#2980b9 !important;
            box-shadow:0 4px 10px rgba(52,152,219,0.25) !important;
        }
        .rmbz-splits-fe-request {
            background:#3498db; color:#fff;
            border:0; padding:7px 18px;
            border-radius:5px; cursor:pointer;
            font-size:13px; font-weight:600;
        }
        .rmbz-splits-fe-request:disabled { opacity:0.5; cursor:not-allowed; }
        .rmbz-splits-fe-request:hover:not(:disabled) { background:#2980b9; }
    </style>
    <?php
}


/**
 * AJAX: guardar splits de uma faixa.
 */
function rmbz_ajax_splits_frontend_save() {
    $release_id = isset($_POST['release_id']) ? (int) $_POST['release_id'] : 0;
    $track_id   = isset($_POST['track_id'])   ? (int) $_POST['track_id']   : 0;
    $nonce      = $_POST['nonce'] ?? '';

    if ( ! wp_verify_nonce($nonce, 'rmbz_splits_frontend_' . $release_id) ) {
        wp_send_json_error('Erro de segurança.', 403);
    }
    if ( $release_id <= 0 || $track_id <= 0 ) {
        wp_send_json_error('IDs inválidos.', 400);
    }
    if ( ! rmbz_splits_user_owns_release($release_id) ) {
        wp_send_json_error('Sem permissão para esta release.', 403);
    }

    // [1.5.120] BLOQUEIO POR FASE.
    // Edição direta só em fase 1 e 2. Fase 3 obriga a passar por
    // pedido de alteração (handler em distribution-splits-phases.php).
    if ( function_exists('rmbz_splits_can_edit_directly')
         && ! rmbz_splits_can_edit_directly($release_id) ) {
        wp_send_json_error(
            'Esta release já gerou royalties. Edição direta de splits está bloqueada — usa "Pedir alteração" para o admin avaliar.',
            403
        );
    }

    // [1.5.120] RATE LIMIT FASE 1.
    // Máximo 3 alterações por release nos últimos 30 dias. Anti-abuso.
    if ( function_exists('rmbz_splits_get_release_phase')
         && rmbz_splits_get_release_phase($release_id) === 'phase1' ) {
        $rate = rmbz_splits_phase1_rate_check( $release_id );
        if ( ! $rate['ok'] ) {
            wp_send_json_error( $rate['message'], 429 );
        }
    }

    global $wpdb;

    // Validar que a faixa pertence à release
    $track_belongs = (int) $wpdb->get_var( $wpdb->prepare(
        "SELECT COUNT(*) FROM {$wpdb->prefix}rmbz_distro_tracks
         WHERE id = %d AND release_id = %d",
        $track_id, $release_id
    ) );
    if ( ! $track_belongs ) {
        wp_send_json_error('Faixa não pertence a esta release.', 400);
    }

    // Decode JSON do payload
    $splits_raw = $_POST['splits'] ?? '[]';
    $splits = json_decode( wp_unslash($splits_raw), true );
    if ( ! is_array($splits) ) {
        wp_send_json_error('Formato de splits inválido.', 400);
    }

    // Sanitizar e validar cada linha
    $clean = [];
    $sum = 0.0;
    $owner_tel = function_exists('rmbz_get_current_user_telemovel') ? rmbz_get_current_user_telemovel() : '';
    foreach ( $splits as $s ) {
        $name = trim( sanitize_text_field( $s['name'] ?? '' ) );
        $tel  = trim( sanitize_text_field( $s['telemovel'] ?? '' ) );
        $role = sanitize_key( $s['role'] ?? 'feature' );
        $pct  = (float) ( $s['percentage'] ?? 0 );

        if ( empty($name) || $pct <= 0 ) continue;
        if ( $pct > 100 ) {
            wp_send_json_error('Percentagem inválida em "' . $name . '" (' . $pct . '%).', 400);
        }
        if ( empty($tel) ) {
            wp_send_json_error('Telemóvel obrigatório para "' . $name . '".', 400);
        }
        // Normalizar telemóvel se existir helper
        if ( function_exists('rmbz_splits_normalize_telemovel') ) {
            $normalized = rmbz_splits_normalize_telemovel($tel);
            if ( ! empty($normalized) ) $tel = $normalized;
        }
        // Não permitir auto-split (artista a si próprio — o resto fica
        // automaticamente como "para o owner")
        if ( ! empty($owner_tel) && $tel === $owner_tel ) {
            wp_send_json_error('Não precisas de criar split para ti próprio. O que sobrar dos 100% fica automaticamente teu.', 400);
        }

        $clean[] = [
            'name'      => $name,
            'telemovel' => $tel,
            'role'      => $role,
            'percentage' => round($pct, 2),
        ];
        $sum += $pct;
    }

    if ( $sum > 100.01 ) {
        wp_send_json_error('Soma das percentagens é ' . number_format($sum, 2) . '% — não pode ultrapassar 100%.', 400);
    }

    // Detectar mudanças de telemóvel — para evitar admin trocar destinatário
    // de holdings já alocadas (por enquanto deixamos passar mas avisamos)
    $t_splits = $wpdb->prefix . 'rmbz_track_splits';
    if ( $wpdb->get_var("SHOW TABLES LIKE '$t_splits'") !== $t_splits ) {
        wp_send_json_error('Tabela de splits não existe.', 500);
    }

    // Regravar (delete + insert) — segue padrão do track-editor
    $wpdb->delete( $t_splits, [ 'track_id' => $track_id ], [ '%d' ] );
    foreach ( $clean as $sp ) {
        $wpdb->insert( $t_splits, [
            'track_id'               => $track_id,
            'release_id'             => $release_id,
            'collaborator_name'      => $sp['name'],
            'collaborator_telemovel' => $sp['telemovel'],
            'role'                   => $sp['role'],
            'percentage'             => $sp['percentage'],
            'invite_status'          => 'pending',
        ], [ '%d', '%d', '%s', '%s', '%s', '%f', '%s' ] );
    }

    // Hook que trata classificação automática (registado vs externo)
    // e envio de notificações.
    do_action( 'rmbz_track_splits_saved', $track_id );

    // [1.5.120] Audit log da edição (necessário para rate-limit Fase 1).
    // O helper rmbz_splits_audit grava em rmbz_splits_audit; usamos action
    // 'frontend_save' para o rate-limit conseguir contar (LIKE 'frontend_save%').
    if ( function_exists('rmbz_splits_audit') ) {
        $phase = function_exists('rmbz_splits_get_release_phase')
            ? rmbz_splits_get_release_phase($release_id) : 'unknown';
        rmbz_splits_audit(
            'frontend_save_' . $phase,
            $track_id,
            $release_id,
            null,
            null,
            wp_json_encode( $clean ),
            'Edição direta via UI do artista'
        );
    }

    wp_send_json_success([
        'splits_count' => count($clean),
        'total_pct'    => $sum,
        'message'      => 'Splits guardados.',
    ]);
}
add_action('wp_ajax_rmbz_splits_frontend_save', 'rmbz_ajax_splits_frontend_save');
// [1.5.208] Sem nopriv, salvar splits no painel artista falhava para users
// com sessão telefone (sem conta WP).
add_action('wp_ajax_nopriv_rmbz_splits_frontend_save', 'rmbz_ajax_splits_frontend_save');
