<?php
/**
 * includes/notifications/notifications-events.php
 *
 * ============================================================================
 * AUTOMAÇÃO DE EVENTOS — listeners para criar notificações inline (1.5.184)
 * ============================================================================
 *
 * Liga eventos reais do plugin ao sistema de notificações inline (1.5.182):
 *
 *   EVENTO                          → BANNER GERADO
 *   ─────────────────────────────────────────────────────────────────
 *   release.returned                → DANGER  "X foi devolvido pela curadoria"
 *   release.live                    → SUCCESS "X está ao vivo nas lojas"
 *   release.rejected                → DANGER  "X foi rejeitado"
 *   somas.registration.approved     → SUCCESS "Registo SOMAS aprovado"
 *   somas.registration.rejected     → DANGER  "Registo SOMAS rejeitado"
 *   somas.registration.returned     → WARNING "Registo SOMAS precisa de correcção"
 *   somas.license.approved          → SUCCESS "Licença SOMAS aprovada"
 *   somas.license.rejected          → DANGER  "Licença SOMAS rejeitada"
 *   match_review.approved.group     → SUCCESS "Royalties atribuídos à sua faixa"
 *   withdrawal.approved             → SUCCESS "Pedido de levantamento aprovado"
 *   withdrawal.rejected             → DANGER  "Pedido de levantamento rejeitado"
 *
 * IDEMPOTÊNCIA:
 *   Cada listener usa dedup_key = "EVENT_TYPE:RESOURCE_ID" para garantir que
 *   o mesmo evento 2x não cria 2 notificações. Ex: "release_returned:42".
 *
 * RESILÊNCIA:
 *   Se rmbz_notify_create() não existir (módulo desligado), os listeners
 *   silenciosamente nada fazem.
 *
 * ============================================================================
 */

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


/* ============================================================================
 * 1. RELEASE LIFECYCLE
 * ============================================================================ */

/**
 * Listener: release foi devolvido pela curadoria.
 *
 * Hook: rmbz_distro_release_returned (definido em distribution-return-workflow.php:191)
 *
 * @param int   $release_id
 * @param array $problems_clean Lista de [code, label, note]
 * @param string $note Nota geral do admin
 */
function rmbz_notif_event_release_returned( $release_id, $problems_clean, $note ) {
    if ( ! function_exists('rmbz_notify_create') ) return;

    global $wpdb;
    $rel = $wpdb->get_row( $wpdb->prepare(
        "SELECT id, title, artist_telemovel
         FROM {$wpdb->prefix}rmbz_distro_releases
         WHERE id = %d",
        (int) $release_id
    ));
    if ( ! $rel || empty( $rel->artist_telemovel ) ) return;

    // Construir motivo legível
    $motivo_lines = [];
    foreach ( (array) $problems_clean as $p ) {
        $line = ( $p['label'] ?? $p['code'] ?? '?' );
        if ( ! empty( $p['note'] ) ) $line .= ': ' . $p['note'];
        $motivo_lines[] = $line;
    }
    if ( ! empty( $note ) ) $motivo_lines[] = 'Nota: ' . $note;

    $body_text = ! empty( $motivo_lines )
        ? '<strong>Motivo:</strong><br>• ' . implode( '<br>• ', array_map( 'esc_html', $motivo_lines ) )
        : 'Por favor reveja a sua submissão e corrija o necessário.';

    rmbz_notify_create([
        'type'             => 'release_returned',
        'severity'         => 'danger',
        'title'            => '"' . ( $rel->title ?: 'Release' ) . '" foi devolvido pela curadoria',
        'body'             => $body_text,
        // [1.5.186] Fix URL: a rota correcta é `edit_release` (não `editar`).
        // Antes ia para uma URL inexistente que caía no dashboard.
        'action_url'       => '?distro_action=edit_release&id=' . (int) $rel->id,
        'action_label'     => 'Ver e corrigir',
        'target_telemovel' => $rel->artist_telemovel,
        'dedup_key'        => 'release_returned:' . (int) $rel->id,
        'metadata'         => [ 'release_id' => (int) $rel->id, 'problems' => $problems_clean ],
        'created_by'       => 'system',
        // Não expira — fica até o artista fechar
    ]);
}
add_action( 'rmbz_distro_release_returned', 'rmbz_notif_event_release_returned', 20, 3 );


