<?php
/**
 * 1MZ For Artists — Bloqueios/banimentos do artista (temporários ou permanentes)
 *
 * [1.6.336] Cada limitação pode ser PERMANENTE ou TEMPORÁRIA (com data de
 * desbloqueio + cronómetro). Expira sozinha (lazy) — ver hooks abaixo.
 *
 * [1.6.337] Cada limitação passa a ter DOIS motivos + auditoria:
 *   - `internal` → SÓ para o admin (nunca sai para app/site). É OBRIGATÓRIO:
 *     sem ele o bloqueio NÃO é aplicado.
 *   - `user`     → mostrado ao artista na app e no site (com cronómetro se for
 *     temporário). Opcional (há texto genérico se faltar).
 * Tudo guardado em `extra_data['blocks_meta'][chave]` = { until, internal,
 * user, by, at }. Histórico em `extra_data['blocks_log']` (últimas 50 ações).
 *
 * @package 1MZ_For_Artists
 */

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

/** Chaves dos bloqueios de serviço/financeiros guardados como boolean em extra_data. */
function rmbz_block_keys() {
    return [
        'block_deposits',
        'block_withdrawals',
        'block_distribution',
        'block_video_applications',
        'block_promotions',
    ];
}

/** Todas as chaves de limitação (inclui banimento total e de convites) + etiquetas pt-PT. */
function rmbz_block_labels() {
    return [
        'is_banned'                => 'Acesso à conta (login)',
        'block_withdrawals'        => 'Levantamentos',
        'block_deposits'           => 'Depósitos',
        'block_distribution'       => 'Distribuição digital',
        'block_video_applications' => 'Candidaturas a videoclipe',
        'block_promotions'         => 'Promoção (Site/Redes)',
        'ban_referral'             => 'Comissões de convite',
    ];
}

/** Etiqueta humana de uma chave de bloqueio. */
function rmbz_block_label( $key ) {
    $labels = rmbz_block_labels();
    return $labels[ $key ] ?? $key;
}

/** Etiqueta pública com linguagem natural para app, site e emails. */
function rmbz_block_public_label( $key ) {
    $labels = [
        'is_banned'                => 'Acesso à conta',
        'block_withdrawals'        => 'Levantamentos',
        'block_deposits'           => 'Depósitos',
        'block_distribution'       => 'Distribuição digital',
        'block_video_applications' => 'Candidaturas a videoclipe',
        'block_promotions'         => 'Promoção no site e redes sociais',
        'ban_referral'             => 'Comissões de convite',
    ];
    return $labels[ $key ] ?? rmbz_block_label( $key );
}

/**
 * Lê o `blocks_meta` de um extra_data, com migração dos campos antigos
 * (blocks_until / ban_until / ban_referral_until) para o novo formato.
 */
function rmbz_blocks_meta( array $extra ) {
    $meta = ( isset( $extra['blocks_meta'] ) && is_array( $extra['blocks_meta'] ) ) ? $extra['blocks_meta'] : [];

    // Migração leve de datas antigas (1.5.335) → meta.until.
    if ( isset( $extra['blocks_until'] ) && is_array( $extra['blocks_until'] ) ) {
        foreach ( $extra['blocks_until'] as $k => $ts ) {
            if ( $ts && empty( $meta[ $k ]['until'] ) ) $meta[ $k ]['until'] = (int) $ts;
        }
    }
    if ( ! empty( $extra['ban_until'] ) && empty( $meta['is_banned']['until'] ) ) {
        $meta['is_banned']['until'] = (int) $extra['ban_until'];
    }
    if ( ! empty( $extra['ban_referral_until'] ) && empty( $meta['ban_referral']['until'] ) ) {
        $meta['ban_referral']['until'] = (int) $extra['ban_referral_until'];
    }
    return $meta;
}

/** Data de desbloqueio (ts) de uma chave; 0 = permanente. */
function rmbz_block_until( array $extra, $key ) {
    $meta = rmbz_blocks_meta( $extra );
    return ! empty( $meta[ $key ]['until'] ) ? (int) $meta[ $key ]['until'] : 0;
}

/** Acrescenta uma entrada ao histórico de bloqueios (cap 50). */
function rmbz_block_log_append( array &$extra, array $entry ) {
    $log = ( isset( $extra['blocks_log'] ) && is_array( $extra['blocks_log'] ) ) ? $extra['blocks_log'] : [];
    $entry['at'] = $entry['at'] ?? time();
    array_unshift( $log, $entry );
    if ( count( $log ) > 50 ) $log = array_slice( $log, 0, 50 );
    $extra['blocks_log'] = $log;
}

