<?php
/**
 * [FEAT 1.6.29] 1MZ For Artists — Próximo Pagamento (projecção)
 *
 * Adiciona endpoint REST que o app consume para mostrar ao artista:
 *   - Saldo USD actual em royalties
 *   - Mínimo de levantamento configurado
 *   - Projecção de quando chega ao mínimo (com base na média mensal)
 *   - Receita média mensal dos últimos 3 meses
 *   - Última receita mensal
 *   - % de progresso até o mínimo (saldo / mínimo, capped a 100)
 *   - Dias estimados até atingir o mínimo
 *
 *   GET /wp-json/rmbz/v1/artist/next-payout
 *
 * Reutiliza:
 *   - rmbz_api_get_royalties_balance_usd() — saldo USD já existente
 *   - rmbz_get_exchange_rate() — taxa actual
 *   - rmbz_distro_ledger — histórico de receitas
 *
 * Não toca em controllers existentes.
 *
 * @package 1MZ_For_Artists
 * @since 1.6.29
 */

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

if ( ! defined( 'RMBZ_API_NEXTPAYOUT_VERSION' ) ) {
    define( 'RMBZ_API_NEXTPAYOUT_VERSION', '1.6.115.2' );
}

add_action( 'rest_api_init', 'rmbz_api_register_next_payout_routes' );

function rmbz_api_register_next_payout_routes() {
    $args = [
        'methods'             => 'GET',
        'callback'            => 'rmbz_api_handle_next_payout',
        'permission_callback' => 'rmbz_api_require_auth',
    ];

    // [FIX] A rota nunca correspondia: o app pedia `me/wallet/next-payout`
    // mas o servidor só registava `artist/next-payout`. Registamos os 3
    // caminhos para o mesmo callback:
    //   - wallet/next-payout    → canónico (alinhado com as outras rotas de wallet)
    //   - me/wallet/next-payout → compat com apps já instalados na loja
    //   - artist/next-payout    → caminho legado original
    register_rest_route( RMBZ_API_NAMESPACE, '/wallet/next-payout', $args );
    register_rest_route( RMBZ_API_NAMESPACE, '/me/wallet/next-payout', $args );
    register_rest_route( RMBZ_API_NAMESPACE, '/artist/next-payout', $args );
}


/**
 * Calcula receita média mensal nos últimos N meses (excluindo mês actual).
 * Devolve [ avg_per_month, last_month_amount, months_with_data, monthly => [ym => amount] ]
 */
