<?php
/**
 * 1MZ For Artists — Profile Controller
 *
 * Endpoints:
 *   GET  /1mz/v1/profile                    — Dados completos do perfil
 *   POST /1mz/v1/profile/request_change     — Pede mudança de email/província
 *                                              (envia OTP de 6 dígitos para o NOVO email)
 *   POST /1mz/v1/profile/verify_change      — Confirma OTP e efectiva a mudança
 *   POST /1mz/v1/profile/cancel_change      — Cancela um pedido pendente
 *   GET  /1mz/v1/profile/change_status      — Indica se há mudança pendente
 *
 * REGRAS DO PLUGIN (ver user-perfil.php):
 *   - O NOME (user_nome) é IMUTÁVEL — nunca pode ser alterado.
 *   - Para mudar email/província é necessário:
 *       1. Pedir mudança → API gera OTP de 6 dígitos e envia para o NOVO email
 *       2. OTP válido 15 minutos
 *       3. Validar OTP → mudança efectiva-se
 *   - Email não pode ser igual ao de outra conta existente.
 *
 * NOTA: Não há endpoint de "trocar PIN". O fluxo de troca de PIN no plugin
 * passa por recuperação (nome+telemóvel→email→nova_senha) e está bloqueado
 * 30 dias entre cada troca. A app aponta o utilizador para fazer no site.
 *
 * @package 1MZ_For_Artists
 * @since   1.6.0
 */

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

add_action( 'rest_api_init', 'rmbz_api_register_profile_routes' );

function rmbz_api_register_profile_routes() {
    register_rest_route( RMBZ_API_NAMESPACE, '/profile', [
        'methods'             => 'GET',
        'callback'            => 'rmbz_api_handle_get_profile',
        'permission_callback' => 'rmbz_api_require_auth',
    ] );

    register_rest_route( RMBZ_API_NAMESPACE, '/profile/request_change', [
        'methods'             => 'POST',
        'callback'            => 'rmbz_api_handle_request_profile_change',
        'permission_callback' => 'rmbz_api_require_auth',
        'args' => [
            'email'     => [ 'required' => false, 'type' => 'string' ],
            'provincia' => [ 'required' => false, 'type' => 'string' ],
        ],
    ] );

    register_rest_route( RMBZ_API_NAMESPACE, '/profile/verify_change', [
        'methods'             => 'POST',
        'callback'            => 'rmbz_api_handle_verify_profile_change',
        'permission_callback' => 'rmbz_api_require_auth',
        'args' => [
            'otp' => [ 'required' => true, 'type' => 'string' ],
        ],
    ] );

    register_rest_route( RMBZ_API_NAMESPACE, '/profile/cancel_change', [
        'methods'             => 'POST',
        'callback'            => 'rmbz_api_handle_cancel_profile_change',
        'permission_callback' => 'rmbz_api_require_auth',
    ] );

    register_rest_route( RMBZ_API_NAMESPACE, '/profile/change_status', [
        'methods'             => 'GET',
        'callback'            => 'rmbz_api_handle_profile_change_status',
        'permission_callback' => 'rmbz_api_require_auth',
    ] );
}

/* ----------------------------------------------------------------------- */
/* GET PROFILE                                                             */
/* ----------------------------------------------------------------------- */

