<?php
/**
 * 1MZ For Artists — Sistema de Marcos/Conquistas
 *
 * Detecta automaticamente conquistas dos artistas e regista-as.
 * Cada marco é detectado UMA vez por artista (idempotente via UNIQUE
 * key). Categorias: catalog, audience, financial, time, community.
 *
 * Triggers:
 *   - WP-cron diário (varre todos os artistas)
 *   - Hooks em tempo real (release aprovado, levantamento pago, etc.)
 *   - Endpoint manual para admins forçarem recheck
 *
 * @package 1MZ_For_Artists
 * @since 1.6.55
 */

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

if ( ! defined( 'RMBZ_MILESTONES_VERSION' ) ) {
    define( 'RMBZ_MILESTONES_VERSION', '1.6.55' );
}

/* ============================================================================
 * SCHEMA
 * ============================================================================ */

function rmbz_milestones_maybe_install() {
    $stored = get_option( 'rmbz_milestones_schema_v', '0' );
    if ( version_compare( $stored, '1.0', '>=' ) ) return;

    global $wpdb;
    $charset_collate = $wpdb->get_charset_collate();
    $table = $wpdb->prefix . 'rmbz_artist_milestones';

    $sql = "CREATE TABLE $table (
        id bigint(20) NOT NULL AUTO_INCREMENT,
        artist_telemovel varchar(20) NOT NULL,
        milestone_key varchar(80) NOT NULL,
        category varchar(30) NOT NULL,
        achieved_value bigint(20) DEFAULT NULL,
        context_json text DEFAULT NULL,
        achieved_at datetime DEFAULT CURRENT_TIMESTAMP NOT NULL,
        acknowledged tinyint(1) DEFAULT 0 NOT NULL,
        PRIMARY KEY  (id),
        UNIQUE KEY uniq_artist_milestone (artist_telemovel, milestone_key),
        KEY idx_artist (artist_telemovel),
        KEY idx_category (category)
    ) ENGINE=InnoDB $charset_collate;";

    require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
    dbDelta( $sql );
    update_option( 'rmbz_milestones_schema_v', '1.0' );
}
add_action( 'admin_init', 'rmbz_milestones_maybe_install', 8 );
// [1.5.207] Também correr quando o plugin é carregado em qualquer contexto
// (REST API, AJAX, frontend) — para garantir que a tabela existe quando
// a app móvel chama /me/milestones, mesmo que o admin nunca tenha aberto
// o wp-admin desde que a feature foi ativada.
add_action( 'init', 'rmbz_milestones_maybe_install', 8 );

/* ============================================================================
 * CATÁLOGO DE MARCOS
 * ============================================================================
 *
 * Cada entrada:
 *   - key:        identificador único (não muda nunca)
 *   - category:   catalog | audience | financial | time | community
 *   - title:      texto curto mostrado no card
 *   - description: explicação (opcional, contexto da conquista)
 *   - icon:       identificador para o app escolher o ícone Material
 *   - threshold:  valor numérico (para os escalonados)
 *   - order_hint: ordem visual no app (números pequenos primeiro)
 *
 * IMPORTANTE: nunca remover entradas — só adicionar. Se um marco for
 * deprecado, marca-se `deprecated => true` em vez de apagar (preserva
 * histórico de quem já o atingiu).
 */