function rmbz_api_get_monthly_revenue_summary( $telemovel, $months = 3 ) {
    global $wpdb;
    $t_ledger = $wpdb->prefix . 'rmbz_distro_ledger';

    if ( $wpdb->get_var( "SHOW TABLES LIKE '$t_ledger'" ) !== $t_ledger ) {
        return [
            'avg_per_month'     => 0.0,
            'last_month_amount' => 0.0,
            'months_with_data'  => 0,
            'has_any_history'   => false,
            'monthly'           => [],
        ];
    }

    // [FIX 1.6.115.1] Em vez de filtrar à partida pelos últimos 3 meses,
    // ir buscar TODO o histórico do artista (até 12 meses) e depois
    // calcular a média sobre os meses com receita real. Antes, se o
    // artista tinha receita em meses mais antigos mas zero nos últimos 3,
    // a média ficava 0 e a headline dizia "A começar" — desinformando.
    //
    // Também removi `AND reverted_at IS NULL` — essa coluna NÃO existe
    // em `rmbz_distro_ledger` (só existe em rmbz_distro_payouts). Estava
    // a causar erro SQL silencioso que devolvia query vazia.
    //
    // Considerar só receitas positivas (type pode ser 'credit' ou
    // 'distro_credit' — não filtramos por type para apanhar variantes).

    // Janela alargada: 12 meses excluindo o actual (incompleto)
    $end_ym   = date( 'Y-m', strtotime( '-1 month' ) );
    $start_ym = date( 'Y-m', strtotime( '-12 months' ) );

    $rows = $wpdb->get_results( $wpdb->prepare(
        "SELECT reporting_period, COALESCE(SUM(amount),0) AS total
           FROM $t_ledger
          WHERE artist_telemovel = %s
            AND reporting_period >= %s
            AND reporting_period <= %s
            AND reporting_period IS NOT NULL
            AND reporting_period != ''
            AND amount > 0
          GROUP BY reporting_period
          ORDER BY reporting_period DESC",
        $telemovel, $start_ym, $end_ym
    ) );

    $monthly = [];
    foreach ( $rows as $r ) {
        $monthly[ $r->reporting_period ] = (float) $r->total;
    }

    // Média = só dos últimos N meses, contando apenas meses com receita > 0.
    // Isto evita inflacionar a média ao incluir meses zero (quando o artista
    // ainda não estava activo).
    $recent_start = date( 'Y-m', strtotime( "-{$months} months" ) );
    $recent_values = [];
    foreach ( $monthly as $ym => $v ) {
        if ( $ym >= $recent_start && $ym <= $end_ym && $v > 0 ) {
            $recent_values[] = $v;
        }
    }
    $n_recent = count( $recent_values );

    if ( $n_recent > 0 ) {
        $avg = array_sum( $recent_values ) / $n_recent;
    } else {
        // Fallback: usar TODA a janela de 12 meses (só meses com receita)
        $all_positive = array_filter( $monthly, function ($v) { return $v > 0; } );
        $avg = count( $all_positive ) > 0
            ? array_sum( $all_positive ) / count( $all_positive )
            : 0.0;
    }

    $last = isset( $monthly[ $end_ym ] ) ? (float) $monthly[ $end_ym ] : 0.0;
    $has_any_history = ! empty( $monthly );

    return [
        'avg_per_month'     => round( $avg, 4 ),
        'last_month_amount' => round( $last, 4 ),
        'months_with_data'  => $n_recent,
        'has_any_history'   => $has_any_history,
        'monthly'           => $monthly,
    ];
}


/**
 * Lê o mínimo de levantamento (USD) — primeiro tenta a setting, depois usa $5.00 como default.
 */
function rmbz_api_get_min_payout_usd() {
    // Tentar várias chaves possíveis (algumas instalações usam nomes diferentes)
    $candidates = [
        'rmbz_min_payout_usd',
        'rmbz_royalties_min_payout',
        'rmbz_min_withdrawal_usd',
    ];
    foreach ( $candidates as $key ) {
        $v = (float) get_option( $key, 0 );
        if ( $v > 0 ) return $v;
    }
    return 5.00; // default conservador
}


/**
 * [1.6.321] Análise do Assistente (IA) sobre o próximo pagamento — narrativa
 * personalizada a partir dos FACTOS reais (nunca inventa números). Para todos
 * quando a IA está disponível (como os insights). Cache 12h (muda devagar).
 */