/**
 * Listener: status do release mudou — atrás disso podem estar 'live' (sucesso!)
 * ou 'rejected' (danger).
 *
 * Hook: rmbz_distro_status_changed (definido em distribution-release-workflow.php:245)
 *
 * @param int    $release_id
 * @param string $old_status
 * @param string $new_status
 */
function rmbz_notif_event_release_status_changed( $release_id, $old_status, $new_status ) {
    if ( ! function_exists('rmbz_notify_create') ) return;

    // [1.5.188] Se o release SAIR de 'returned' por qualquer motivo (artista
    // re-submete, admin força transição, etc.), arquivar a notificação
    // "X foi devolvido" — o problema está resolvido, banner já não faz sentido.
    //
    // Isto é o complemento do hook 'rmbz_release_resubmitted' que cobre o
    // caso específico do artista. Aqui apanhamos casos extra onde o admin
    // muda status manualmente sem passar pelo flow de resubmit.
    if ( $old_status === 'returned' && $new_status !== 'returned' ) {
        global $wpdb;
        $wpdb->update(
            "{$wpdb->prefix}rmbz_notifications",
            [ 'is_archived' => 1 ],
            [
                'dedup_key'   => 'release_returned:' . (int) $release_id,
                'is_archived' => 0,
            ],
            [ '%d' ],
            [ '%s', '%d' ]
        );
    }

    // Apenas criamos novas notifs para 'live' e 'rejected'
    if ( ! in_array( $new_status, ['live', 'rejected'], true ) ) return;

    global $wpdb;
    $rel = $wpdb->get_row( $wpdb->prepare(
        "SELECT id, title, artist_telemovel
         FROM {$wpdb->prefix}rmbz_distro_releases
         WHERE id = %d",
        (int) $release_id
    ));
    if ( ! $rel || empty( $rel->artist_telemovel ) ) return;

    if ( $new_status === 'live' ) {
        rmbz_notify_create([
            'type'             => 'release_live',
            'severity'         => 'success',
            'title'            => '🎉 "' . ( $rel->title ?: 'Release' ) . '" está ao vivo nas lojas!',
            'body'             => 'A sua música já está a ser ouvida no Spotify, Apple Music e mais. Os royalties vão começar a chegar nos próximos meses.',
            'action_url'       => '?distro_action=view_release&id=' . (int) $rel->id,
            'action_label'     => 'Ver detalhes',
            'target_telemovel' => $rel->artist_telemovel,
            'dedup_key'        => 'release_live:' . (int) $rel->id,
            'expires_at'       => gmdate( 'Y-m-d H:i:s', time() + (30 * 86400) ), // expira em 30 dias
            'created_by'       => 'system',
        ]);
    } elseif ( $new_status === 'rejected' ) {
        rmbz_notify_create([
            'type'             => 'release_rejected',
            'severity'         => 'danger',
            'title'            => '"' . ( $rel->title ?: 'Release' ) . '" foi rejeitado',
            'body'             => 'O lançamento foi rejeitado e não será distribuído. Para detalhes, contacte o suporte.',
            'action_url'       => '?distro_action=view_release&id=' . (int) $rel->id,
            'action_label'     => 'Ver detalhes',
            'target_telemovel' => $rel->artist_telemovel,
            'dedup_key'        => 'release_rejected:' . (int) $rel->id,
            'created_by'       => 'system',
        ]);
    }
}
add_action( 'rmbz_distro_status_changed', 'rmbz_notif_event_release_status_changed', 20, 3 );


/* ============================================================================
 * 2. SOMAS LICENSING
 * ============================================================================ */

/**
 * Listener: registo SOMAS aprovado pelo admin.
 *
 * Hook: rmbz_somas_registration_approved (NOVO — vamos adicionar em
 *       distribution-licensing.php).
 *
 * @param object $reg
 * @param string $somas_number
 */
