<?php
/**
 * 1MZ Music Player — App Config / Permissões
 *
 * GET /1mzmusic/v1/app/config  (público — primeiro endpoint no arranque)
 *
 * É a "fonte da verdade" que o app lê para se configurar:
 *   - version       → forçar atualização (ok / soft_update / force_update / blocked)
 *   - access        → gate de acesso ao app (open / account_required / blocked)
 *   - features      → add-ons que o app pode usar e quais exigem conta
 *   - message       → aviso global a mostrar no app
 *
 * Tudo é gerido no admin do WordPress (ver mp-admin.php).
 *
 * @package 1MZ_Music_Player
 */

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

/** Catálogo de funções/add-ons que o plugin controla no app. */
function mp_feature_catalog() {
    return [
        'youtube_addon'    => 'Add-on do YouTube',
        'offline_download' => 'Download offline',
        'lyrics'           => 'Letras sincronizadas',
        'lyrics_editor'    => 'Editor de letras',
        'cover_zoom'       => 'Zoom na capa',
        'equalizer'        => 'Equalizador',
        'audio_boost'      => '1MZ Boost (qualidade IA)',
        'studio'           => 'Estúdio 1MZ (efeitos)',
        'ai_shuffle'       => 'Aleatório com IA',
        'sponsored'        => 'Músicas Patrocinadas (ganhar $)',
        'resume_playback'  => 'Continuar de onde parou',
        'ai_assistant'     => 'Assistente IA',
    ];
}

/** Sub-texto mostrado no paywall por função (descrição curta). */
function mp_feature_subtitles() {
    return [
        'youtube_addon'    => 'Importa por link e ouve sem net',
        'offline_download' => 'Guarda e ouve sem internet',
        'lyrics'           => 'Letra sincronizada com a música',
        'lyrics_editor'    => 'Edita/cola a letra e afina o sync',
        'cover_zoom'       => 'Aproxima a capa com dois dedos',
        'equalizer'        => '10 bandas e som à tua medida',
        'audio_boost'      => 'IA no telemóvel melhora cada música',
        'studio'           => 'Eco, reverb, estéreo largo, graves+',
        'ai_shuffle'       => 'A Assistente escolhe a ordem por ti',
        'sponsored'        => 'Ouve faixas patrocinadas e ganha em dólar',
        'resume_playback'  => 'Volta onde paraste, em qualquer lado',
        'ai_assistant'     => 'Traduz letras e recomenda músicas',
    ];
}

/**
 * Estado de cada função: enabled (ligada), requires_account (precisa de conta)
 * e vip_only (só desbloqueia com VIP). Lido das options, com defaults sãos.
 */
function mp_get_features() {
    $saved = get_option( 'mp_features', [] );
    if ( ! is_array( $saved ) ) {
        $saved = [];
    }
    $subs = mp_feature_subtitles();
    $out = [];
    foreach ( mp_feature_catalog() as $key => $label ) {
        $cfg = isset( $saved[ $key ] ) && is_array( $saved[ $key ] ) ? $saved[ $key ] : [];
        $out[] = [
            'key'              => $key,
            'label'            => $label,
            'subtitle'         => $subs[ $key ] ?? '',
            'enabled'          => isset( $cfg['enabled'] ) ? (bool) $cfg['enabled'] : true,
            'requires_account' => isset( $cfg['requires_account'] ) ? (bool) $cfg['requires_account'] : false,
            'vip_only'         => isset( $cfg['vip_only'] ) ? (bool) $cfg['vip_only'] : false,
        ];
    }
    return $out;
}

/** Lista (keys) das funções que exigem conta e estão ligadas. */
function mp_account_gated_features() {
    $keys = [];
    foreach ( mp_get_features() as $f ) {
        if ( $f['enabled'] && $f['requires_account'] ) {
            $keys[] = $f['key'];
        }
    }
    return $keys;
}

/** Lista (keys) das funções que só o VIP desbloqueia e estão ligadas. */
function mp_vip_only_features() {
    $keys = [];
    foreach ( mp_get_features() as $f ) {
        if ( $f['enabled'] && $f['vip_only'] ) {
            $keys[] = $f['key'];
        }
    }
    return $keys;
}