function rmbz_next_payout_ai_message( $tel, array $f ) {
    if ( ! function_exists( 'rmbz_ai_messages' ) ) {
        $p = dirname( __FILE__, 2 ) . '/ai/ai-client.php';
        if ( file_exists( $p ) ) require_once $p;
    }
    if ( ! function_exists( 'rmbz_ai_messages' ) ) return '';

    $cache_key = 'rmbz_npay_ai_' . md5(
        $tel . '|' . round( $f['balance_usd'], 1 ) . '|' . round( $f['avg'], 1 )
        . '|' . ( $f['ready_now'] ? 1 : 0 ) . '|' . date( 'Y-m-d' )
    );
    $cached = get_transient( $cache_key );
    if ( is_string( $cached ) ) return $cached;

    $facts = sprintf(
        "Saldo atual: %.2f USD (~%.0f MT). Mínimo para levantar: %.2f USD. Falta: %.2f USD. Já pode levantar: %s. "
        . "Média mensal de royalties: %.2f USD. Último mês: %.2f USD. Meses com dados: %d. "
        . "Estimativa até ao mínimo: %s. Total já recebido: %.2f USD em %d levantamento(s).",
        $f['balance_usd'], $f['balance_mt'], $f['min_payout'], $f['missing'], $f['ready_now'] ? 'sim' : 'não',
        $f['avg'], $f['last_month'], $f['months_with_data'],
        ( $f['days_to_min'] !== null ? ( '~' . $f['days_to_min'] . ' dias' ) : 'sem dados suficientes' ),
        $f['total_paid'], $f['payouts_count']
    );

    $profile = function_exists( 'rmbz_ai_artist_profile' ) ? rmbz_ai_artist_profile( $tel ) : '';

    $system = 'És o assistente de carreira da 1MZ Records (Moçambique). Falas português de Portugal (pt-PT), '
            . 'claro, honesto e motivador, como um manager. Explicas ao artista, em linguagem simples, como está o '
            . 'caminho até ao PRÓXIMO PAGAMENTO dos royalties e o que pode fazer para lá chegar mais depressa. '
            . 'REGRAS: usa APENAS os números dados; NUNCA inventes; não prometas resultados; sê realista. Os ganhos '
            . 'são em USD (royalties das plataformas), não confundir com a carteira. Responde em texto corrido curto '
            . '(~80 a 120 palavras), sem markdown nem listas.';

    $instruction = $profile . "FACTOS DO PRÓXIMO PAGAMENTO:\n" . $facts . "\n\n"
                 . 'Escreve uma análise pessoal: onde está, quanto falta e — ao ritmo atual — quando deve chegar, '
                 . 'mais 1 a 2 ações concretas e realistas para acelerar. Se ainda não há dados suficientes, diz com '
                 . 'honestidade e foca em começar a gerar streams.';

    $res = rmbz_ai_messages( $system, $instruction, [ 'max_tokens' => 320, 'temperature' => 0.7 ] );
    if ( empty( $res['ok'] ) ) return '';
    $msg = trim( $res['text'] );
    if ( $msg === '' ) return '';

    set_transient( $cache_key, $msg, 12 * HOUR_IN_SECONDS );
    return $msg;
}

/**
 * Handler principal: monta o objecto de projecção.
 */