function rmbz_notif_event_somas_registration_approved( $reg, $somas_number ) {
    if ( ! function_exists('rmbz_notify_create') ) return;
    if ( empty( $reg->telemovel ) ) return;

    rmbz_notify_create([
        'type'             => 'somas_approved',
        'severity'         => 'success',
        'title'            => '✓ Registo SOMAS aprovado',
        'body'             => 'O seu nº de membro SOMAS é <strong>' . esc_html( $somas_number ) . '</strong>. Já pode licenciar faixas a 100MT/cada quando submeter um lançamento.',
        'action_url'       => '?distro_action=licensing-somas',
        'action_label'     => 'Ver detalhes',
        'target_telemovel' => $reg->telemovel,
        'dedup_key'        => 'somas_registration_approved:' . (int) $reg->id,
        'expires_at'       => gmdate( 'Y-m-d H:i:s', time() + (30 * 86400) ),
        'created_by'       => 'system',
    ]);
}
add_action( 'rmbz_somas_registration_approved', 'rmbz_notif_event_somas_registration_approved', 20, 2 );


/**
 * Listener: registo SOMAS rejeitado pelo admin.
 */
function rmbz_notif_event_somas_registration_rejected( $reg, $reason ) {
    if ( ! function_exists('rmbz_notify_create') ) return;
    if ( empty( $reg->telemovel ) ) return;

    rmbz_notify_create([
        'type'             => 'somas_rejected',
        'severity'         => 'danger',
        'title'            => 'Registo SOMAS rejeitado',
        'body'             => '<strong>Motivo:</strong> ' . esc_html( $reason ) . '<br>O valor pago foi reembolsado para a sua carteira.',
        'action_url'       => '?distro_action=licensing-somas',
        'action_label'     => 'Ver detalhes',
        'target_telemovel' => $reg->telemovel,
        'dedup_key'        => 'somas_registration_rejected:' . (int) $reg->id,
        'created_by'       => 'system',
    ]);
}
add_action( 'rmbz_somas_registration_rejected', 'rmbz_notif_event_somas_registration_rejected', 20, 2 );


/**
 * Listener: registo SOMAS devolvido para correcção.
 */
function rmbz_notif_event_somas_registration_returned( $reg, $reason ) {
    if ( ! function_exists('rmbz_notify_create') ) return;
    if ( empty( $reg->telemovel ) ) return;

    rmbz_notify_create([
        'type'             => 'somas_returned',
        'severity'         => 'warning',
        'title'            => 'Registo SOMAS precisa de correcção',
        'body'             => '<strong>Motivo:</strong> ' . esc_html( $reason ) . '<br>Por favor corrija e reenvie.',
        'action_url'       => '?distro_action=licensing-somas',
        'action_label'     => 'Ver e corrigir',
        'target_telemovel' => $reg->telemovel,
        'dedup_key'        => 'somas_registration_returned:' . (int) $reg->id,
        'created_by'       => 'system',
    ]);
}
add_action( 'rmbz_somas_registration_returned', 'rmbz_notif_event_somas_registration_returned', 20, 2 );


/**
 * Listener: licença SOMAS aprovada (cobertura por faixa).
 */
function rmbz_notif_event_somas_license_approved( $lic ) {
    if ( ! function_exists('rmbz_notify_create') ) return;
    if ( empty( $lic->telemovel ) ) return;

    rmbz_notify_create([
        'type'             => 'license_approved',
        'severity'         => 'success',
        'title'            => '✓ Licença SOMAS aprovada',
        'body'             => 'A sua licença foi processada e está activa. O lançamento pode prosseguir.',
        'target_telemovel' => $lic->telemovel,
        'dedup_key'        => 'license_approved:' . (int) $lic->id,
        'expires_at'       => gmdate( 'Y-m-d H:i:s', time() + (14 * 86400) ),
        'created_by'       => 'system',
    ]);
}
add_action( 'rmbz_somas_license_approved', 'rmbz_notif_event_somas_license_approved', 20, 1 );


/**
 * Listener: licença SOMAS rejeitada.
 */
function rmbz_notif_event_somas_license_rejected( $lic, $reason ) {
    if ( ! function_exists('rmbz_notify_create') ) return;
    if ( empty( $lic->telemovel ) ) return;

    rmbz_notify_create([
        'type'             => 'license_rejected',
        'severity'         => 'danger',
        'title'            => 'Licença SOMAS rejeitada',
        'body'             => '<strong>Motivo:</strong> ' . esc_html( $reason ) . '<br>O valor pago foi reembolsado.',
        'target_telemovel' => $lic->telemovel,
        'dedup_key'        => 'license_rejected:' . (int) $lic->id,
        'created_by'       => 'system',
    ]);
}
add_action( 'rmbz_somas_license_rejected', 'rmbz_notif_event_somas_license_rejected', 20, 2 );


