<?php
/**
 * =====================================================================
 * NADIPLAYER  -  cPanel PHP backend  -  Front controller
 * =====================================================================
 * Author     : Nadifi abdessamad
 * Email      : nadiplayer@nadi.kr
 * Website    : https://nadi.kr
 * Copyright  : (c) 2026 Nadi Player. All rights reserved.
 * Repository : https://github.com/ghizlanefit-cell/Nadiplayer-v1.2.5-ads
 * =====================================================================
 * Proprietary and confidential. Unauthorized copying of this file,
 * via any medium, is strictly prohibited.
 * =====================================================================
 *
 * All requests under /api/ are routed here by .htaccess. We dispatch
 * based on (method, path) to the right handler.
 */

// Hidden ownership marker (do not remove) - used for piracy detection
if (!defined('NDP_OWNER')) {
    define('NDP_OWNER', json_encode([
        'author'    => 'Nadifi abdessamad',
        'email'     => 'nadiplayer@nadi.kr',
        'website'   => 'https://nadi.kr',
        'copyright' => '(c) 2026 Nadi Player',
        'repo'      => 'https://github.com/ghizlanefit-cell/Nadiplayer-v1.2.5-ads',
    ]));
}

require_once __DIR__ . '/config.php';
require_once __DIR__ . '/lib/util.php';
require_once __DIR__ . '/lib/db.php';
require_once __DIR__ . '/lib/auth.php';
require_once __DIR__ . '/routes/auth.php';
require_once __DIR__ . '/routes/admin.php';
require_once __DIR__ . '/routes/public.php';
require_once __DIR__ . '/routes/device.php';
require_once __DIR__ . '/routes/iptv_proxy.php';
// Stream-proxy routes were introduced in v1.3.1. Older installs that
// upload files in stages may temporarily lack proxy.php — we MUST NOT
// fatal in that case (it would 502 the whole site, including unrelated
// endpoints like /api/auth/login that don't need the proxy at all).
// `@require_once` returns FALSE if the file is missing, and the route
// dispatch below uses function_exists() to skip the proxy block when
// the helpers aren't loaded.
@include_once __DIR__ . '/routes/proxy.php';
require_once __DIR__ . '/routes/stalker.php';
require_once __DIR__ . '/routes/notifications.php';
require_once __DIR__ . '/routes/stats.php';
require_once __DIR__ . '/routes/trial.php';
require_once __DIR__ . '/routes/user_profile.php';
require_once __DIR__ . '/routes/ad_free.php';
require_once __DIR__ . '/routes/cron.php';
// Sports / World Cup (live fixtures proxy). Added 2026-02. Guard with
// @include_once so older installs that staged this file mid-upload
// don't fatal — the route dispatch below uses function_exists().
@include_once __DIR__ . '/routes/sports.php';

send_cors_headers();

$method = $_SERVER['REQUEST_METHOD'] ?? 'GET';
if ($method === 'OPTIONS') { http_response_code(204); exit; }

// Compute the path under the API root (works on every cPanel host).
//
// Strategy:
//   1. Take REQUEST_URI (e.g. "/nadiplayer/api/auth/login")
//   2. Strip the directory of SCRIPT_NAME (e.g. "/nadiplayer/api/index.php"
//      → dirname = "/nadiplayer/api"), leaving "/auth/login"
//   3. Defensive: if any host still leaves "/api/..." after step 2,
//      strip that too.
$uri = parse_url($_SERVER['REQUEST_URI'] ?? '/', PHP_URL_PATH) ?? '/';
$script_dir = str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'] ?? ''));

// Strategy 1: strip the script's directory (works on real Apache)
if ($script_dir !== '' && $script_dir !== '/' && strncmp($uri, $script_dir, strlen($script_dir)) === 0) {
    $path = substr($uri, strlen($script_dir));
} else {
    $path = $uri;
}

// Strategy 2: if "/api/" still appears, slice from there (works when proxies rewrite paths)
if (preg_match('#/api(/.*)$#', $path, $m)) {
    $path = $m[1];
} elseif (preg_match('#/api$#', $path)) {
    $path = '/';
}

// Strategy 3: some hosts hand us "/index.php/..." (e.g. when AcceptPathInfo
// is on but mod_rewrite isn't peeling the script name). Strip a leading
// "/index.php" so the routes still match.
if (preg_match('#^/index\.php(/.*)?$#', $path, $m)) {
    $path = $m[1] ?? '/';
    if ($path === '') $path = '/';
}

$path = '/' . ltrim($path, '/');
if ($path === '') { $path = '/'; }