function rmbz_milestones_catalog() {
    static $cache = null;
    if ( $cache !== null ) return $cache;

    $cache = [
        // ─── Catálogo ───────────────────────────────────────────────────
        'first_release_submitted' => [
            'category' => 'catalog',
            'title'    => 'Primeiro release submetido',
            'description' => 'Enviaste o teu primeiro lançamento para revisão',
            'icon'     => 'send',
            'threshold' => 1,
            'order_hint' => 10,
        ],
        'first_release_live' => [
            'category' => 'catalog',
            'title'    => 'Primeiro release nas lojas',
            'description' => 'O teu primeiro release entrou nas plataformas',
            'icon'     => 'check_circle',
            'threshold' => 1,
            'order_hint' => 11,
        ],
        'first_ep' => [
            'category' => 'catalog',
            'title'    => 'Primeiro EP',
            'description' => 'Publicaste um release com 3 ou mais faixas',
            'icon'     => 'album',
            'threshold' => 3,
            'order_hint' => 12,
        ],
        'first_album' => [
            'category' => 'catalog',
            'title'    => 'Primeiro álbum',
            'description' => 'Publicaste um release com 8 ou mais faixas',
            'icon'     => 'album',
            'threshold' => 8,
            'order_hint' => 13,
        ],
        'releases_5'  => [ 'category' => 'catalog', 'title' => '5 releases publicados',  'icon' => 'library_music', 'threshold' => 5,  'order_hint' => 20 ],
        'releases_10' => [ 'category' => 'catalog', 'title' => '10 releases publicados', 'icon' => 'library_music', 'threshold' => 10, 'order_hint' => 21 ],
        'releases_25' => [ 'category' => 'catalog', 'title' => '25 releases publicados', 'icon' => 'library_music', 'threshold' => 25, 'order_hint' => 22 ],
        'releases_50' => [ 'category' => 'catalog', 'title' => '50 releases publicados', 'icon' => 'library_music', 'threshold' => 50, 'order_hint' => 23 ],

        // ─── Audiência ──────────────────────────────────────────────────
        'streams_1k'   => [ 'category' => 'audience', 'title' => '1.000 streams',     'icon' => 'headphones', 'threshold' => 1000,    'order_hint' => 30 ],
        'streams_10k'  => [ 'category' => 'audience', 'title' => '10.000 streams',    'icon' => 'headphones', 'threshold' => 10000,   'order_hint' => 31 ],
        'streams_100k' => [ 'category' => 'audience', 'title' => '100.000 streams',   'icon' => 'headphones', 'threshold' => 100000,  'order_hint' => 32 ],
        'streams_1m'   => [ 'category' => 'audience', 'title' => '1 milhão de streams','icon' => 'headphones', 'threshold' => 1000000, 'order_hint' => 33 ],

        // ─── Financeiro ─────────────────────────────────────────────────
        'first_payment' => [
            'category' => 'financial',
            'title'    => 'Primeiro pagamento',
            'description' => 'Recebeste o teu primeiro depósito',
            'icon'     => 'attach_money',
            'threshold' => 1,
            'order_hint' => 40,
        ],
        'earnings_1k'   => [ 'category' => 'financial', 'title' => '1.000 MT acumulados',   'icon' => 'savings', 'threshold' => 1000,    'order_hint' => 41 ],
        'earnings_10k'  => [ 'category' => 'financial', 'title' => '10.000 MT acumulados',  'icon' => 'savings', 'threshold' => 10000,   'order_hint' => 42 ],
        'earnings_100k' => [ 'category' => 'financial', 'title' => '100.000 MT acumulados', 'icon' => 'savings', 'threshold' => 100000,  'order_hint' => 43 ],

        // ─── Tempo ──────────────────────────────────────────────────────
        'tenure_1m'  => [ 'category' => 'time', 'title' => '1 mês como artista 1MZ',   'icon' => 'cake', 'threshold' => 30,  'order_hint' => 50 ],
        'tenure_6m'  => [ 'category' => 'time', 'title' => '6 meses como artista 1MZ', 'icon' => 'cake', 'threshold' => 180, 'order_hint' => 51 ],
        'tenure_1y'  => [ 'category' => 'time', 'title' => '1 ano como artista 1MZ',   'icon' => 'cake', 'threshold' => 365, 'order_hint' => 52 ],
        'tenure_2y'  => [ 'category' => 'time', 'title' => '2 anos como artista 1MZ',  'icon' => 'cake', 'threshold' => 730, 'order_hint' => 53 ],

        // ─── Comunidade ─────────────────────────────────────────────────
        'first_split_accepted' => [
            'category' => 'community',
            'title'    => 'Primeira colaboração',
            'description' => 'Um split que criaste foi aceite por um colaborador',
            'icon'     => 'group',
            'threshold' => 1,
            'order_hint' => 60,
        ],
        'first_referral' => [
            'category' => 'community',
            'title'    => 'Primeiro amigo convidado',
            'description' => 'Trouxeste mais alguém para a plataforma',
            'icon'     => 'person_add',
            'threshold' => 1,
            'order_hint' => 61,
        ],
        'referrals_5' => [ 'category' => 'community', 'title' => '5 amigos convidados', 'icon' => 'people_alt', 'threshold' => 5, 'order_hint' => 62 ],
    ];

    return $cache;
}

/* ============================================================================
 * DETECÇÃO — chama por artista, regista marcos atingidos
 * ============================================================================ */