/**
 * Aplica as expirações: limpa bloqueios/banimentos cuja data de desbloqueio já
 * passou. Persiste só se houve mudança. Idempotente.
 *
 * @return int  is_banned efetivo (já corrigido) — 0 ou 1.
 */
function rmbz_apply_block_expiries( $telemovel, $row = null ) {
    if ( empty( $telemovel ) ) return 0;
    global $wpdb;
    $table = $wpdb->prefix . 'rmbz_wallets';

    if ( $row === null ) {
        $row = $wpdb->get_row( $wpdb->prepare(
            "SELECT is_banned, extra_data FROM {$table} WHERE user_telemovel = %s LIMIT 1",
            $telemovel
        ) );
    }
    if ( ! $row ) return 0;

    $extra = ! empty( $row->extra_data ) ? json_decode( $row->extra_data, true ) : [];
    if ( ! is_array( $extra ) ) $extra = [];
    $meta = rmbz_blocks_meta( $extra );

    $now       = time(); // Unix real (UTC) — condiz com os until guardados.
    $is_banned = (int) ( $row->is_banned ?? 0 );
    $changed   = false;

    $clear_meta = function ( $key ) use ( &$meta, &$extra, &$changed, $telemovel ) {
        if ( isset( $meta[ $key ] ) ) { unset( $meta[ $key ] ); }
        rmbz_block_log_append( $extra, [ 'action' => 'auto_lift', 'key' => $key, 'by' => 'sistema' ] );
        $changed = true;
        // [1.6.338] Avisa o artista que o bloqueio expirou (email + push + in-app).
        if ( function_exists( 'rmbz_blocks_notify' ) ) {
            rmbz_blocks_notify( $telemovel, $key, 'lift' );
        }
    };

    // Bloqueios de serviço/financeiros.
    foreach ( rmbz_block_keys() as $k ) {
        $until = ! empty( $meta[ $k ]['until'] ) ? (int) $meta[ $k ]['until'] : 0;
        if ( ! empty( $extra[ $k ] ) && $until > 0 && $until <= $now ) {
            $extra[ $k ] = 0;
            $clear_meta( $k );
        }
    }

    // Banimento total (impede login).
    $ban_until = ! empty( $meta['is_banned']['until'] ) ? (int) $meta['is_banned']['until'] : 0;
    if ( $is_banned === 1 && $ban_until > 0 && $ban_until <= $now ) {
        $is_banned = 0;
        $clear_meta( 'is_banned' );
    }

    // Banimento de convites (lista global) com expiração.
    $ref_until = ! empty( $meta['ban_referral']['until'] ) ? (int) $meta['ban_referral']['until'] : 0;
    if ( $ref_until > 0 && $ref_until <= $now ) {
        $bl  = (array) get_option( 'rmbz_referral_blacklist', [] );
        $new = array_values( array_filter( $bl, function ( $v ) use ( $telemovel ) {
            return $v !== $telemovel;
        } ) );
        if ( count( $new ) !== count( $bl ) ) update_option( 'rmbz_referral_blacklist', $new );
        $clear_meta( 'ban_referral' );
    }

    if ( $changed ) {
        $extra['blocks_meta'] = $meta;
        // Remove campos antigos já migrados.
        unset( $extra['blocks_until'], $extra['ban_until'], $extra['ban_referral_until'] );
        $wpdb->update(
            $table,
            [ 'is_banned' => $is_banned, 'extra_data' => wp_json_encode( $extra ) ],
            [ 'user_telemovel' => $telemovel ],
            [ '%d', '%s' ], [ '%s' ]
        );
    }

    return $is_banned;
}

/**
 * [1.6.337] Lista de limitações ATIVAS de um artista, com o motivo PARA O
 * UTILIZADOR e a data de desbloqueio (para cronómetro). NUNCA inclui o motivo
 * interno. Usado pela app, pelo site e nas mensagens de erro.
 *
 * @return array<int,array> [ key, label, reason, until (ts|0), until_iso, permanent ]
 */