/** Lê uma option de texto (linhas/vírgulas) numa lista limpa, sem repetidos. */
function mp_list_option( $key, $upper = false ) {
    $raw   = (string) get_option( $key, '' );
    $parts = preg_split( '/[\r\n,]+/', $raw );
    $out   = [];
    foreach ( (array) $parts as $p ) {
        $p = trim( $p );
        if ( $p === '' ) {
            continue;
        }
        $out[] = $upper ? strtoupper( $p ) : $p;
    }
    return array_values( array_unique( $out ) );
}

/** Regras próprias do add-on YouTube (geridas no admin). */
function mp_youtube_rules() {
    return [
        'blocked_countries' => mp_list_option( 'mp_yt_blocked_countries', true ),
        'blocked_artists'   => mp_list_option( 'mp_yt_blocked_artists' ),
        'blocked_keywords'  => mp_list_option( 'mp_yt_blocked_keywords' ),
        // Free caches only this bounded prefix; a complete file always requires VIP.
        'prebuffer_kb'      => min( 4096, max( 128, (int) get_option( 'mp_yt_prebuffer_kb', 768 ) ) ),
        'resolve_retries'   => min( 5, max( 1, (int) get_option( 'mp_yt_resolve_retries', 3 ) ) ),
        'offline_vip_only'  => true,
    ];
}

/** Configuração dos pacotes VIP (gerida no admin) + benefícios para o paywall. */
function mp_vip_config() {
    $currency  = (string) get_option( 'mp_vip_currency', '$' );
    $monthly   = (string) get_option( 'mp_vip_monthly', '2.99' );
    $annual    = (string) get_option( 'mp_vip_annual', '19.99' );
    $per_month = (string) get_option( 'mp_vip_annual_permonth', '1.67' );
    $savings   = (int) get_option( 'mp_vip_savings', 44 );

    // Benefícios: "sem anúncios" + cada função marcada como Só VIP.
    $benefits = [ [
        'key'      => 'no_ads',
        'title'    => 'Sem anúncios',
        'subtitle' => 'Para sempre, em todo o app',
    ] ];
    $subs = mp_feature_subtitles();
    foreach ( mp_get_features() as $f ) {
        if ( $f['enabled'] && $f['vip_only'] ) {
            $benefits[] = [
                'key'      => $f['key'],
                'title'    => $f['label'],
                'subtitle' => $subs[ $f['key'] ] ?? '',
            ];
        }
    }

    return [
        'enabled'          => (bool) get_option( 'mp_vip_enabled', true ),
        'currency'         => $currency,
        'monthly_price'    => $monthly,
        'annual_price'     => $annual,
        'annual_per_month' => $per_month,
        'savings_percent'  => $savings,
        'cta_url'          => (string) get_option( 'mp_vip_cta', '' ),
        'benefits'         => $benefits,
    ];
}

/** Resposta de version-check para um version_code do cliente. */
function mp_build_version( $client_code ) {
    $min    = (int) get_option( 'mp_min_version_code', 0 );
    $latest = (int) get_option( 'mp_latest_version_code', 0 );
    $emergency = (bool) get_option( 'mp_version_blocked', false );

    $status = 'ok';
    if ( $emergency ) {
        $status = 'blocked';
    } elseif ( $client_code > 0 && $min > 0 && $client_code < $min ) {
        $status = 'force_update';
    } elseif ( $client_code > 0 && $latest > 0 && $client_code < $latest ) {
        $status = 'soft_update';
    }

    return [
        'status'              => $status,
        'latest_version'      => (string) get_option( 'mp_latest_version', '' ),
        'latest_version_code' => $latest,
        'min_version_code'    => $min,
        'store_url'           => (string) get_option( 'mp_store_url', '' ),
        'force_message'       => (string) get_option( 'mp_force_message', 'É necessário atualizar o app para continuar.' ),
    ];
}

add_action( 'rest_api_init', 'mp_register_config_routes' );

function mp_register_config_routes() {
    register_rest_route( MP_API_NAMESPACE, '/app/config', [
        'methods'             => 'GET',
        'callback'            => 'mp_handle_app_config',
        'permission_callback' => '__return_true',
        'args' => [
            'version_code' => [ 'type' => 'integer', 'default' => 0 ],
            'platform'     => [ 'type' => 'string',  'default' => 'android' ],
        ],
    ] );
    // Anúncios premiados: ver anúncio → encher o progresso → desbloquear dias VIP.
    register_rest_route( MP_API_NAMESPACE, '/ads/reward', [
        [
            'methods'             => 'GET',
            'callback'            => 'mp_handle_ads_reward_state',
            'permission_callback' => '__return_true',
        ],
        [
            'methods'             => 'POST',
            'callback'            => 'mp_handle_ads_reward_hit',
            'permission_callback' => '__return_true',
        ],
    ] );
}