/**
 * Verifica todos os marcos para um artista. Idempotente —
 * marcos já atingidos não voltam a ser inseridos.
 *
 * @param string $telemovel
 * @return array Lista de keys de marcos NOVOS atingidos nesta chamada.
 */
function rmbz_milestones_check_artist( $telemovel ) {
    global $wpdb;

    if ( empty( $telemovel ) ) return [];

    $catalog = rmbz_milestones_catalog();
    $table   = $wpdb->prefix . 'rmbz_artist_milestones';

    // 1. Quais já tem atingidos?
    $already = $wpdb->get_col( $wpdb->prepare(
        "SELECT milestone_key FROM $table WHERE artist_telemovel = %s",
        $telemovel
    ) );
    $already_set = array_flip( $already );

    // 2. Carregar todas as métricas que precisamos uma vez só
    $metrics = rmbz_milestones_compute_metrics( $telemovel );

    // 3. Para cada marco, ver se atingiu
    $new_keys = [];
    foreach ( $catalog as $key => $def ) {
        if ( isset( $already_set[ $key ] ) ) continue;

        $hit = rmbz_milestones_check_one( $key, $def, $metrics );
        if ( $hit === false ) continue;

        // INSERT IGNORE para o caso raro de race condition
        $inserted = $wpdb->query( $wpdb->prepare(
            "INSERT IGNORE INTO $table
             (artist_telemovel, milestone_key, category, achieved_value, context_json)
             VALUES (%s, %s, %s, %d, %s)",
            $telemovel,
            $key,
            $def['category'],
            (int) ( $hit['value'] ?? 0 ),
            wp_json_encode( $hit['context'] ?? [] )
        ) );

        if ( $inserted ) {
            $new_keys[] = $key;
        }
    }

    // 4. Push notification + entrada no histórico (via hook)
    if ( ! empty( $new_keys ) ) {
        do_action( 'rmbz_milestones_achieved', $telemovel, $new_keys );
    }

    return $new_keys;
}

/**
 * Calcula todas as métricas que algum marco pode precisar.
 * Centralizado para evitar 20 queries por artista.
 */
function rmbz_milestones_compute_metrics( $telemovel ) {
    global $wpdb;

    $metrics = [];

    // Releases por status
    $rel_t = $wpdb->prefix . 'rmbz_distro_releases';
    $metrics['releases_submitted'] = (int) $wpdb->get_var( $wpdb->prepare(
        "SELECT COUNT(*) FROM $rel_t
         WHERE artist_telemovel = %s
           AND status IN ('pendente','live','distribuido','taken_down','takedown_requested','returned','rejected')",
        $telemovel
    ) );
    $metrics['releases_live'] = (int) $wpdb->get_var( $wpdb->prepare(
        "SELECT COUNT(*) FROM $rel_t
         WHERE artist_telemovel = %s
           AND status IN ('live','distribuido')",
        $telemovel
    ) );

    // Maior número de faixas num release live
    $trk_t = $wpdb->prefix . 'rmbz_distro_tracks';
    $metrics['max_tracks_in_release'] = (int) $wpdb->get_var( $wpdb->prepare(
        "SELECT MAX(c) FROM (
            SELECT COUNT(t.id) AS c
            FROM $trk_t t
            INNER JOIN $rel_t r ON r.id = t.release_id
            WHERE r.artist_telemovel = %s
              AND r.status IN ('live','distribuido')
            GROUP BY t.release_id
         ) sub",
        $telemovel
    ) );

    // Stats agregados (streams + earnings)
    $stats_t = $wpdb->prefix . 'rmbz_distro_stats';
    $stats = $wpdb->get_row( $wpdb->prepare(
        "SELECT total_streams, total_earnings, withdrawn_amount
         FROM $stats_t WHERE artist_telemovel = %s LIMIT 1",
        $telemovel
    ) );
    $metrics['total_streams']  = $stats ? (int)   $stats->total_streams  : 0;
    $metrics['total_earnings'] = $stats ? (float) $stats->total_earnings : 0.0;

    // Já recebeu algum pagamento? (transação positiva na wallet)
    $wt_t = $wpdb->prefix . 'rmbz_wallet_transactions';
    $metrics['received_any_payment'] = (int) $wpdb->get_var( $wpdb->prepare(
        "SELECT COUNT(*) FROM $wt_t
         WHERE user_telemovel = %s AND amount > 0",
        $telemovel
    ) );

    // Splits aceites
    $sa_t = $wpdb->prefix . 'rmbz_splits_audit';
    $metrics['splits_accepted_in_own_releases'] = (int) $wpdb->get_var( $wpdb->prepare(
        "SELECT COUNT(*) FROM $sa_t s
         INNER JOIN $rel_t r ON r.id = s.release_id
         WHERE r.artist_telemovel = %s
           AND LOWER(s.action) LIKE '%accept%'",
        $telemovel
    ) );

    // Tempo como artista (dias desde criação aproximada)
    // Usa MIN(transaction_date) como proxy (mesma heurística do histórico)
    $created_at = $wpdb->get_var( $wpdb->prepare(
        "SELECT MIN(transaction_date) FROM $wt_t WHERE user_telemovel = %s",
        $telemovel
    ) );
    if ( ! $created_at ) {
        $created_at = $wpdb->get_var( $wpdb->prepare(
            "SELECT last_updated FROM {$wpdb->prefix}rmbz_wallets WHERE user_telemovel = %s",
            $telemovel
        ) );
    }
    $metrics['days_as_artist'] = $created_at
        ? max( 0, (int) floor( ( time() - strtotime( $created_at ) ) / 86400 ) )
        : 0;

    // Referrals
    $w_t = $wpdb->prefix . 'rmbz_wallets';
    $metrics['referrals_count'] = (int) $wpdb->get_var( $wpdb->prepare(
        "SELECT COUNT(*) FROM $w_t WHERE referred_by = %s",
        $telemovel
    ) );

    return $metrics;
}