function rmbz_user_active_blocks( $telemovel, $extra = null, $is_banned = null ) {
    global $wpdb;
    if ( $extra === null || $is_banned === null ) {
        $row = $wpdb->get_row( $wpdb->prepare(
            "SELECT is_banned, extra_data FROM {$wpdb->prefix}rmbz_wallets WHERE user_telemovel = %s LIMIT 1",
            $telemovel
        ) );
        if ( $row ) {
            if ( $extra === null )     $extra = ! empty( $row->extra_data ) ? json_decode( $row->extra_data, true ) : [];
            if ( $is_banned === null ) $is_banned = (int) $row->is_banned;
        }
    }
    if ( ! is_array( $extra ) ) $extra = [];
    $meta = rmbz_blocks_meta( $extra );

    // Está ativo?
    $active_map = [
        'is_banned'    => ( (int) $is_banned === 1 ),
        'ban_referral' => in_array( $telemovel, (array) get_option( 'rmbz_referral_blacklist', [] ), true ),
    ];
    foreach ( rmbz_block_keys() as $k ) {
        $active_map[ $k ] = ! empty( $extra[ $k ] );
    }

    $out = [];
    foreach ( rmbz_block_labels() as $key => $label ) {
        if ( empty( $active_map[ $key ] ) ) continue;
        $until  = ! empty( $meta[ $key ]['until'] ) ? (int) $meta[ $key ]['until'] : 0;
        $reason = isset( $meta[ $key ]['user'] ) ? trim( (string) $meta[ $key ]['user'] ) : '';
        $out[] = [
            'key'       => $key,
            'label'     => $label,
            'reason'    => $reason,
            'until'     => $until,
            'until_iso' => $until > 0 ? wp_date( 'c', $until ) : null,
            'permanent' => $until <= 0,
        ];
    }
    return $out;
}

/**
 * Remove dados internos (motivo interno, autor) do `extra` antes de o enviar
 * para a app/site. Mantém só `user` + `until` em cada bloco.
 */
function rmbz_blocks_strip_internal( array $extra ) {
    if ( isset( $extra['blocks_meta'] ) && is_array( $extra['blocks_meta'] ) ) {
        foreach ( $extra['blocks_meta'] as $k => $m ) {
            if ( ! is_array( $m ) ) continue;
            $extra['blocks_meta'][ $k ] = [
                'until' => ! empty( $m['until'] ) ? (int) $m['until'] : 0,
                'user'  => isset( $m['user'] ) ? (string) $m['user'] : '',
            ];
        }
    }
    unset( $extra['blocks_log'] ); // histórico/auditoria é só do admin
    return $extra;
}

/**
 * [1.6.338] Notifica o artista de um bloqueio/desbloqueio em TODOS os canais:
 *   - Notificação in-app (rmbz_notify_user) → também dispara PUSH (FCM) e é
 *     dispensável (depois de vista não volta a aparecer).
 *   - Email (best-effort).
 *
 * @param string $action 'apply' (bloqueou) ou 'lift' (desbloqueou/expirou).
 */
function rmbz_blocks_notify( $telemovel, $key, $action, $user_reason = '', $until = 0 ) {
    $label = function_exists( 'rmbz_block_public_label' ) ? rmbz_block_public_label( $key ) : rmbz_block_label( $key );

    if ( $action === 'apply' ) {
        $title = 'Acesso limitado: ' . $label;
        $body  = $user_reason !== '' ? $user_reason : 'O acesso a ' . $label . ' foi limitado na tua conta.';
        if ( (int) $until > 0 ) {
            $body .= ' A reativação está prevista para ' . wp_date( 'd/m/Y \à\s H:i', (int) $until ) . '.';
        } else {
            $body .= ' A reativação será feita pela equipa.';
        }
        $severity = 'danger';
        $type     = 'block_applied';
    } else {
        $title    = 'Acesso restabelecido: ' . $label;
        $body     = 'O acesso a ' . $label . ' foi restabelecido. Já podes voltar a utilizar este serviço.';
        $severity = 'success';
        $type     = 'block_lifted';
    }

    // In-app + push (dispensável). dedup evita repetir a mesma notificação.
    if ( function_exists( 'rmbz_notify_user' ) ) {
        rmbz_notify_user( $telemovel, $title, $body, $severity, [
            'type'       => $type,
            'dedup_key'  => $type . '_' . $key . '_' . ( (int) $until ) . '_' . md5( (string) $telemovel ),
            'created_by' => 'system',
        ] );
    }

    // Email (best-effort).
    rmbz_blocks_send_email( $telemovel, $title, $body, [
        'action' => $action,
        'key'    => $key,
        'label'  => $label,
        'reason' => $user_reason,
        'until'  => (int) $until,
    ] );
}