/** Estado do progresso de anúncios premiados de uma conta. */
function mp_ads_reward_state( $aid ) {
    return [
        'progress' => (int) get_option( 'mp_adsrew_prog_' . $aid, 0 ),
        'target'   => max( 1, (int) get_option( 'mp_ads_rew_target', 10 ) ),
        'days'     => max( 1, (int) get_option( 'mp_ads_rew_days', 3 ) ),
        'enabled'  => (bool) get_option( 'mp_ads_enabled', 0 ) && '' !== (string) get_option( 'mp_ads_rew_id', '' ),
        'cloud_audio_allowed' => (bool) get_option( 'mp_ads_rew_cloud_audio', 0 ),
    ];
}

/** GET /ads/reward — o app pergunta o progresso atual. */
function mp_handle_ads_reward_state( WP_REST_Request $request ) {
    $row = mp_account_from_request( $request );
    if ( ! $row ) {
        return rmbz_api_error( 'Inicia sessão.', 401, 'unauthorized' );
    }
    return rmbz_api_ok( mp_ads_reward_state( (int) $row->id ) );
}

/**
 * POST /ads/reward — o utilizador VIU um anúncio premiado até ao fim. Cada
 * visualização enche o progresso; ao completar, desbloqueia dias VIP. Este VIP
 * sincroniza dados; o envio de áudio só é incluído quando o admin o autorizar.
 * Anti-abuso: intervalo mínimo entre recompensas + teto diário por conta.
 */
function mp_handle_ads_reward_hit( WP_REST_Request $request ) {
    $row = mp_account_from_request( $request );
    if ( ! $row ) {
        return rmbz_api_error( 'Inicia sessão.', 401, 'unauthorized' );
    }
    $aid   = (int) $row->id;
    $state = mp_ads_reward_state( $aid );
    if ( ! $state['enabled'] ) {
        return rmbz_api_error( 'Recompensas indisponíveis.', 403, 'disabled' );
    }

    $now = time();
    // Um anúncio premiado dura 15–30s: pedidos mais rápidos que 15s são impossíveis.
    $last = (int) get_option( 'mp_adsrew_last_' . $aid, 0 );
    if ( $now - $last < 15 ) {
        return rmbz_api_ok( $state + [ 'granted_days' => 0, 'ignored' => true ] );
    }
    // Teto diário (anti-farm).
    $daily_cap = max( 1, (int) get_option( 'mp_ads_rew_daily', 20 ) );
    $today     = current_time( 'Y-m-d' );
    $day       = get_option( 'mp_adsrew_day_' . $aid, [] );
    $count     = ( is_array( $day ) && ( $day['d'] ?? '' ) === $today ) ? (int) $day['n'] : 0;
    if ( $count >= $daily_cap ) {
        return rmbz_api_ok( $state + [ 'granted_days' => 0, 'capped' => true ] );
    }

    update_option( 'mp_adsrew_last_' . $aid, $now, false );
    update_option( 'mp_adsrew_day_' . $aid, [ 'd' => $today, 'n' => $count + 1 ], false );

    $progress = $state['progress'] + 1;
    $granted  = 0;
    if ( $progress >= $state['target'] ) {
        $progress = 0;
        $granted  = $state['days'];
        // Estende o VIP a partir de agora ou do fim do VIP atual (o que for maior).
        global $wpdb;
        $tbl  = $wpdb->prefix . 'mp_accounts';
        $acct = $wpdb->get_row( $wpdb->prepare(
            "SELECT is_vip, vip_until, vip_source, vip_full_until FROM {$tbl} WHERE id = %d",
            $aid
        ) );
        $lifetime = $acct && (int) $acct->is_vip === 1 && empty( $acct->vip_until );
        if ( ! $lifetime ) {
            $active = $acct && mp_vip_is_active( $acct );
            $source = $acct ? mp_vip_source( $acct ) : 'rewarded';
            $base = ( $active && $acct->vip_until )
                ? strtotime( $acct->vip_until ) : $now;
            $full_until = ( $acct && ! empty( $acct->vip_full_until ) ) ? $acct->vip_full_until : null;
            if ( $active && in_array( $source, [ 'paid', 'admin', 'legacy' ], true ) ) {
                $source = 'mixed';
                if ( empty( $full_until ) && ! empty( $acct->vip_until ) ) {
                    $full_until = $acct->vip_until;
                }
            } elseif ( ! $active ) {
                $source = 'rewarded';
                $full_until = null;
            }
            $wpdb->update( $tbl, [
                'is_vip'    => 1,
                'vip_until' => gmdate( 'Y-m-d H:i:s', $base + $granted * 86400 ),
                'vip_source' => $source,
                'vip_full_until' => $full_until,
            ], [ 'id' => $aid ] );
        }
    }
    update_option( 'mp_adsrew_prog_' . $aid, $progress, false );

    $state['progress'] = $progress;
    return rmbz_api_ok( $state + [ 'granted_days' => $granted ] );
}