function rmbz_api_handle_next_payout( WP_REST_Request $request ) {
    $tel = (string) $request->get_param( 'rmbz_telemovel' );

    // 1. Saldo actual em USD
    $balance_usd = function_exists( 'rmbz_api_get_royalties_balance_usd' )
        ? (float) rmbz_api_get_royalties_balance_usd( $tel )
        : 0.0;

    // 2. Mínimo de levantamento
    $min_payout = rmbz_api_get_min_payout_usd();

    // 3. Receita histórica (últimos 3 meses)
    $hist = rmbz_api_get_monthly_revenue_summary( $tel, 3 );

    // [1.6.115.2] Estatísticas de pagamentos (A + B)
    //   - total_paid: soma de tudo o que o artista já recebeu (KPI permanente)
    //   - last_payout: último pagamento (para mensagem pós-levantamento)
    global $wpdb;
    $t_payouts = $wpdb->prefix . 'rmbz_distro_payouts';
    $total_paid_usd = 0.0;
    $payouts_count = 0;
    $last_payout_at = null;
    $last_payout_amount_usd = 0.0;
    if ( $wpdb->get_var( "SHOW TABLES LIKE '$t_payouts'" ) === $t_payouts ) {
        $stats = $wpdb->get_row( $wpdb->prepare(
            "SELECT COALESCE(SUM(amount_usd), 0) AS total,
                    COUNT(*) AS n,
                    MAX(paid_at) AS last_at
               FROM $t_payouts
              WHERE artist_telemovel = %s
                AND status = 'completed'
                AND reverted_at IS NULL",
            $tel
        ) );
        if ( $stats ) {
            $total_paid_usd = (float) $stats->total;
            $payouts_count = (int) $stats->n;
            $last_payout_at = $stats->last_at;
        }
        if ( $last_payout_at ) {
            // Buscar o valor desse último pagamento
            $last_amount = $wpdb->get_var( $wpdb->prepare(
                "SELECT amount_usd FROM $t_payouts
                  WHERE artist_telemovel = %s
                    AND status = 'completed'
                    AND reverted_at IS NULL
               ORDER BY paid_at DESC
                  LIMIT 1",
                $tel
            ) );
            $last_payout_amount_usd = (float) $last_amount;
        }
    }

    // Calcular dias desde último pagamento (para a headline pós-levantamento)
    $days_since_last_payout = null;
    if ( $last_payout_at ) {
        $days_since_last_payout = (int) ( ( time() - strtotime( $last_payout_at ) ) / 86400 );
    }

    // 4. Projecção:
    //    - Se saldo já está acima do mínimo: pode levantar JÁ
    //    - Caso contrário, estima quanto falta e quantos meses (à média mensal)
    $missing_usd = max( 0.0, $min_payout - $balance_usd );
    $ready_now   = ( $balance_usd >= $min_payout && $min_payout > 0 );

    $months_to_min = null;
    $days_to_min   = null;
    if ( ! $ready_now ) {
        if ( $hist['avg_per_month'] > 0.01 ) {
            $months_to_min = $missing_usd / $hist['avg_per_month'];
            $days_to_min   = (int) round( $months_to_min * 30 );
        } else {
            // Sem histórico suficiente — não podemos prever
            $months_to_min = null;
            $days_to_min   = null;
        }
    }

    // 5. Progresso %
    $progress_pct = 0.0;
    if ( $min_payout > 0 ) {
        $progress_pct = min( 100.0, ( $balance_usd / $min_payout ) * 100.0 );
    }

    // 6. Mensagem amigável para mostrar ao artista
    //
    //    Ordem de prioridade das mensagens:
    //    1. Saldo ≥ mínimo  → "Já podes levantar!"
    //    2. Levantamento recente (≤30d) e saldo < mínimo → "Próximo ciclo"
    //       (mensagem reconfortante para não dar sensação de "voltei à estaca zero")
    //    3. Sem histórico nenhum + saldo 0 → "A começar"
    //    4. Sem média estimável → "A acumular"
    //    5. ≤30 dias estimados → "Quase lá!"
    //    6. ≤90 dias estimados → "A caminho"
    //    7. >90 dias → "A caminho" com motivação geral
    if ( $ready_now ) {
        $headline = '🎉 Já podes levantar!';
        $message  = sprintf( 'Tens $%s disponíveis. Vai à carteira para levantar.', number_format( $balance_usd, 2 ) );
    } elseif (
        $days_since_last_payout !== null
        && $days_since_last_payout <= 30
        && $last_payout_amount_usd > 0
    ) {
        // [1.6.115.2] Levantamento recente — mensagem positiva, não desmotivar
        $headline = '🎉 Próximo ciclo';
        $payout_date = date_i18n( 'd \d\e F', strtotime( $last_payout_at ) );
        if ( $days_to_min !== null && $days_to_min > 0 ) {
            $message = sprintf(
                'Acabaste de receber $%s em %s. Próximo levantamento estimado em ~%d dia%s.',
                number_format( $last_payout_amount_usd, 2 ),
                $payout_date,
                $days_to_min,
                $days_to_min === 1 ? '' : 's'
            );
        } else {
            $message = sprintf(
                'Acabaste de receber $%s em %s. Continua a acumular para o próximo ciclo!',
                number_format( $last_payout_amount_usd, 2 ),
                $payout_date
            );
        }
    } elseif ( ! $hist['has_any_history'] && $balance_usd <= 0 && $total_paid_usd <= 0 ) {
        $headline = 'A começar';
        $message  = 'Assim que as primeiras receitas chegarem, vamos mostrar uma estimativa.';
    } elseif ( $days_to_min === null ) {
        // Tem histórico mas média demasiado baixa para estimar dias
        $headline = 'A acumular';
        $message  = sprintf( 'Faltam $%s para o mínimo. Continua a divulgar a tua música!', number_format( $missing_usd, 2 ) );
    } elseif ( $days_to_min <= 30 ) {
        $headline = 'Quase lá!';
        $message  = sprintf( 'Faltam aproximadamente %d dia%s para o teu próximo pagamento.', $days_to_min, $days_to_min === 1 ? '' : 's' );
    } elseif ( $days_to_min <= 90 ) {
        $headline = 'A caminho';
        $message  = sprintf( '~%d dias para o próximo levantamento à média actual.', $days_to_min );
    } else {
        $headline = 'A caminho';
        $message  = 'Mais alguns meses para o próximo levantamento. Continua a divulgar a tua música!';
    }

    // 7. Taxa de câmbio (para equivalente em MT)
    $rate = function_exists( 'rmbz_get_exchange_rate' )
        ? (float) rmbz_get_exchange_rate()
        : 63.50;

    // 8. Formatar histórico mensal para o gráfico no app (12 meses, zeros incluídos).
    //    [FIX 1.6.115.1] `$hist['monthly']` já tem 12 meses (a função
    //    rmbz_api_get_monthly_revenue_summary foi alargada). Removido o
    //    fallback duplicado que tinha o mesmo bug do `reverted_at IS NULL`.
    $monthly_series = [];
    for ( $i = 11; $i >= 0; $i-- ) {
        $ym = date( 'Y-m', strtotime( "-{$i} months" ) );
        $val = isset( $hist['monthly'][ $ym ] ) ? (float) $hist['monthly'][ $ym ] : 0.0;
        $monthly_series[] = [
            'period' => $ym,
            'amount' => round( $val, 4 ),
        ];
    }

    // [1.6.321] Análise do Assistente (IA) — só quando a IA está disponível.
    // [1.6.362] E SÓ para quem tem o add-on de IA (VIP com IA). Antes verificava
    // apenas a chave global → o não-VIP recebia a análise de IA na mesma.
    $ai_message = '';
    $ai_enabled = function_exists( 'rmbz_ai_available' ) && rmbz_ai_available()
        && function_exists( 'rmbz_ai_user_is_vip' ) && rmbz_ai_user_is_vip( $tel );
    if ( $ai_enabled ) {
        $ai_message = rmbz_next_payout_ai_message( $tel, [
            'balance_usd'      => $balance_usd,
            'balance_mt'       => $balance_usd * $rate,
            'min_payout'       => $min_payout,
            'missing'          => $missing_usd,
            'ready_now'        => $ready_now,
            'avg'              => $hist['avg_per_month'],
            'last_month'       => $hist['last_month_amount'],
            'months_with_data' => $hist['months_with_data'],
            'days_to_min'      => $days_to_min,
            'total_paid'       => $total_paid_usd,
            'payouts_count'    => $payouts_count,
        ] );
    }

    return rmbz_api_ok( [
        '_api_version'        => RMBZ_API_NEXTPAYOUT_VERSION,

        // [1.6.321] Análise do Assistente (vazio se IA desligada/sem dados)
        'ai_message'          => $ai_message,
        'ai_enabled'          => ( $ai_enabled && $ai_message !== '' ),

        // Saldo actual
        'balance_usd'         => round( $balance_usd, 4 ),
        'balance_mt'          => round( $balance_usd * $rate, 2 ),
        'exchange_rate'       => round( $rate, 4 ),

        // Mínimo de levantamento
        'min_payout_usd'      => round( $min_payout, 2 ),
        'min_payout_mt'       => round( $min_payout * $rate, 2 ),

        // Progresso até mínimo
        'progress_pct'        => round( $progress_pct, 1 ),
        'ready_now'           => $ready_now,
        'missing_usd'         => round( $missing_usd, 4 ),

        // Histórico
        'avg_per_month_usd'   => $hist['avg_per_month'],
        'last_month_usd'      => $hist['last_month_amount'],
        'months_with_data'    => $hist['months_with_data'],

        // [1.6.115.2] Estatísticas de pagamentos
        'total_paid_usd'             => round( $total_paid_usd, 2 ),
        'total_paid_mt'              => round( $total_paid_usd * $rate, 2 ),
        'payouts_count'              => $payouts_count,
        'last_payout_at'             => $last_payout_at, // ISO datetime ou null
        'last_payout_amount_usd'     => round( $last_payout_amount_usd, 2 ),
        'days_since_last_payout'     => $days_since_last_payout,

        // Projecção
        'days_to_min'         => $days_to_min,         // null se não pode prever
        'months_to_min'       => $months_to_min !== null ? round( $months_to_min, 1 ) : null,

        // Mensagens prontas para mostrar
        'headline'            => $headline,
        'message'             => $message,

        // Série mensal para gráfico (12 meses)
        'monthly_series'      => $monthly_series,
    ] );
}