/** Envia o email do bloqueio/desbloqueio ao artista, se tiver email real. */
function rmbz_blocks_send_email( $telemovel, $subject, $body, array $context = [] ) {
    global $wpdb;
    $artist = $wpdb->get_row( $wpdb->prepare(
        "SELECT user_email, user_nome FROM {$wpdb->prefix}rmbz_wallets WHERE user_telemovel = %s LIMIT 1",
        $telemovel
    ) );
    $email = $artist ? (string) $artist->user_email : '';
    if ( empty( $email ) || strpos( (string) $email, '@1mz.local' ) !== false || ! is_email( $email ) ) {
        return;
    }

    $action     = ( $context['action'] ?? 'apply' ) === 'lift' ? 'lift' : 'apply';
    $label      = trim( (string) ( $context['label'] ?? '' ) );
    $reason     = trim( (string) ( $context['reason'] ?? '' ) );
    $until      = (int) ( $context['until'] ?? 0 );
    $artist_name = $artist ? trim( (string) $artist->user_nome ) : '';
    $greeting   = $artist_name !== '' ? 'Olá ' . $artist_name . ',' : 'Olá,';

    if ( $label === '' ) {
        $label = 'Serviço da conta';
    }

    $is_lifted    = $action === 'lift';
    $state_label  = $is_lifted ? 'Acesso restabelecido' : 'Acesso limitado';
    $state_color  = $is_lifted ? '#42d6a4' : '#ff7770';
    $state_bg     = $is_lifted ? '#15382f' : '#3b2225';
    $intro        = $is_lifted
        ? 'A equipa atualizou o estado de um serviço da tua conta.'
        : 'Foi aplicada uma alteração ao acesso de um serviço da tua conta.';
    $timing_label = $is_lifted
        ? 'O serviço já está novamente disponível.'
        : ( $until > 0
            ? 'Reativação automática em ' . wp_date( 'd/m/Y \à\s H:i', $until ) . '.'
            : 'A reativação será feita pela equipa.' );

    $content  = '<p style="margin:0 0 12px; color:#e8e8ee; font-size:16px;">' . esc_html( $greeting ) . '</p>';
    $content .= '<p style="margin:0 0 22px; color:#b7b7c2; font-size:15px; line-height:1.65;">' . esc_html( $intro ) . '</p>';
    $content .= '<table role="presentation" width="100%" cellpadding="0" cellspacing="0" border="0" style="width:100%; border-collapse:separate; background:#25252c; border:1px solid #35353e; border-radius:20px;">';
    $content .= '<tr><td style="padding:20px 20px 18px;">';
    $content .= '<span style="display:inline-block; padding:6px 10px; border-radius:999px; background:' . esc_attr( $state_bg ) . '; color:' . esc_attr( $state_color ) . '; font-size:11px; line-height:1.2; font-weight:700; letter-spacing:.5px; text-transform:uppercase;">' . esc_html( $state_label ) . '</span>';
    $content .= '<div style="margin-top:13px; color:#91919d; font-size:11px; line-height:1.3; font-weight:700; letter-spacing:.8px; text-transform:uppercase;">Serviço</div>';
    $content .= '<div style="margin-top:4px; color:#ffffff; font-size:19px; line-height:1.35; font-weight:750;">' . esc_html( $label ) . '</div>';
    $content .= '<div style="margin-top:15px; padding-top:14px; border-top:1px solid #3a3a44; color:#c9c9d2; font-size:13px; line-height:1.55;">' . esc_html( $timing_label ) . '</div>';
    $content .= '</td></tr></table>';

    if ( ! $is_lifted && $reason !== '' ) {
        $content .= '<div style="margin-top:14px; padding:16px 18px; border-left:3px solid #f0b90b; border-radius:4px 16px 16px 4px; background:#29271f;">';
        $content .= '<div style="color:#f0b90b; font-size:10px; line-height:1.3; font-weight:750; letter-spacing:.8px; text-transform:uppercase;">Informação da equipa</div>';
        $content .= '<div style="margin-top:6px; color:#dedee5; font-size:13px; line-height:1.6;">' . nl2br( esc_html( $reason ) ) . '</div>';
        $content .= '</div>';
    }

    $support_email = sanitize_email( (string) get_option( 'rmbz_support_email', '' ) );
    if ( $support_email === '' ) {
        $support_email = sanitize_email( (string) get_option( 'admin_email', '' ) );
    }
    if ( $support_email !== '' ) {
        $content .= '<p style="margin:20px 0 0; color:#9a9aa6; font-size:13px; line-height:1.6;">Precisas de esclarecimento? Contacta o suporte em <a href="mailto:' . esc_attr( $support_email ) . '" style="color:#f0b90b; font-weight:700; text-decoration:none;">' . esc_html( $support_email ) . '</a>.</p>';
    }

    $clean_subject = wp_strip_all_tags( $subject );
    if ( function_exists( 'rmbz_build_html_email' ) ) {
        $message = rmbz_build_html_email( $content, '', [
            'emoji'   => $is_lifted ? '&#10003;&#xFE0E;' : '&#33;',
            'eyebrow' => 'Estado da conta',
        ] );
    } else {
        $message = '<div style="max-width:620px; margin:0 auto; padding:28px; border-radius:24px; background:#1c1c22; color:#e8e8ee; font-family:Arial,sans-serif; line-height:1.6;">' . $content . '</div>';
    }
    $headers = [ 'Content-Type: text/html; charset=UTF-8' ];
    wp_mail( $email, $clean_subject, $message, $headers );
}