/**
 * Verifica um marco contra as métricas. Devolve `false` se não atingiu,
 * ou um array `['value' => N, 'context' => [...]]` se atingiu.
 */
function rmbz_milestones_check_one( $key, $def, $metrics ) {
    switch ( $key ) {
        case 'first_release_submitted':
            return $metrics['releases_submitted'] >= 1
                ? [ 'value' => $metrics['releases_submitted'] ] : false;
        case 'first_release_live':
            return $metrics['releases_live'] >= 1
                ? [ 'value' => $metrics['releases_live'] ] : false;
        case 'first_ep':
            return $metrics['max_tracks_in_release'] >= 3
                ? [ 'value' => $metrics['max_tracks_in_release'] ] : false;
        case 'first_album':
            return $metrics['max_tracks_in_release'] >= 8
                ? [ 'value' => $metrics['max_tracks_in_release'] ] : false;
        case 'releases_5':
        case 'releases_10':
        case 'releases_25':
        case 'releases_50':
            return $metrics['releases_live'] >= $def['threshold']
                ? [ 'value' => $metrics['releases_live'] ] : false;

        case 'streams_1k':
        case 'streams_10k':
        case 'streams_100k':
        case 'streams_1m':
            return $metrics['total_streams'] >= $def['threshold']
                ? [ 'value' => $metrics['total_streams'] ] : false;

        case 'first_payment':
            return $metrics['received_any_payment'] >= 1
                ? [ 'value' => $metrics['received_any_payment'] ] : false;
        case 'earnings_1k':
        case 'earnings_10k':
        case 'earnings_100k':
            return $metrics['total_earnings'] >= $def['threshold']
                ? [ 'value' => (int) $metrics['total_earnings'] ] : false;

        case 'tenure_1m':
        case 'tenure_6m':
        case 'tenure_1y':
        case 'tenure_2y':
            return $metrics['days_as_artist'] >= $def['threshold']
                ? [ 'value' => $metrics['days_as_artist'] ] : false;

        case 'first_split_accepted':
            return $metrics['splits_accepted_in_own_releases'] >= 1
                ? [ 'value' => $metrics['splits_accepted_in_own_releases'] ] : false;
        case 'first_referral':
            return $metrics['referrals_count'] >= 1
                ? [ 'value' => $metrics['referrals_count'] ] : false;
        case 'referrals_5':
            return $metrics['referrals_count'] >= 5
                ? [ 'value' => $metrics['referrals_count'] ] : false;
    }
    return false;
}

/* ============================================================================
 * CRON DIÁRIO — varre todos os artistas activos
 * ============================================================================ */

function rmbz_milestones_ensure_cron_scheduled() {
    if ( ! wp_next_scheduled( 'rmbz_milestones_daily_check' ) ) {
        $next = strtotime( 'tomorrow 04:30' ); // 04:30 — depois de outros crons
        wp_schedule_event( $next, 'daily', 'rmbz_milestones_daily_check' );
    }
}
add_action( 'admin_init', 'rmbz_milestones_ensure_cron_scheduled' );