function rmbz_api_handle_get_profile( WP_REST_Request $request ) {
    $telemovel = (string) $request->get_param( 'rmbz_telemovel' );

    global $wpdb;
    $w = $wpdb->get_row( $wpdb->prepare(
        "SELECT user_telemovel, user_nome, user_email, user_provincia, balance,
                is_creator, referred_by, extra_data, last_updated, is_banned
         FROM {$wpdb->prefix}rmbz_wallets WHERE user_telemovel = %s",
        $telemovel
    ) );
    if ( ! $w ) {
        return rmbz_api_error( 'Perfil não encontrado.', 404, 'not_found' );
    }

    $extra = ! empty( $w->extra_data ) ? json_decode( $w->extra_data, true ) : [];
    if ( ! is_array( $extra ) ) {
        $extra = [];
    }

    // Filtrar campos sensíveis
    $sensitive = [ 'reset_key', 'reset_key_expires', 'reset_key_attempts' ];
    foreach ( $sensitive as $k ) {
        unset( $extra[ $k ] );
    }

    // [1.6.47] Injectar bloqueios globais no `extra` para o app saber
    // preventivamente que features estão suspensas. Estes flags coexistem
    // com os per-user (block_distribution, block_withdrawals, etc) — o app
    // mostra mensagem se QUALQUER um dos dois estiver ligado.
    if ( function_exists( 'rmbz_global_blocks_snapshot' ) ) {
        $extra = array_merge( $extra, rmbz_global_blocks_snapshot() );
    }

    // [1.6.337] Limitações por-utilizador com motivo PARA O ARTISTA + cronómetro.
    // O motivo INTERNO e a auditoria são removidos antes de sair do servidor.
    $restrictions = function_exists( 'rmbz_user_active_blocks' )
        ? rmbz_user_active_blocks( $telemovel, $extra, (int) $w->is_banned )
        : [];
    if ( function_exists( 'rmbz_blocks_strip_internal' ) ) {
        $extra = rmbz_blocks_strip_internal( $extra );
    }

    $withdrawable = function_exists( 'rmbz_get_withdrawable_balance' )
        ? rmbz_get_withdrawable_balance( $telemovel )
        : (float) $w->balance;

    // Detectar se o email actual é "de placeholder" (onboarding incompleto)
    $email_is_placeholder = strpos( (string) $w->user_email, '@1mz.local' ) !== false;

    // [Resolução de nome] O `user_nome` pode estar vazio ou conter o
    // placeholder literal "Artista" (inserido por distribution-financial.php
    // quando uma wallet é criada automaticamente). Em qualquer desses casos
    // devolvemos `null` para a app aplicar o seu próprio fallback (telemóvel
    // formatado) — a app usa este campo no cartão de partilha de conquistas.
    $resolved_nome = trim( (string) $w->user_nome );
    if ( $resolved_nome === '' || strcasecmp( $resolved_nome, 'Artista' ) === 0 ) {
        $resolved_nome = null;
    }

    return rmbz_api_ok( [
        'telemovel'             => $w->user_telemovel,
        'nome'                  => $resolved_nome,
        'email'                 => $w->user_email,
        'email_is_placeholder'  => $email_is_placeholder,
        'provincia'             => $w->user_provincia,
        'is_creator'            => (bool) $w->is_creator,
        'referred_by'           => $w->referred_by,
        'balance_total'         => (float) $w->balance,
        'balance_withdrawable'  => (float) $withdrawable,
        'currency'              => 'MZN',
        'updated_at'            => mysql_to_rfc3339( $w->last_updated ),
        'extra'                 => $extra,
        'restrictions'          => $restrictions,
    ] );
}

/* ----------------------------------------------------------------------- */
/* REQUEST PROFILE CHANGE — gera OTP e envia para novo email               */
/* ----------------------------------------------------------------------- */

function rmbz_api_handle_request_profile_change( WP_REST_Request $request ) {
    $telemovel = (string) $request->get_param( 'rmbz_telemovel' );

    $new_email_raw = $request->get_param( 'email' );
    $new_prov_raw  = $request->get_param( 'provincia' );

    $new_email = $new_email_raw !== null ? sanitize_email( wp_unslash( (string) $new_email_raw ) ) : null;
    $new_prov  = $new_prov_raw  !== null ? sanitize_text_field( wp_unslash( (string) $new_prov_raw ) ) : null;

    if ( $new_email === null && $new_prov === null ) {
        return rmbz_api_error( 'Indica pelo menos um campo a alterar.', 400, 'nothing_to_change' );
    }

    // Validar email se fornecido
    if ( $new_email !== null ) {
        if ( ! is_email( $new_email ) ) {
            return rmbz_api_error( 'Email inválido.', 400, 'bad_email' );
        }

        global $wpdb;
        $email_em_uso = $wpdb->get_var( $wpdb->prepare(
            "SELECT id FROM {$wpdb->prefix}rmbz_wallets WHERE user_email = %s AND user_telemovel != %s",
            $new_email, $telemovel
        ) );
        if ( $email_em_uso ) {
            return rmbz_api_error(
                'Este email já está registado noutra conta de artista. Por favor, utiliza um email diferente.',
                409, 'email_in_use'
            );
        }
    }

    // Validar província (lista oficial do plugin web)
    if ( $new_prov !== null ) {
        $allowed_provincias = rmbz_api_allowed_provincias();
        if ( ! in_array( $new_prov, $allowed_provincias, true ) ) {
            return rmbz_api_error( 'Província inválida.', 400, 'bad_provincia' );
        }
    }

    // Se o utilizador não enviou email novo, mantemos o actual para ENVIAR o OTP
    global $wpdb;
    $current_email = $wpdb->get_var( $wpdb->prepare(
        "SELECT user_email FROM {$wpdb->prefix}rmbz_wallets WHERE user_telemovel = %s",
        $telemovel
    ) );

    if ( $new_email === null ) {
        $new_email = $current_email;
    }

    // Se o email é placeholder, não dá para enviar OTP para lá
    if ( strpos( (string) $new_email, '@1mz.local' ) !== false ) {
        return rmbz_api_error(
            'Para mudar a província, define primeiro um email real.',
            400, 'need_real_email'
        );
    }

    // Rate limit por telemovel (evitar spam de OTPs)
    $rl = rmbz_api_rate_limit( 'profile_otp_' . md5( $telemovel ), 5, 900 );
    if ( ! $rl['allowed'] ) {
        return rmbz_api_error( 'Pediste demasiados códigos. Aguarda 15 minutos.', 429, 'rate_limited' );
    }

    // Gerar OTP e guardar como transient (15 minutos)
    try {
        $otp = sprintf( '%06d', random_int( 0, 999999 ) );
    } catch ( Exception $e ) {
        $otp = sprintf( '%06d', mt_rand( 0, 999999 ) );
    }

    set_transient(
        'rmbz_profile_otp_' . $telemovel,
        [
            'email'     => $new_email,
            'provincia' => $new_prov ?? $wpdb->get_var( $wpdb->prepare(
                "SELECT user_provincia FROM {$wpdb->prefix}rmbz_wallets WHERE user_telemovel = %s",
                $telemovel
            ) ),
            'otp'       => $otp,
            'attempts'  => 0,
        ],
        15 * 60
    );

    // Enviar email (com o nome do artista — email mais pessoal = menos spam).
    $nome_artista = (string) $wpdb->get_var( $wpdb->prepare(
        "SELECT user_nome FROM {$wpdb->prefix}rmbz_wallets WHERE user_telemovel = %s",
        $telemovel
    ) );
    rmbz_api_send_otp_email( $new_email, $otp, $nome_artista );

    return rmbz_api_ok( [
        'sent_to'    => rmbz_api_mask_email( $new_email ),
        'expires_in' => 15 * 60,
        'message'    => 'Código enviado. Verifica a tua caixa de entrada (e a pasta Spam).',
    ] );
}