/** Formatos de áudio geríveis + o nível de cada um (off|free|account|vip). */
function mp_audio_format_keys() {
    return [ 'mp3', 'aac', 'flac', 'ogg', 'wav', 'wma', 'alac', 'midi', 'amr' ];
}
function mp_audio_formats() {
    $saved = (array) get_option( 'mp_audio_formats', [] );
    $out   = [];
    foreach ( mp_audio_format_keys() as $k ) {
        $v = isset( $saved[ $k ] ) ? (string) $saved[ $k ] : 'free';
        $out[ $k ] = in_array( $v, [ 'off', 'free', 'account', 'vip' ], true ) ? $v : 'free';
    }
    return $out;
}

function mp_handle_app_config( WP_REST_Request $request ) {
    $client_code = max( 0, (int) $request->get_param( 'version_code' ) );

    $access = get_option( 'mp_access_gate', 'open' );
    if ( ! in_array( $access, [ 'open', 'account_required', 'blocked' ], true ) ) {
        $access = 'open';
    }

    $message_text = trim( (string) get_option( 'mp_message_text', '' ) );

    $data = [
        'version' => mp_build_version( $client_code ),
        'access'  => [
            'mode'    => $access, // open | account_required | blocked
            'message' => (string) get_option( 'mp_access_message', '' ),
        ],
        'features' => mp_get_features(),
        'vip'      => mp_vip_config(),
        'youtube'  => mp_youtube_rules(),
        'ai'       => [
            'covers'    => (bool) get_option( 'mp_ai_covers', 0 ),
            'tags'      => (bool) get_option( 'mp_ai_tags', 1 ),
            'lookup'    => (bool) get_option( 'mp_ai_lookup', 1 ),
            'translate' => (bool) get_option( 'mp_ai_translate', 1 ),
            'recommend' => (bool) get_option( 'mp_ai_recommend', 1 ),
            'playlist'  => (bool) get_option( 'mp_ai_playlist', 1 ),
            'shuffle'   => (bool) get_option( 'mp_ai_shuffle', 1 ),
            'diagnostics' => (bool) get_option( 'mp_ai_diagnostics', 1 ),
        ],
        'storage'  => [
            's3' => function_exists( 'mp_s3_enabled' ) ? mp_s3_enabled() : false,
        ],
        'eq'       => [
            // Sub-funções do Equalizador (checkboxes no modal Configurar do admin).
            'signatures' => (bool) get_option( 'mp_eq_signatures', 1 ),
        ],
        'audio'    => [
            // Regras de formato: chave (mp3/flac/wma…) → nível (off|free|account|vip).
            'formats' => mp_audio_formats(),
        ],
        'ads'      => [
            // Anúncios AdMob — o app obedece a isto (VIP pode ficar isento).
            'enabled'     => (bool) get_option( 'mp_ads_enabled', 0 ),
            'banner'      => (string) get_option( 'mp_ads_banner_id', '' ),
            'inter'       => (string) get_option( 'mp_ads_inter_id', '' ),
            'inter_every' => (int) get_option( 'mp_ads_inter_every', 0 ),
            'vip_free'    => (bool) get_option( 'mp_ads_vip_free', 1 ),
            // Premiados: ver anúncios → encher o progresso → dias VIP.
            'rewarded'    => (string) get_option( 'mp_ads_rew_id', '' ),
            // Nativos: linhas-anúncio dentro das listas de músicas/álbuns/artistas.
            'native'      => (string) get_option( 'mp_ads_native_id', '' ),
        ],
        'message'  => $message_text === '' ? null : [
            'type' => (string) get_option( 'mp_message_type', 'info' ), // info | warning | maintenance
            'text' => $message_text,
        ],
    ];

    return rmbz_api_ok( $data );
}