/**
 * Mensagem de "conta suspensa" para mostrar ao artista (login/app/site), já com
 * o motivo do utilizador e a data de desbloqueio se for temporário.
 */
function rmbz_banned_message( $telemovel ) {
    $base = 'Conta suspensa.';
    if ( ! function_exists( 'rmbz_user_active_blocks' ) ) return $base . ' Contacta o suporte.';
    foreach ( rmbz_user_active_blocks( $telemovel ) as $b ) {
        if ( $b['key'] !== 'is_banned' ) continue;
        $msg = $base;
        if ( $b['reason'] !== '' ) $msg .= ' ' . $b['reason'];
        if ( (int) $b['until'] > 0 ) {
            $msg .= ' (desbloqueia em ' . wp_date( 'd/m/Y \à\s H:i', (int) $b['until'] ) . ')';
        } else {
            $msg .= ' Contacta o suporte.';
        }
        return $msg;
    }
    return $base . ' Contacta o suporte.';
}

/**
 * [1.6.339] Guarda de servidor: se um serviço está bloqueado (per-user OU
 * global), devolve uma mensagem pt-PT para o artista; null se está livre.
 * Aplica primeiro as expirações. $service_key ex.: 'block_distribution'.
 * $global_type ex.: 'distribution' (para rmbz_is_globally_blocked).
 */
function rmbz_service_blocked_message( $telemovel, $service_key, $global_type = '' ) {
    if ( function_exists( 'rmbz_apply_block_expiries' ) ) {
        rmbz_apply_block_expiries( $telemovel );
    }
    // Per-user (com motivo + data).
    foreach ( rmbz_user_active_blocks( $telemovel ) as $b ) {
        if ( $b['key'] !== $service_key ) continue;
        $msg = 'Este serviço está bloqueado na tua conta.';
        if ( $b['reason'] !== '' ) $msg .= ' ' . $b['reason'];
        if ( (int) $b['until'] > 0 ) {
            $msg .= ' Desbloqueia em ' . wp_date( 'd/m/Y \à\s H:i', (int) $b['until'] ) . '.';
        }
        return $msg;
    }
    // Global (toda a plataforma).
    if ( $global_type !== '' && function_exists( 'rmbz_is_globally_blocked' ) && rmbz_is_globally_blocked( $global_type ) ) {
        return 'Este serviço está temporariamente suspenso em toda a plataforma. Tenta mais tarde.';
    }
    return null;
}

/** Converte um <input datetime-local> num timestamp UNIX real (UTC). A hora é
 * interpretada no FUSO DO WORDPRESS (wp_timezone), não no do PHP. 0 = permanente. */
function rmbz_block_parse_until( $raw ) {
    $raw = trim( (string) $raw );
    if ( $raw === '' ) return 0;
    $tz = function_exists( 'wp_timezone' ) ? wp_timezone() : null;
    $dt = date_create_from_format( 'Y-m-d\TH:i', $raw, $tz );
    if ( ! $dt ) {
        $dt = date_create_from_format( 'Y-m-d\TH:i:s', $raw, $tz );
    }
    return $dt ? (int) $dt->getTimestamp() : 0;
}

/** Valor para preencher o <input datetime-local> a partir de um timestamp. */
function rmbz_block_until_input_value( $ts ) {
    $ts = (int) $ts;
    return $ts > 0 ? wp_date( 'Y-m-d\TH:i', $ts ) : '';
}

/** Etiqueta humana do estado de um bloqueio temporário/permanente (pt-PT). */
function rmbz_block_state_label( $active, $until ) {
    if ( ! $active ) return '';
    $until = (int) $until;
    if ( $until > 0 ) {
        return 'Até ' . wp_date( 'd/m/Y \à\s H:i', $until );
    }
    return 'Permanente';
}