try {
    // ── Health ─────────────────────────────────────────────
    if ($method === 'GET'  && $path === '/')                                    { send_json(['message' => 'Hello World']); }
    if ($method === 'GET'  && $path === '/_debug')                              {
        send_json([
            'method' => $method,
            'parsed_path' => $path,
            'raw_request_uri' => $_SERVER['REQUEST_URI'] ?? null,
            'script_name' => $_SERVER['SCRIPT_NAME'] ?? null,
            'php_self' => $_SERVER['PHP_SELF'] ?? null,
            'document_root' => $_SERVER['DOCUMENT_ROOT'] ?? null,
            'has_authorization_header' => extract_token() !== null,
            'php_version' => PHP_VERSION,
            'pdo_drivers' => PDO::getAvailableDrivers(),
            'curl_loaded' => extension_loaded('curl'),
        ]);
    }

    // ── Auth ──────────────────────────────────────────────
    if ($method === 'POST' && $path === '/auth/login')                          { route_auth_login(); }
    if ($method === 'GET'  && $path === '/auth/me')                             { route_auth_me(); }

    // ── Admin: users ──────────────────────────────────────
    if ($method === 'GET'    && $path === '/admin/users')                       { route_admin_list_users(); }
    if ($method === 'POST'   && $path === '/admin/users')                       { route_admin_create_user(); }
    if ($method === 'PUT'    && preg_match('#^/admin/users/([^/]+)$#', $path, $m)) { route_admin_update_user($m[1]); }
    if ($method === 'DELETE' && preg_match('#^/admin/users/([^/]+)$#', $path, $m)) { route_admin_delete_user($m[1]); }

    // ── Admin: settings ──────────────────────────────────
    if ($method === 'GET'  && $path === '/admin/settings')                      { route_admin_get_settings(); }
    if ($method === 'PUT'  && $path === '/admin/settings')                      { route_admin_put_settings(); }

    // ── Public ────────────────────────────────────────────
    if ($method === 'GET'  && $path === '/public/shared-xtream')                { route_public_shared_xtream(); }
    if ($method === 'GET'  && $path === '/public/playback-mode')                { route_public_playback_mode(); }
    if ($method === 'GET'  && $path === '/public/app-info')                     { route_public_app_info(); }
    if ($method === 'GET'  && $path === '/public/ad-config')                    { route_public_ad_config(); }
    if ($method === 'GET'  && $path === '/shared-profiles')                     { route_shared_profiles(); }
    if ($method === 'GET'  && $path === '/subscription/status')                 { route_subscription_status(); }

    // ── Device pairing ───────────────────────────────────
    if ($method === 'POST'   && $path === '/device/register')                   { route_device_register(); }
    if ($method === 'GET'    && preg_match('#^/device/status/([^/]+)$#', $path, $m)) { route_device_status($m[1]); }
    if ($method === 'POST'   && $path === '/device/pair')                       { route_device_pair(); }
    if ($method === 'GET'    && preg_match('#^/device/config/([^/]+)$#', $path, $m)) { route_device_config($m[1]); }
    if ($method === 'DELETE' && preg_match('#^/device/unpair/([^/]+)$#', $path, $m)) { route_device_unpair($m[1]); }

    // ── IPTV proxy ───────────────────────────────────────
    if ($path === '/iptv-proxy') {
        if ($method === 'GET')  { route_iptv_proxy_get(); }
        if ($method === 'POST') { route_iptv_proxy_post(); }
        if ($method === 'OPTIONS') { route_iptv_proxy_options(); }
    }

    // ── Stream Proxy / Restreaming (Shared Profiles only) ───────
    // PHP port of backend/routes/proxy.py — same wire format so the
    // React player works against either backend without changes.
    // Guarded with function_exists() so a partial upload that's
    // missing routes/proxy.php returns a clean 404 instead of fatal.
    if ($method === 'POST' && $path === '/proxy/sign' && function_exists('route_proxy_sign'))        { route_proxy_sign(); }
    if ($method === 'GET'  && $path === '/proxy/stats' && function_exists('route_proxy_stats'))      { route_proxy_stats(); }
    if ($method === 'GET'  && preg_match('#^/proxy/live/(.+)\.m3u8$#', $path, $m) && function_exists('route_proxy_live_playlist')) {
        route_proxy_live_playlist(rawurldecode($m[1]));
    }
    if ($method === 'GET'  && preg_match('#^/proxy/seg/(.+)$#',  $path, $m) && function_exists('route_proxy_segment')) {
        route_proxy_segment(rawurldecode($m[1]));
    }
    if ($method === 'GET'  && preg_match('#^/proxy/vod/(.+)$#',  $path, $m) && function_exists('route_proxy_vod')) {
        route_proxy_vod(rawurldecode($m[1]));
    }

    // ── Stalker / MAC portal proxy ───────────────────────
    if ($method === 'POST' && $path === '/stalker/handshake')        { route_stalker_handshake(); }
    if ($method === 'POST' && $path === '/stalker/all-channels')     { route_stalker_all_channels(); }
    if ($method === 'POST' && $path === '/stalker/vod-categories')   { route_stalker_vod_categories(); }
    if ($method === 'POST' && $path === '/stalker/resolve-stream')   { route_stalker_resolve_stream(); }

    // ── Push notifications (FCM) ─────────────────────────
    if ($method === 'POST' && $path === '/devices/register-token')       { route_devices_register_token(); }
    if ($method === 'POST' && $path === '/admin/broadcast-notification') { route_admin_broadcast(); }
    if ($method === 'POST' && $path === '/admin/notify-user')            { route_admin_notify_user(); }
    if ($method === 'GET'  && $path === '/admin/broadcasts')             { route_admin_broadcasts(); }
    if ($method === 'GET'  && $path === '/admin/devices')                { route_admin_devices(); }

    // ── Live stats (heartbeats + dashboards) ─────────────
    if ($method === 'GET'  && $path === '/stats/heartbeat')              { route_stats_heartbeat_get(); }
    if ($method === 'POST' && $path === '/stats/heartbeat')              { route_stats_heartbeat_post(); }
    if ($method === 'GET'  && $path === '/admin/stats/live')             { route_admin_stats_live(); }
    if ($method === 'GET'  && $path === '/admin/stats/installs')         { route_admin_stats_installs(); }

    // ── Payments removed (Google Play "Choice B" — no in-app purchase) ───

    // ── Trial (device fingerprint, anti-reinstall) ───────
    if ($method === 'POST' && $path === '/trial/status')                 { route_trial_status(); }

    // ── Admin: device-trials management ──────────────────
    if ($method === 'GET'  && $path === '/admin/device-trials')          { route_admin_list_device_trials(); }
    if (preg_match('#^/admin/device-trials/([^/]+)$#', $path, $m)) {
        if ($method === 'PATCH')  { route_admin_patch_device_trial(urldecode($m[1])); }
        if ($method === 'DELETE') { route_admin_delete_device_trial(urldecode($m[1])); }
    }

    // ── User self-service ────────────────────────────────
    if ($method === 'PUT'  && $path === '/user/profile')                 { route_user_update_profile(); }
    // BUG-5 FEATURE (2026-05) — rewarded-ads "unlock ad-free" flow
    if ($method === 'POST' && $path === '/user/grant-ad-free')           { route_user_grant_ad_free(); }
    if ($method === 'GET'  && $path === '/user/ad-free-status')          { route_user_ad_free_status(); }
    if ($method === 'POST' && $path === '/user/ad-watched')              { route_user_ad_watched(); }

    // ── Cron (scheduled tasks, hit from cPanel Cron Jobs) ────────────
    // Public route protected by ?key=CRON_SECRET_KEY (see config.php).
    if ($method === 'GET'  && ($path === '/cron' || $path === '/cron/run')) {
        route_cron_run();
    }

    // ── Sports / World Cup Hub (live fixtures proxy) ────────────────
    // Public fixture/standings endpoints are cached server-side; the
    // upstream API key never leaves the server. Admin endpoints
    // validate a new key and clear the cache. Guarded with
    // function_exists() so a partial upload that's missing
    // routes/sports.php returns 404 instead of fatal.
    if ($method === 'GET'  && $path === '/sports/fixtures'  && function_exists('route_sports_fixtures'))  { route_sports_fixtures();  }
    if ($method === 'GET'  && $path === '/sports/standings' && function_exists('route_sports_standings')) { route_sports_standings(); }
    if ($method === 'POST' && $path === '/admin/sports/test' && function_exists('route_admin_sports_test'))               { route_admin_sports_test(); }
    if ($method === 'POST' && $path === '/admin/sports/clear-cache' && function_exists('route_admin_sports_clear_cache')) { route_admin_sports_clear_cache(); }

    // No route matched
    json_error(404, "No route for $method $path");
} catch (Throwable $e) {
    @error_log('[NADIPLAY] ' . $e->getMessage() . "\n" . $e->getTraceAsString());
    json_error(500, 'Server error: ' . $e->getMessage());
}