/* ============================================================================
 * 3. MATCH REVIEW (royalties por nome+UPC sem ISRC)
 * ============================================================================ */

/**
 * Listener: admin aprovou um match group → royalties foram atribuídos ao artista.
 *
 * Hook: rmbz_match_review_group_approved (NOVO — vamos adicionar em
 *       admin-match-review.php).
 *
 * @param string $artist_telemovel
 * @param string $artist_name
 * @param float  $total_amount_usd
 * @param int    $group_count Quantas linhas foram aprovadas
 * @param string $track_title Título da faixa
 */
function rmbz_notif_event_match_review_group_approved( $artist_telemovel, $artist_name, $total_amount_usd, $group_count, $track_title ) {
    if ( ! function_exists('rmbz_notify_create') ) return;
    if ( empty( $artist_telemovel ) ) return;

    $amount_formatted = number_format( (float) $total_amount_usd, 2 );

    rmbz_notify_create([
        'type'             => 'match_review_approved',
        'severity'         => 'success',
        'title'            => '💰 Royalties atribuídos à sua música',
        'body'             => 'A faixa <strong>' . esc_html( $track_title ?: 'sua música' ) . '</strong> foi confirmada manualmente pela equipa e <strong>$' . $amount_formatted . '</strong> foram creditados na sua carteira de royalties.',
        'action_url'       => '?distro_action=analytics',
        'action_label'     => 'Ver analytics',
        'target_telemovel' => $artist_telemovel,
        // Dedup por hash do título+amount para evitar 2 notifs do mesmo evento
        'dedup_key'        => 'match_review_approved:' . md5( $track_title . '|' . $amount_formatted . '|' . $group_count ),
        'expires_at'       => gmdate( 'Y-m-d H:i:s', time() + (14 * 86400) ),
        'created_by'       => 'system',
    ]);
}
add_action( 'rmbz_match_review_group_approved', 'rmbz_notif_event_match_review_group_approved', 20, 5 );


/* ============================================================================
 * 4. WITHDRAWAL APPROVED / REJECTED
 * ============================================================================ */

/**
 * Listener: pedido de levantamento aprovado pelo admin.
 *
 * Hook: rmbz_withdrawal_approved (NOVO — vamos adicionar em admin-handlers).
 *
 * @param int    $withdrawal_id
 * @param string $artist_telemovel
 * @param float  $amount_mt
 */
function rmbz_notif_event_withdrawal_approved( $withdrawal_id, $artist_telemovel, $amount_mt ) {
    if ( ! function_exists('rmbz_notify_create') ) return;
    if ( empty( $artist_telemovel ) ) return;

    $amount_formatted = number_format( (float) $amount_mt, 2, ',', '.' );

    rmbz_notify_create([
        'type'             => 'withdrawal_approved',
        'severity'         => 'success',
        'title'            => '✓ Pedido de levantamento aprovado',
        'body'             => 'O pagamento de <strong>' . $amount_formatted . ' MT</strong> foi processado e enviado para a conta indicada.',
        'target_telemovel' => $artist_telemovel,
        'dedup_key'        => 'withdrawal_approved:' . (int) $withdrawal_id,
        'expires_at'       => gmdate( 'Y-m-d H:i:s', time() + (14 * 86400) ),
        'created_by'       => 'system',
    ]);
}
add_action( 'rmbz_withdrawal_approved', 'rmbz_notif_event_withdrawal_approved', 20, 3 );


/**
 * Listener: pedido de levantamento rejeitado pelo admin.
 */