/* ----------------------------------------------------------------------- */
/* VERIFY OTP                                                              */
/* ----------------------------------------------------------------------- */

function rmbz_api_handle_verify_profile_change( WP_REST_Request $request ) {
    $telemovel = (string) $request->get_param( 'rmbz_telemovel' );
    $otp_input = trim( (string) $request->get_param( 'otp' ) );

    if ( ! preg_match( '/^\d{6}$/', $otp_input ) ) {
        return rmbz_api_error( 'O código deve ter 6 dígitos.', 400, 'bad_otp_format' );
    }

    $transient = get_transient( 'rmbz_profile_otp_' . $telemovel );
    if ( ! $transient || empty( $transient['otp'] ) ) {
        return rmbz_api_error( 'Código expirado ou inexistente. Pede um novo.', 410, 'otp_expired' );
    }

    // Limite de tentativas (5 por OTP)
    $attempts = isset( $transient['attempts'] ) ? (int) $transient['attempts'] : 0;
    if ( $attempts >= 5 ) {
        delete_transient( 'rmbz_profile_otp_' . $telemovel );
        return rmbz_api_error( 'Demasiadas tentativas. Pede um novo código.', 429, 'too_many_attempts' );
    }

    if ( (string) $otp_input !== (string) $transient['otp'] ) {
        // Incrementar contador
        $transient['attempts'] = $attempts + 1;
        set_transient( 'rmbz_profile_otp_' . $telemovel, $transient, 15 * 60 );
        $remaining = max( 0, 5 - $transient['attempts'] );
        return rmbz_api_error(
            'Código incorrecto. Tentativas restantes: ' . $remaining,
            401, 'bad_otp'
        );
    }

    // Sucesso — efectivar mudança
    global $wpdb;
    $table = $wpdb->prefix . 'rmbz_wallets';

    $old_email = $wpdb->get_var( $wpdb->prepare(
        "SELECT user_email FROM {$table} WHERE user_telemovel = %s",
        $telemovel
    ) );
    $is_first_time = ( strpos( (string) $old_email, '@1mz.local' ) !== false );

    $wpdb->update(
        $table,
        [
            'user_email'     => $transient['email'],
            'user_provincia' => $transient['provincia'],
        ],
        [ 'user_telemovel' => $telemovel ],
        [ '%s', '%s' ],
        [ '%s' ]
    );

    if ( $is_first_time ) {
        $nome = $wpdb->get_var( $wpdb->prepare(
            "SELECT user_nome FROM {$table} WHERE user_telemovel = %s",
            $telemovel
        ) );
        if ( function_exists( 'rmbz_send_welcome_email' ) ) {
            rmbz_send_welcome_email( $transient['email'], $nome );
        }
        update_option( 'rmbz_show_welcome_' . $telemovel, 'yes' );
    }

    delete_transient( 'rmbz_profile_otp_' . $telemovel );

    return rmbz_api_ok( [
        'updated' => true,
        'message' => $is_first_time
            ? 'Email validado e perfil actualizado.'
            : 'Perfil actualizado com sucesso.',
    ] );
}

/* ----------------------------------------------------------------------- */
/* CANCEL                                                                  */
/* ----------------------------------------------------------------------- */