function rmbz_milestones_run_daily_check() {
    global $wpdb;

    // Varre artistas com pelo menos uma transação OU um release
    // (utilizadores fantasma sem actividade não interessam)
    $artists = $wpdb->get_col(
        "SELECT DISTINCT user_telemovel
         FROM {$wpdb->prefix}rmbz_wallets
         WHERE is_banned = 0"
    );

    if ( ! $artists ) return;

    foreach ( $artists as $tel ) {
        rmbz_milestones_check_artist( (string) $tel );
        // Pequena pausa para não bater a DB se houverem milhares de users
        usleep( 50000 ); // 50ms
    }
}
add_action( 'rmbz_milestones_daily_check', 'rmbz_milestones_run_daily_check' );

/* ============================================================================
 * HOOKS — detecção em tempo real depois de eventos relevantes
 * ============================================================================ */

/**
 * Re-corre o check para o artista do release quando o status muda.
 * Hooked em `rmbz_distro_status_changed` que é disparado pelo lifecycle.
 */
function rmbz_milestones_on_release_status_changed( $release_id, $from_status = null, $to_status = null ) {
    global $wpdb;
    $tel = $wpdb->get_var( $wpdb->prepare(
        "SELECT artist_telemovel FROM {$wpdb->prefix}rmbz_distro_releases WHERE id = %d",
        (int) $release_id
    ) );
    if ( $tel ) {
        rmbz_milestones_check_artist( (string) $tel );
    }
}
add_action( 'rmbz_distro_status_changed', 'rmbz_milestones_on_release_status_changed', 20, 3 );

/**
 * Re-corre o check depois de qualquer transação na wallet (depósito,
 * levantamento, ajuste, royalty).
 */
function rmbz_milestones_on_wallet_changed( $telemovel ) {
    if ( ! empty( $telemovel ) ) {
        rmbz_milestones_check_artist( (string) $telemovel );
    }
}
add_action( 'rmbz_wallet_transaction_added', 'rmbz_milestones_on_wallet_changed', 20, 1 );

/**
 * Re-corre depois de um split ser aceite.
 */
function rmbz_milestones_on_split_accepted( $track_id ) {
    global $wpdb;
    $tel = $wpdb->get_var( $wpdb->prepare(
        "SELECT r.artist_telemovel
         FROM {$wpdb->prefix}rmbz_distro_tracks t
         INNER JOIN {$wpdb->prefix}rmbz_distro_releases r ON r.id = t.release_id
         WHERE t.id = %d",
        (int) $track_id
    ) );
    if ( $tel ) {
        rmbz_milestones_check_artist( (string) $tel );
    }
}
add_action( 'rmbz_split_invite_accepted', 'rmbz_milestones_on_split_accepted', 20, 1 );

/* ============================================================================
 * PUSH NOTIFICATION + HISTÓRICO (ao desbloquear)
 * ============================================================================ */

function rmbz_milestones_notify_artist( $telemovel, $new_keys ) {
    if ( empty( $new_keys ) ) return;
    $catalog = rmbz_milestones_catalog();

    // Apenas notificar do PRIMEIRO marco da batch (evitar spam se 5
    // marcos forem desbloqueados de uma vez no primeiro check).
    $first_key = $new_keys[0];
    $def = $catalog[ $first_key ] ?? null;
    if ( ! $def ) return;

    $title = '🏆 Nova conquista!';
    $body  = $def['title'];
    if ( count( $new_keys ) > 1 ) {
        $body .= ' (e mais ' . ( count( $new_keys ) - 1 ) . ')';
    }

    // Push (se a função existir — depende do plugin push estar activo)
    if ( function_exists( 'rmbz_push_send_to_telemovel' ) ) {
        rmbz_push_send_to_telemovel( $telemovel, $title, $body, [
            'type'         => 'milestone',
            'milestone_key'=> $first_key,
            'deep_link'    => 'milestones',
        ] );
    }

    // Notificação in-app (tabela rmbz_notifications) se a função existir
    if ( function_exists( 'rmbz_notifications_insert' ) ) {
        rmbz_notifications_insert( $telemovel, [
            'type'     => 'milestone_unlocked',
            'severity' => 'success',
            'title'    => $title,
            'body'     => $body,
        ] );
    }
}
add_action( 'rmbz_milestones_achieved', 'rmbz_milestones_notify_artist', 10, 2 );