function rmbz_notif_event_withdrawal_rejected( $withdrawal_id, $artist_telemovel, $amount_mt, $reason = '' ) {
    if ( ! function_exists('rmbz_notify_create') ) return;
    if ( empty( $artist_telemovel ) ) return;

    $amount_formatted = number_format( (float) $amount_mt, 2, ',', '.' );

    $body = 'O valor de <strong>' . $amount_formatted . ' MT</strong> foi devolvido à sua carteira.';
    if ( ! empty( $reason ) ) {
        $body = '<strong>Motivo:</strong> ' . esc_html( $reason ) . '<br>' . $body;
    }

    rmbz_notify_create([
        'type'             => 'withdrawal_rejected',
        'severity'         => 'danger',
        'title'            => 'Pedido de levantamento rejeitado',
        'body'             => $body,
        'target_telemovel' => $artist_telemovel,
        'dedup_key'        => 'withdrawal_rejected:' . (int) $withdrawal_id,
        'created_by'       => 'system',
    ]);
}
add_action( 'rmbz_withdrawal_rejected', 'rmbz_notif_event_withdrawal_rejected', 20, 4 );


/* ============================================================================
 * 5. CLEANUP — release apagado → arquivar notifs órfãs (1.5.187)
 * ============================================================================ */

/**
 * Listener: release foi apagado. Arquiva imediatamente todas as notificações
 * que referenciam esse release_id (no metadata ou no action_url).
 *
 * Hook: rmbz_release_deleted (NOVO em 1.5.187 — disparado em form-handler.php
 *       e distribution-release-cleanup.php).
 *
 * Esta é a Camada B (proactiva) do cleanup. A Camada A (defesa em runtime,
 * em rmbz_notify_filter_orphans) cobre casos onde este hook não corre.
 *
 * @param int    $release_id
 * @param string $artist_telemovel  (vazio em deletes do cleanup cron)
 */
function rmbz_notif_event_release_deleted( $release_id, $artist_telemovel = '' ) {
    global $wpdb;
    $release_id = (int) $release_id;
    if ( $release_id <= 0 ) return;

    // Arquivar notifs que referenciam o release no metadata OU no action_url.
    // Usar JSON_EXTRACT seria mais limpo mas não funciona em todas as versões
    // do MySQL (5.7+). LIKE é universal.
    //
    // [1.5.190] Match em 2 formatos de query string:
    //   - URLs antigos: ?...&release_id=N
    //   - URLs novos:   ?...&id=N (formato real do wizard)
    // Para "&id=" temos de evitar match com "&release_id=", "&track_id=",
    // etc. — uso anchor `&id=` literal e checks no início e fim.
    $wpdb->query( $wpdb->prepare(
        "UPDATE {$wpdb->prefix}rmbz_notifications
         SET is_archived = 1
         WHERE is_archived = 0
           AND (
                metadata LIKE %s
             OR action_url LIKE %s
             OR action_url LIKE %s
             OR action_url LIKE %s
             OR action_url LIKE %s
           )",
        '%"release_id":' . $release_id . '%',
        // Formato antigo release_id=N
        '%release_id=' . $release_id . '&%',
        '%release_id=' . $release_id,
        // Formato novo &id=N (note o & antes obrigatório para evitar
        // matchar release_id por substring overlap)
        '%&id=' . $release_id . '&%',
        '%&id=' . $release_id
    ));
}
add_action( 'rmbz_release_deleted', 'rmbz_notif_event_release_deleted', 20, 2 );


/**
 * [1.5.188] Listener: artista re-submeteu um release após correcções.
 * Arquiva imediatamente a notificação "release_returned" desse release —
 * o problema está resolvido, o banner já não faz sentido.
 *
 * Hook: rmbz_release_resubmitted (NOVO em 1.5.188 — disparado em
 *       distribution-return-workflow.php após status 'returned' → 'pendente').
 *
 * Usa o dedup_key fixo "release_returned:ID" para encontrar a notif certa
 * (criado pelo listener rmbz_notif_event_release_returned).
 *
 * @param int    $release_id
 * @param string $artist_telemovel
 */
function rmbz_notif_event_release_resubmitted( $release_id, $artist_telemovel ) {
    global $wpdb;
    $release_id = (int) $release_id;
    if ( $release_id <= 0 ) return;

    // Arquivar via dedup_key — match exacto, mais rápido e seguro que LIKE
    $wpdb->update(
        "{$wpdb->prefix}rmbz_notifications",
        [ 'is_archived' => 1 ],
        [
            'dedup_key'   => 'release_returned:' . $release_id,
            'is_archived' => 0,
        ],
        [ '%d' ],
        [ '%s', '%d' ]
    );
}
add_action( 'rmbz_release_resubmitted', 'rmbz_notif_event_release_resubmitted', 20, 2 );