function rmbz_api_handle_cancel_profile_change( WP_REST_Request $request ) {
    $telemovel = (string) $request->get_param( 'rmbz_telemovel' );
    delete_transient( 'rmbz_profile_otp_' . $telemovel );
    return rmbz_api_ok( [ 'cancelled' => true ] );
}

/* ----------------------------------------------------------------------- */
/* CHANGE STATUS                                                           */
/* ----------------------------------------------------------------------- */

function rmbz_api_handle_profile_change_status( WP_REST_Request $request ) {
    $telemovel = (string) $request->get_param( 'rmbz_telemovel' );
    $transient = get_transient( 'rmbz_profile_otp_' . $telemovel );

    if ( ! $transient ) {
        return rmbz_api_ok( [ 'has_pending' => false ] );
    }

    return rmbz_api_ok( [
        'has_pending'      => true,
        'sent_to_masked'   => rmbz_api_mask_email( $transient['email'] ?? '' ),
        'attempts_left'    => max( 0, 5 - (int) ( $transient['attempts'] ?? 0 ) ),
    ] );
}

/* ----------------------------------------------------------------------- */
/* HELPERS                                                                 */
/* ----------------------------------------------------------------------- */

function rmbz_api_allowed_provincias() {
    return [
        'Maputo Cidade',
        'Maputo Província',
        'Gaza',
        'Inhambane',
        'Sofala',
        'Manica',
        'Tete',
        'Zambézia',
        'Nampula',
        'Cabo Delgado',
        'Niassa',
        'Diáspora (Exterior)',
    ];
}

function rmbz_api_mask_email( $email ) {
    if ( ! is_email( $email ) ) return '';
    $parts = explode( '@', $email );
    $local = $parts[0];
    $domain = $parts[1] ?? '';
    $visible = mb_substr( $local, 0, 2 );
    $masked = $visible . str_repeat( '*', max( 1, mb_strlen( $local ) - 2 ) );
    return $masked . '@' . $domain;
}

/**
 * [1.5.407] Email do código OTP reescrito ANTI-SPAM: código no assunto
 * (prática padrão dos grandes serviços — assuntos vagos tipo "Código de
 * Verificação" pontuam pior no Gmail), corpo completo e pessoal (quem
 * pediu, porquê, validade, referência ao site) em vez de 3 linhas com um
 * número solto — mensagens curtas só com um código para um destinatário
 * novo são um padrão clássico de spam/phishing para os filtros.
 */
function rmbz_api_send_otp_email( $email, $otp, $nome = '' ) {
    $site_name = get_bloginfo( 'name' );
    $site_url  = home_url( '/' );
    $subject   = $otp . ' é o teu código de confirmação — ' . $site_name;
    $nome_html = $nome !== '' ? esc_html( $nome ) : 'Artista';

    $body = "<p>Olá <strong>{$nome_html}</strong>,</p>"
          . "<p>Recebemos um pedido para ligar este endereço de email à tua conta de artista na plataforma "
          . "<strong>" . esc_html( $site_name ) . "</strong> (" . esc_html( $site_url ) . "). "
          . "Este passo é importante para receberes as novidades do teu projeto de videoclipe, contratos e pagamentos.</p>"
          . "<p>O teu código de confirmação é:</p>"
          . "<p style='text-align:center;'><span style='font-size:32px; letter-spacing:8px; font-weight:800; color:#f0b90b; "
          . "background:rgba(240,185,11,0.12); border:1px solid rgba(240,185,11,0.4); border-radius:12px; padding:12px 24px; display:inline-block;'>{$otp}</span></p>"
          . "<p>Escreve este código na página onde fizeste o pedido. É válido durante <strong>15 minutos</strong> e só funciona uma vez.</p>"
          . "<p style='font-size:13px;'>Se não foste tu que pediste esta ligação, podes ignorar este email com segurança — "
          . "sem o código, ninguém consegue ligar o email à conta.</p>";

    $tpl = get_option( 'rmbz_email_templates' );
    $sender_name = ! empty( $tpl['sender_name'] ) ? $tpl['sender_name'] : $site_name;
    $sender_email = is_email( $tpl['sender_email'] ?? '' ) ? $tpl['sender_email'] : get_option( 'admin_email' );

    if ( function_exists( 'rmbz_build_html_email' ) ) {
        $html_body = rmbz_build_html_email( $body, $sender_name, [ 'emoji' => '🔐', 'eyebrow' => 'Confirmação de email' ] );
        $headers = [
            'Content-Type: text/html; charset=UTF-8',
            'From: ' . $sender_name . ' <' . $sender_email . '>',
        ];
        wp_mail( $email, $subject, $html_body, $headers );
    } else {
        wp_mail( $email, $subject, strip_tags( str_replace( [ '</p>', '<br>' ], "\n", $body ) ) );
    }
}
