<?php
/*-----------------------------------------------*/
/*  EXTHEM.ES
/*  PREMIUM WORDRESS THEMES
/*
/*  STOP DON'T TRY EDIT
/*  IF YOU DON'T KNOW PHP 
/*
/*  As Errors In Your Themes
/*  Are Not The Responsibility
/*  Of The DEVELOPERS
/*  @EXTHEM.ES
/*  
/*  Follow Social Media Exthem.es
/*  Youtube : https://www.youtube.com/channel/UCpcZNXk6ySLtwRSBN6fVyLA
/*  Facebook : https://www.facebook.com/groups/exthem.es
/*  Twitter : https://x.com/bangreyblog
/*  Instagram : https://www.instagram.com/exthem.es/
/*  Telegram : https://t.me/exthemes_helps
/*  TikTok : https://www.tiktok.com/@exthemes
/*	More Premium Themes Visit Now On https://exthem.es/
/*-----------------------------------------------*/
if ( ! defined( 'ABSPATH' ) ) exit; 
// Silence is golden.

/* --------------------------------------------------------------------
 * Main function: Check if a newer version is available on Google Play
 * ------------------------------------------------------------------ */
function app_update_available11( $post_id, $debug = false ) {

	global $opt_themes;
	$post_id = (int) $post_id;

	/* --------------------------------------------------------------------
	 * Validate post
	 * ------------------------------------------------------------------ */
	if ( ! $post_id || ! get_post( $post_id ) ) {
		if ( $debug ) echo "<br>⚠️ [ERROR] Invalid post ID: $post_id ⚠️ ";
		return false;
	}

	/* --------------------------------------------------------------------
	 * CRON LOCK (overlap protection)
	 * ------------------------------------------------------------------ */
	$lock_key  = "apk_update_lock_{$post_id}";
	$lock_time = get_transient( $lock_key );

	// Emergency cleanup of stuck lock (>30 minutes)
	if ( $lock_time && ( time() - $lock_time ) > 30 * MINUTE_IN_SECONDS ) {
		delete_transient( $lock_key );
		$lock_time = false;
	}

	if ( $lock_time ) {
		if ( $debug ) echo "<br>⚠️ [SKIP] Post <strong>#$post_id</strong> is locked ⚠️";
		return false;
	}

	set_transient( $lock_key, time(), 10 * MINUTE_IN_SECONDS );

	/* --------------------------------------------------------------------
	 * Required meta
	 * ------------------------------------------------------------------ */
	$appid  = get_post_meta( $post_id, 'wp_GP_ID', true );
	$title  = get_post_meta( $post_id, 'wp_title_GP', true );
	$title  = $title ?: get_the_title( $post_id );

	if ( ! $appid ) {
		if ( $debug ) echo "<br>⚠️ <strong>[SKIP] #$post_id <strong>{$title}</strong> No Google Play ID</strong> ⚠️";
		update_post_meta( $post_id, '_time_scrape_app_update', time() );
		delete_transient( $lock_key );
		return false;
	}

	update_post_meta( $post_id, '_time_scrape_app_update', time() );

	if ( $debug ) {
		echo "<br>🟢 Checking <strong style='color: gold;'>#$post_id</strong> → <strong>{$title}</strong>";
	}
	
	/* --------------------------------------------------------------------
	 * Fetch data
	 * ------------------------------------------------------------------ 
	 */
	//$scraper		= new Go_Curl(); 
	//$url			= 'https://a-a.my.id/gps.php?pkgid='.$appid;  
	//$g_data 		= $scraper->scrapesite2( $url );

	//if ( ! $g_data || strlen( $g_data ) < 1500 ) {
	//	if ( $debug ) echo " <span style='color:maroon;'>[ERROR] Failed to fetch data from server</span>";
	//	delete_transient( $lock_key );
	//	return false;
	//}
	
	//$n_version_alt	= $scraper->match( '/<div class="c_version">(.*?)<\/div>/ms', $g_data, 1 );
	//$n_whatsnew1	= $scraper->match( '/<div class="whatsnew">(.*?)<\/div>/ms', $g_data, 1 );
	
	/* --------------------------------------------------------------------
	 * Fetch from Google Play (Nelexa)
	 * ------------------------------------------------------------------ */
	try {
		$language = $opt_themes['apk_language'] ?? 'en';
		$gplay    = new \Nelexa\GPlay\GPlayApps( $language );
		$appinfo  = $gplay->getAppInfo( $appid );

		$n_version  = normalize_version( $appinfo->getAppVersion() );
		$n_whatsnew = $appinfo->getRecentChanges();

	} catch ( Exception $e ) {
		if ( $debug ) echo "⚠️ <span style='color:gold'>[ERROR] {$e->getMessage()}</span> ⚠️";
		delete_transient( $lock_key );
		return false;
	}

	if ( ! $n_version ) {
		if ( $debug ) echo "⚠️ <span style='color:orange'>[WARNING] Version not found</span> ⚠️";
		delete_transient( $lock_key );
		return false;
	}


	$c_version = normalize_version(
		get_post_meta( $post_id, 'wp_version_GP', true )
	);
	
	//$n_version = preg_replace( '/\+.*$/', '', $n_version );
	//$c_version = $c_version ? preg_replace( '/\+.*$/', '', trim( $c_version ) ) : '';
	
	/* --------------------------------------------------------------------
	 * Version compare
	 * ------------------------------------------------------------------ */
	//if ( $c_version && version_compare( $n_version, $c_version, '>' ) ) {
	if ( version_compare( $n_version, $c_version ) > 0) {
		update_post_meta( $post_id, 'available_updated', 'yes' );
		update_post_meta( $post_id, 'available_version', $n_version );
		update_post_meta( $post_id, 'available_whatsnew', $n_whatsnew );
		update_post_meta( $post_id, 'app_last_update_found', time() );

		if ( $debug ) {
			echo " <span style='color:lime;font-weight:bold'>[UPDATE AVAILABLE]</span> <span style='color: white;font-weight: bolder;'>v.$c_version</span> ↪️ <span style='color: gold;font-weight: bolder;'>v.$n_version</span>";
		}

		$appInfo = [
			'post_id'         => $post_id,
			'appid'           => $appid,
			'title'           => $title,
			'current_version' => $c_version,
			'new_version'     => $n_version,
			'new_whatsnew'    => $n_whatsnew,
		];

		delete_transient( $lock_key );

		do_action( 'app_update_detected', $post_id, $appInfo );
		return true;
	}

	/* --------------------------------------------------------------------
	 * No update  
	 * ------------------------------------------------------------------ */
	clear_app_update_flags( $post_id );
	delete_transient( $lock_key );

	if ( $debug ) {
		echo " <span style='color: deepskyblue;font-weight: bolder;'>[UP TO DATE]</span> <span style='color: gold;font-weight: bolder;'>v.$c_version</span> ✔️";
	}

	return true;
}


/* --------------------------------------------------------------------
* Main function: Check if a newer version is available on Google Play
* ------------------------------------------------------------------ 
*/	
function app_update_available1( $post_id, $debug=false ) 
{
	global $opt_themes;
	$post_id = (int) $post_id;	
 
 
	if ( ! $post_id || ! get_post( $post_id ) ) {
		if ( $debug ) echo "<br/>[ERROR] Invalid post ID: $post_id";
		return false;
	}

	
	/* --------------------------------------------------------------------
	 * CRON LOCK (overlap protection)
	 * ------------------------------------------------------------------ 
	 */
	$lock_key = "apk_update_lock_{$post_id}";
	if ( get_transient( $lock_key ) ) {
		if ( $debug ) echo "<br/>[SKIP] Post $post_id is already being processed (locked).";
		return false; // Another process is already checking this app
	}

	/* --------------------------------------------------------------------
	 * Acquire lock for 8 minutes (adjust as needed, should be longer than max execution time)
	 * ------------------------------------------------------------------ 
	 */
	set_transient( $lock_key, time(), 8 * MINUTE_IN_SECONDS );

	/* --------------------------------------------------------------------
	 * Optional: emergency cleanup of very old stuck locks (>30 min)
	 * ------------------------------------------------------------------ 
	 */
	register_shutdown_function( function() use ( $lock_key ) {
		delete_transient( $lock_key );
	} );

	/* --------------------------------------------------------------------
	 * Required meta
	 * ------------------------------------------------------------------ 
	 */
	$appid 			= get_post_meta( $post_id, 'wp_GP_ID', true );
	$titles			= get_post_meta( $post_id, 'wp_title_GP', true ); 
 
	if ( empty( $appid ) ) {
		if ( $debug ) echo "<br/>[SKIP] Post $post_id has no Google Play ID";
		delete_transient( $lock_key );
		update_post_meta( $post_id, '_time_scrape_app_update', time() );
		return false;
	}

	/* --------------------------------------------------------------------
	 * Mark as being processed + update timestamp
	 * ------------------------------------------------------------------ 
	 */
	update_post_meta( $post_id, '_time_scrape_app_update', time() );

	if ( $debug ) {
		echo "<br/>Checking Post ID <strong>$post_id</strong> → <strong>$titles</strong>...";
	}
	
	/* --------------------------------------------------------------------
	 * Fetch data
	 * ------------------------------------------------------------------ 
	 */
	/* $scraper		= new Go_Curl(); 
	$url			= 'https://a-a.my.id/gps.php?pkgid='.$appid;  
	$g_data 		= $scraper->scrapesite2( $url );

	if ( ! $g_data || strlen( $g_data ) < 1500 ) {
		if ( $debug ) echo " <span style='color:maroon;'>[ERROR] Failed to fetch data from server</span>";
		delete_transient( $lock_key );
		return false;
	} */
	
	//$n_version_raw2	= $scraper->match( '/<div class="c_version">(.*?)<\/div>/ms', $g_data, 1 );
	//$n_whatsnew1	= $scraper->match( '/<div class="whatsnew">(.*?)<\/div>/ms', $g_data, 1 );
		
	$language		= $opt_themes['apk_language'];   
	$gplay			= new \Nelexa\GPlay\GPlayApps( $defaultLocale = $language, $defaultCountry = '' ); 
	$appinfo		= $gplay->getAppInfo( $appid );

	//$n_version_raw2	= $scraper->match( '/<div class="c_version">(.*?)<\/div>/ms', $g_data, 1 );
	//$n_whatsnew1	= $scraper->match( '/<div class="whatsnew">(.*?)<\/div>/ms', $g_data, 1 );
	$n_whatsnew		= $appinfo->getRecentChanges();
	$n_version_raw	= $appinfo->getAppVersion();
	
	$n_version		= trim( $n_version_raw ); 
	$c_version		= get_post_meta( $post_id, 'wp_version_GP', true );
	
	// Clean version numbers (remove +hotfix, build metadata, etc.)
	//$n_version = preg_replace( '/\+.*$/', '', $n_version1 );
	//$c_version = $c_version1 ? preg_replace( '/\+.*$/', '', trim( $c_version1 ) ) : '';

	if ( empty( $n_version_raw ) ) {
		if ( $debug ) echo " <span style='color:orange;'>[WARNING] Could not parse new version from response</span>";
		delete_transient( $lock_key );
		return false;
	}
	
	/* --------------------------------------------------------------------
	 * 
	 * ------------------------------------------------------------------ 
	 */
	 
	/* --------------------------------------------------------------------
	 * Always update the stored version if different (handles rollbacks too)
	 * ------------------------------------------------------------------ 
	 */
	if ( $n_version && $n_version !== $c_version ) {
		//update_post_meta( $post_id, 'wp_version_GP', $n_version );
		if ( $debug ) echo " <strong>v.$c_version</strong>";
	}

	//if ( $debug ) {
	//	echo " <strong>v.$c_version</strong> ";
	//}
	
    // Always clean up old update flags first
    /* delete_post_meta( $post_id, 'available_updated' );
    delete_post_meta( $post_id, 'available_version' );
    delete_post_meta( $post_id, 'available_whatsnew' );
    delete_post_meta( $post_id, 'available_update_version' ); // legacy?
    delete_post_meta( $post_id, 'app_last_update_found' ); */

	/* --------------------------------------------------------------------
	 * Version compare
	 * ------------------------------------------------------------------ 
	*/	
	if ( version_compare( $n_version, $c_version, '>' ) ) {

	//if (version_compare( $n_version, $c_version ) > 0) {

	/* --------------------------------------------------------------------
	 * UPDATE FOUND! 
	 * ------------------------------------------------------------------ 
	*/	
	update_post_meta( $post_id, 'available_updated', 'yes' );
	update_post_meta( $post_id, 'available_version', $n_version );
	update_post_meta( $post_id, 'available_whatsnew', $n_whatsnew );
	update_post_meta( $post_id, 'app_last_update_found', time() );

	if ( $debug ) {
		echo " → v.$n_version <span style='color:green;font-weight:bold;'>UPDATE AVAILABLE!</span>";
	}

	/* --------------------------------------------------------------------
	 * Prepare app info for action hook
	 * ------------------------------------------------------------------ 
	*/	
	$appInfo = [
		'post_id'			=> $post_id,
		'appid'				=> $appid,
		'title'				=> $titles,
		'current_version'  	=> $c_version,
		'new_version'	  	=> $n_version,
		'new_whatsnew'	  	=> $n_whatsnew,
	];

	/* --------------------------------------------------------------------
	 * Remove lock ONLY after everything succeeded
	 * ------------------------------------------------------------------ 
	*/	
	delete_transient( $lock_key );

	/* --------------------------------------------------------------------
	 * Trigger action (for downloads, notifications, etc.) 
	 * ------------------------------------------------------------------ 
	*/	
	do_action( 'app_update_detected', $post_id, $appInfo );
	return true;

	} else {
		delete_transient( $lock_key );
		delete_post_meta( $post_id, 'app_last_update_found' );
		delete_post_meta( $post_id, 'available_update_version' );
		delete_post_meta( $post_id, 'available_updated' );
		delete_post_meta( $post_id, 'available_version' );
		delete_post_meta( $post_id, 'available_whatsnew' );
		return true;
	} 	
	
	/* --------------------------------------------------------------------
	 * No update – just keep current version
	 * ------------------------------------------------------------------ 
	*/	
	if ( $c_version !== $n_version ) {
		//update_post_meta( $post_id, 'wp_version_GP', $current_version );
	}
	
	/* --------------------------------------------------------------------
	 * No update
	 * ------------------------------------------------------------------ 
	*/	
	delete_post_meta( $post_id, 'available_update_version' );
	delete_post_meta( $post_id, 'available_updated' );
	delete_post_meta( $post_id, 'available_version' );	
	delete_post_meta( $post_id, 'available_whatsnew' );	
	
	/* --------------------------------------------------------------------
	 * optional: delete_post_meta( $post_id, 'app_last_update_found' );
	 * ------------------------------------------------------------------ 
	*/	
	
	if ( $debug ) echo " <span style='color:gray;'> → Up to date</span>";
	
	delete_transient( $lock_key );
 
	return false; 
}

function app_update_available212( $post_id, $debug = false ) {
    global $opt_themes;
    $post_id = (int) $post_id;

    /* --------------------------------------------------------------------
     * Validate post
     * ------------------------------------------------------------------ */
    if ( ! $post_id || ! get_post( $post_id ) ) {
        if ( $debug ) echo "<br>⚠️ [ERROR] Invalid post ID: $post_id ⚠️ ";
        return false;
    }

    /* --------------------------------------------------------------------
     * CRON LOCK (overlap protection)
     * ------------------------------------------------------------------ */
    $lock_key = "apk_update_lock_{$post_id}";
    $lock_time = get_transient( $lock_key );

    // Emergency cleanup of stuck lock (>30 minutes)
    if ( $lock_time && ( time() - $lock_time ) > 30 * MINUTE_IN_SECONDS ) {
        delete_transient( $lock_key );
        $lock_time = false;
    }

    if ( $lock_time ) {
        if ( $debug ) echo "<br>⚠️ [SKIP] Post <strong>#$post_id</strong> is locked ⚠️";
        return false;
    }

    set_transient( $lock_key, time(), 10 * MINUTE_IN_SECONDS );

    /* --------------------------------------------------------------------
     * Required meta
     * ------------------------------------------------------------------ */
    $appid = get_post_meta( $post_id, 'wp_GP_ID', true );
    $title = get_post_meta( $post_id, 'wp_title_GP', true );
    $title = $title ?: get_the_title( $post_id );

    if ( ! $appid ) {
        if ( $debug ) echo "<br>⚠️ <strong>[SKIP] #$post_id <strong>{$title}</strong> No Google Play ID</strong> ⚠️";
        update_post_meta( $post_id, '_time_scrape_app_update', time() );
        delete_transient( $lock_key );
        return false;
    }

    update_post_meta( $post_id, '_time_scrape_app_update', time() );

    if ( $debug ) {
        echo "<br>🟢 Checking <strong style='color: gold;'>#$post_id</strong> → <strong>{$title}</strong>";
    }

    /* --------------------------------------------------------------------
     * Initialize variables
     * ------------------------------------------------------------------ */
    $new_version  = false;
    $new_whatsnew = '';
    $source_used  = '';

    /* --------------------------------------------------------------------
     * Primary: Nelexa Library (with country support)
     * ------------------------------------------------------------------ */
    try {
        $language = $opt_themes['apk_language'] ?? 'en';
        $country  = $opt_themes['apk_country'] ?? 'us'; 

        $gplay   = new \Nelexa\GPlay\GPlayApps( $language, $country );
        $appinfo = $gplay->getAppInfo( $appid );

        $raw_version = $appinfo->getAppVersion();

        if ( ! empty( $raw_version ) && stripos( $raw_version, 'varies' ) === false ) {
            $new_version  = normalize_version( $raw_version );
            $new_whatsnew = $appinfo->getRecentChanges() ?: '';
            $source_used  = 'PlayStore';
        }

        if ( $debug && $source_used ) {
            //echo " <span style='color:gold'>[SOURCE]</span> $source_used";
        }

    } catch ( Exception $e ) {
        if ( $debug ) echo " ⚠️ <span style='color:orange'>[ERROR] PlayStore failed: " . esc_html( $e->getMessage() ) . "</span> ⚠️ ";
    }

    /* --------------------------------------------------------------------
     * Fallback: Custom proxy scraper[](https://a-a.my.id/gps.php)
     * ------------------------------------------------------------------ */
    if ( ! $new_version ) {
        $scraper = new Go_Curl();
        $url     = 'https://a-a.my.id/gps.php?pkgid=' . urlencode( $appid );
        $g_data  = $scraper->scrapesite( $url );

        if ( $g_data && strlen( $g_data ) >= 1000 && stripos( $g_data, 'New Version :' ) !== false ) {
		//if ( ! $g_data || strlen( $g_data ) < 1500 ) {
            // Extract New Version
            //if ( preg_match( '/New Version\s*:\s*([0-9A-Za-z.\-]+)/i', $g_data, $m ) ) {
            //    $new_version = normalize_version( $m[1] );
            //}
			
			$n_versi		= $scraper->match( '/<div class="version">(.*?)<\/div>/ms', $g_data, 1 );
			$new_version	= normalize_version($n_versi);

            // Extract What's New (everything between "What's New :" and "Thanks for using")
            //if ( preg_match( '/What\'s New\s*:\s*(.*?)(Thanks for using|$)/is', $g_data, $m ) ) {
            //    $new_whatsnew = trim( $m[1] );
            //}
			
			$new_whatsnew	= $scraper->match( '/<div class="whatsnew">(.*?)<\/div>/ms', $g_data, 1 );
			
            if ( $new_version ) {
                $source_used = 'eXthem.es';
				
				if ( $debug && $source_used ) {
					//echo " <span style='color:gold'>[SOURCE]</span> $source_used";
				} 
            }
        } else {
            if ( $debug ) echo " ⚠️ <span style='color:maroon'>[ERROR]</span> eXthem.es or empty response  ";
        }
    }

    /* --------------------------------------------------------------------
     * Final checks
     * ------------------------------------------------------------------ */
    if ( ! $new_version ) {
        if ( $debug ) echo " <span style='color:coral'>[FAILED]</span> No version from any source ⚠️ ";
        delete_transient( $lock_key );
        return false;
    }

    // Handle "Varies with device" case (though fallback usually provides a version)
    if ( stripos( $new_version, 'varies' ) !== false ) {
        if ( $debug ) echo " <span style='color:orange'>[SKIP]</span> Varies with device ⚠️ ";
        clear_app_update_flags( $post_id );
        delete_transient( $lock_key );
        return true;
    }

    $current_version = normalize_version( get_post_meta( $post_id, 'wp_version_GP', true ) ?: '' );

    /* --------------------------------------------------------------------
     * Version compare
     * ------------------------------------------------------------------ */
    if ( version_compare( $new_version, $current_version, '>' ) ) {
        update_post_meta( $post_id, 'available_updated', 'yes' );
        update_post_meta( $post_id, 'available_version', $new_version );
        update_post_meta( $post_id, 'available_whatsnew', $new_whatsnew );
        update_post_meta( $post_id, 'app_last_update_found', time() );

        if ( $debug ) {
            echo " <span style='color: lime;font-weight:bold'>[UPDATE AVAILABLE]</span> "
               . "<span style='color: white;font-weight: bolder;'>v{$current_version}</span> ↪️ "
               . "<span style='color: gold;font-weight: bolder;'>v{$new_version}</span> "
               . " → <span style='color: white'>[ $source_used ]</span> ";
        }

        $appInfo = [
            'post_id'         => $post_id,
            'appid'           => $appid,
            'title'           => $title,
            'current_version' => $current_version,
            'new_version'     => $new_version,
            'new_whatsnew'    => $new_whatsnew,
            'source'          => $source_used,
        ];

        delete_transient( $lock_key );
        do_action( 'app_update_detected', $post_id, $appInfo );
        return true;
    }

    /* --------------------------------------------------------------------
     * No update
     * ------------------------------------------------------------------ */
    clear_app_update_flags( $post_id );

    if ( $debug ) {
        echo " <span style='color: deepskyblue;font-weight: bolder;'>[UP TO DATE]</span> "
           . "<span style='color: gold;font-weight: bolder;'>v{$current_version}</span> ✔️ "
           . " → <span style='color: white'>[ $source_used ]</span> ";
    }

    delete_transient( $lock_key );
    return true;
}

function app_update_available12345( $post_id, $debug = false ) 
{
    global $opt_themes;
    $post_id = (int) $post_id;

    /* --------------------------------------------------------------------
     * Validate post
     * ------------------------------------------------------------------ */
    if ( ! $post_id || ! get_post( $post_id ) ) {
        if ( $debug ) echo "<br>⚠️ [ERROR] Invalid post ID: $post_id ⚠️ ";
        return false;
    }

    /* --------------------------------------------------------------------
     * CRON LOCK (overlap protection)
     * ------------------------------------------------------------------ */
    $lock_key = "apk_update_lock_{$post_id}";
    $lock_time = get_transient( $lock_key );

    // Emergency cleanup of stuck lock (>30 minutes)
    if ( $lock_time && ( time() - $lock_time ) > 30 * MINUTE_IN_SECONDS ) {
        delete_transient( $lock_key );
        $lock_time = false;
    }
	 
	 
    if ( $lock_time ) {
        if ( $debug ) echo "<br>⚠️ [SKIP] Post <strong>#$post_id</strong> is locked ⚠️";
        return false;
    }

    set_transient( $lock_key, time(), 10 * MINUTE_IN_SECONDS );

    /* --------------------------------------------------------------------
     * Required meta
     * ------------------------------------------------------------------ */
    $appid = get_post_meta( $post_id, 'wp_GP_ID', true );
    $title = get_post_meta( $post_id, 'wp_title_GP', true );
    $title = $title ?: get_the_title( $post_id );

    if ( ! $appid ) {
        if ( $debug ) echo "<br>⚠️ <strong>[SKIP]</strong> #$post_id <strong>{$title}</strong> No Google Play ID ⚠️";
        update_post_meta( $post_id, '_time_scrape_app_update', time() );
        delete_transient( $lock_key );
        return false;
    }

    update_post_meta( $post_id, '_time_scrape_app_update', time() );

    if ( $debug ) {
		//echo "<div class=\"notice notice-success is-dismissible\">";
        echo "<br>🟢 Checking <strong style='color: #2271b1;'>#$post_id</strong> → <strong style='color:#2271b1;font-weight:bold;padding: 0 5px;'>{$title}</strong> → ";
		//echo "</div>";
    }

    /* --------------------------------------------------------------------
     * Initialize variables 
     * ------------------------------------------------------------------ */
    $new_version   = false;
    $new_whatsnew  = '';
    $source_used   = '';

    /* --------------------------------------------------------------------
     * Primary: Nelexa/GPlay Library
     * ------------------------------------------------------------------ */
    try {
        $language = $opt_themes['apk_language'] ?? 'en-US';
        $country  = $opt_themes['apk_country'] ?? '';

        $gplay   = new \Nelexa\GPlay\GPlayApps( $language, $country );
        $appinfo = $gplay->getAppInfo( $appid );

        $raw_version = $appinfo->getAppVersion();

        if ( ! empty( $raw_version ) && stripos( $raw_version, 'varies' ) === false ) {
            $new_version  = normalize_version( $raw_version );
            $new_whatsnew = $appinfo->getRecentChanges() ?: '';
            $source_used  = 'PlayStore';
        }

        if ( $debug && $source_used ) {
            //echo " <span style='color:gold'>[SOURCE]</span> {$source_used}";
            //echo " <span style='color:gold'>[SOURCE]</span> {PlayStore}";
        }
    } catch ( Exception $e ) {
        if ( $debug ) echo " ⚠️ <span style='color:orange'>[ERROR]</span> PlayStore failed: " . esc_html( $e->getMessage() ) . "";
    }

    /* --------------------------------------------------------------------
     * Fallback: a-a.my.id proxy scraper (confirmed working Dec 17, 2025)
     * ------------------------------------------------------------------ */
    if ( ! $new_version ) {
        $url      = 'https://a-a.my.id/gps.php?pkgid=' . rawurlencode( $appid );
        $response = wp_remote_get( $url, array( 'timeout' => 20 ) );

        if ( is_wp_error( $response ) ) {
            if ( $debug ) echo " ⚠️ <span style='color:maroon'>[ERROR]</span> Fallback request failed: " . esc_html( $response->get_error_message() ) . "";
        } else {
            $g_data = wp_remote_retrieve_body( $response );
			
			/* --------------------------------------------------------------------
			 * Fallback: a-a.my.id proxy scraper (WORKING per 25 Dec 2025)
			 * ------------------------------------------------------------------ 
			*/

			// Fallback: a-a.my.id proxy scraper
			if ( ! $new_version ) {
				$url = 'https://a-a.my.id/gps.php?pkgid=' . rawurlencode( $appid );
				$response = wp_remote_get( $url, array( 'timeout' => 20 ) );
				if ( is_wp_error( $response ) ) {
					if ( $debug ) echo " ⚠️ <span style='color:maroon'>[ERROR]</span> Fallback request failed: " . esc_html( $response->get_error_message() ) . "";
				} else {
					$g_data = wp_remote_retrieve_body( $response );
					if ( $g_data && stripos( $g_data, 'New Version :' ) !== false ) {
						// Extract Version
						if ( preg_match( '/New Version\s*:\s*([0-9\.\w\-]+)/i', $g_data, $m ) ) {
							$raw_version = trim( $m[1] );
							$new_version = normalize_version( $raw_version );
						}

						// Extract What's New (ambil semua setelah "What's New :" sampai sebelum "Update :" atau akhir)
						if ( preg_match( '/What\'s New\s*:\s*(.*?)(?=Update\s*:|$)/is', $g_data, $m ) ) {
							$new_whatsnew = trim( $m[1] );
							// Optional: bersihkan "Content :" jika ada (seperti di Instagram)
							$new_whatsnew = preg_replace( '/^Content\s*:\s*/i', '', $new_whatsnew );
							$new_whatsnew = strip_tags( $new_whatsnew ); // safety
						}

						if ( $new_version ) {
							$source_used = 'exthem.es';
							if ( $debug ) echo " <span style='color:gold'>[SOURCE]</span> {$source_used}";
						} else {
							if ( $debug ) echo " ⚠️ <span style='color:maroon'>[ERROR]</span> Version not found in fallback response";
						}
					} else {
						if ( $debug ) echo " ⚠️ <span style='color:maroon'>[ERROR]</span> Invalid/empty response from exthem.es";
					}
				}
			}

            /* 
			if ( $g_data && strlen( $g_data ) >= 1000 && stripos( $g_data, 'New Version :' ) !== false ) {
                // Extract version
                if ( preg_match( '/<div class="version">(.*?)<\/div>/ms', $g_data, $m ) ) {
                    $new_version = normalize_version( trim( $m[1] ) );
                }

                // Extract What's New
                if ( preg_match( '/<div class="whatsnew">(.*?)<\/div>/ms', $g_data, $m ) ) {
                    $new_whatsnew = trim( $m[1] );
                }

                if ( $new_version ) {
                    $source_used = 'exthem.es';
                    
					if ( $debug && $source_used ) {
						//echo " <span style='color:gold'>[SOURCE]</span> {$source_used}";
						//echo " <span style='color:gold'>[SOURCE]</span> {exthem.es}";
					}
                }
            } else {
                if ( $debug ) echo " ⚠️ <span style='color:maroon'>[ERROR]</span> Invalid/empty response from exthem.es";
            } 
			*/
        }
    }

    /* --------------------------------------------------------------------
     * Final checks
     * ------------------------------------------------------------------ */
    if ( ! $new_version ) {
        if ( $debug ) echo " <span style='color:red'>[FAILED]</span> No version retrieved from any source ⚠️";
        delete_transient( $lock_key );
        return false;
    }

    // Handle "Varies with device"
    if ( stripos( $new_version, 'varies' ) !== false ) {
        if ( $debug ) echo " <span style='color:orange'>[SKIP]</span> Varies with device";
        clear_app_update_flags( $post_id );
        delete_transient( $lock_key );
        return true;
    }

    $current_version = normalize_version( get_post_meta( $post_id, 'wp_version_GP', true ) ?: '' );

    /* --------------------------------------------------------------------
     * Version comparison
     * ------------------------------------------------------------------ */
    if ( version_compare( $new_version, $current_version, '>' ) ) {
        update_post_meta( $post_id, 'available_updated', 'yes' );
        update_post_meta( $post_id, 'available_version', $new_version );
        update_post_meta( $post_id, 'available_whatsnew', $new_whatsnew );
        update_post_meta( $post_id, 'app_last_update_found', time() );

        if ( $debug ) {
            echo "<strong style='color:crimson;font-weight:bold;padding: 0 5px;'>v{$current_version}</strong> ↪️  <strong style='color:crimson;font-weight:bold;padding: 0 5px;'>v{$new_version}</strong>"
               . " <span style='color:green;font-weight:bold'>[UPDATE AVAILABLE]</span>"
               . " -== checked by {$source_used} ==- ";
        }

        $appInfo = [
            'post_id'         => $post_id,
            'appid'           => $appid,
            'title'           => $title,
            'current_version' => $current_version,
            'new_version'     => $new_version,
            'new_whatsnew'    => $new_whatsnew,
            'source'          => $source_used,
        ];

        delete_transient( $lock_key );
        do_action( 'app_update_detected', $post_id, $appInfo );
        return true;
    }

    /* --------------------------------------------------------------------
     * No update found
     * ------------------------------------------------------------------ */
    clear_app_update_flags( $post_id );

    if ( $debug ) {
        echo " <strong style='color:crimson;font-weight:bold;padding: 0 5px;'>v{$current_version}</strong> "
           . " ✔️ <span style='color:dodgerblue;font-weight:bold'>[UP TO DATE]</span> -== checked by {$source_used} ==-";
    }

    delete_transient( $lock_key );
    return true;
}


/* --------------------------------------------------------------------
 * AJAX: Render Table + Pagination + Count
 * --------------------------------------------------------------------
 * Called via AJAX to load a specific page of updates.
 * Returns the full table HTML and native WordPress pagination.
 */
//add_action('wp_ajax_apk_render_updates_list', 'apk_render_updates_list');
function apk_render_updates_list22222() 
{
    // Security check
    check_ajax_referer('apps_updates_nonce', 'nonce');
    if (!current_user_can('manage_options')) {
        wp_send_json_error();
    }

    // Get current page from request, default to 1
    $paged 			= max(1, intval($_POST['paged'] ?? 1));
    $per_page 		= 10;                    // Matches default WP posts per page
    $offset 		= ($paged - 1) * $per_page;

    // Total number of apps needing updates
    $total 			= apk_update_count_posts();
    $total_pages 	= max(1, ceil($total / $per_page));

    // Capture table HTML
    ob_start();
    apk_render_updates_table($offset, $per_page);
    $table_html 	= ob_get_clean();

    // Capture native-style pagination HTML
    ob_start();
    ?>
    <div class="tablenav-pages">
        <span class="displaying-num"><?php echo $total; ?> item<?php echo $total != 1 ? 's' : ''; ?></span>
        <?php if ($total_pages > 1): ?>
        <span class="pagination-links">
            <?php if ($paged == 1): ?>
                <span class="tablenav-pages-navspan button disabled" aria-hidden="true">«</span>
                <span class="tablenav-pages-navspan button disabled" aria-hidden="true">‹</span>
            <?php else: ?>
                <a class="first-page button" href="#" data-page="1"><span aria-hidden="true">«</span></a>
                <a class="prev-page button" href="#" data-page="<?php echo $paged - 1; ?>"><span aria-hidden="true">‹</span></a>
            <?php endif; ?>

            <span class="paging-input">
                <span class="tablenav-paging-text"><?php echo $paged; ?> of <span class="total-pages"><?php echo $total_pages; ?></span></span>
            </span>

            <?php if ($paged == $total_pages): ?>
                <span class="tablenav-pages-navspan button disabled" aria-hidden="true">›</span>
                <span class="tablenav-pages-navspan button disabled" aria-hidden="true">»</span>
            <?php else: ?>
                <a class="next-page button" href="#" data-page="<?php echo $paged + 1; ?>"><span aria-hidden="true">›</span></a>
                <a class="last-page button" href="#" data-page="<?php echo $total_pages; ?>"><span aria-hidden="true">»</span></a>
            <?php endif; ?>
        </span>
        <?php endif; ?>
    </div>
    <?php
    $pagination_html = ob_get_clean();

    // Return everything needed for the frontend
    wp_send_json_success([
        'table'         => $table_html,
        'pagination'    => $pagination_html,
        'total'         => $total,
        'total_pages'   => $total_pages,
        'current_page'  => $paged,
    ]);
}


//add_action( 'check_all_apps_cron', 'app_update_run_batch_check' );
function app_update_run_batch_check999() {
    global $opt_themes;

    // Safety: Cegah eksekusi bersamaan
    if ( get_transient( 'app_update_global_cron_lock' ) ) {
        return;
    }
	
	
    // Lock selama proses (maksimal 30 menit)
    set_transient( 'app_update_global_cron_lock', true, 30 * MINUTE_IN_SECONDS );

    // Pengaturan batch
	$batch_sizex       	= get_option( 'app_update_batch_size', 20 );
    $batch_size 		= ! empty( $batch_sizex ) ? max( 1, intval( $batch_sizex ) ) : 20;
    $max_execution 		= 120; // detik maksimal per batch
    $min_interval_hours = 12; // Minimal berapa jam sejak terakhir dicek (ubah sesuai kebutuhan)

    $start_time 		= time();

    // Hitung waktu minimal untuk pengecekan ulang
    $min_time 			= date( 'Y-m-d H:i:s', strtotime( "-{$min_interval_hours} hours" ) );

    /**
     * Query prioritas:
     * 1. wp_GP_ID tidak kosong
     * 2. _time_scrape_app_update = 0 (belum pernah dicek) → paling atas
     * 3. Atau sudah dicek tapi lebih lama dari $min_interval_hours
     * 4. Urutkan ASC berdasarkan _time_scrape_app_update
     */
    $args = [
        'post_type'           => 'post', // GANTI jika pakai CPT
        'post_status'         => 'publish',
        'posts_per_page'      => $batch_size,
        'fields'              => 'ids',
        'no_found_rows'       => true,        // Hemat resource
        'ignore_sticky_posts' => true,
        'meta_query'          => [
            'relation' => 'AND',
            [
                'key'     => 'wp_GP_ID',
                'value'   => '',
                'compare' => '!=',
            ],
            [
                'relation' => 'OR',
                // Belum pernah dicek (nilai 0 atau tidak ada meta)
                [
                    'key'     => '_time_scrape_app_update',
                    'value'   => 0,
                    'compare' => '=',
                    'type'    => 'NUMERIC',
                ],
                [
                    'key'     => '_time_scrape_app_update',
                    'compare' => 'NOT EXISTS',
                ],
                // Atau sudah dicek tapi sudah lama
                [
                    'key'     => '_time_scrape_app_update',
                    'value'   => $min_time,
                    'compare' => '<',
                    'type'    => 'DATETIME',
                ],
            ],
        ],
        'orderby'   => 'meta_value_num',
        'meta_key'  => '_time_scrape_app_update',
        'order'     => 'ASC', // 0 dan nilai kecil muncul duluan
    ];

    $query = new WP_Query( $args );

    if ( ! $query->have_posts() ) {
        delete_transient( 'app_update_global_cron_lock' );
        return;
    }

    $checked_count = 0;
    foreach ( $query->posts as $post_id ) {
        // Hentikan jika waktu hampir habis
        if ( ( time() - $start_time ) > $max_execution ) {
            break;
        }

        if ( function_exists( 'app_update_available' ) ) {
            app_update_available( $post_id, false );
        } else {
            error_log( "[APK Updates Cron] Function app_update_available() tidak ditemukan!" );
        }

        $checked_count++;
    }

    // Log
    $message = "[APK Updates Cron] Batch selesai: Dicek {$checked_count} aplikasi.";
    error_log( $message );

    // Simpan log terakhir (maks 20 entri)
    $log_entry = [
        'time'    => current_time( 'mysql' ),
        'message' => $message,
    ];
    $existing_log = get_option( 'app_update_cron_last_log', [] );
    if ( ! is_array( $existing_log ) ) $existing_log = [];
    array_unshift( $existing_log, $log_entry );
    update_option( 'app_update_cron_last_log', array_slice( $existing_log, 0, 20 ) );

    // Jika batch penuh → kemungkinan masih ada yang belum dicek → jadwalkan lagi
    if ( $checked_count === $batch_size ) {
        wp_schedule_single_event( time() + 60, 'check_all_apps_cron' );
    }

    // Lepas lock
    delete_transient( 'app_update_global_cron_lock' );
}

// 3. Fungsi utama: Proses batch pengecekan update
//add_action( 'check_all_apps_cron', 'app_update_run_batch_check' );
function app_update_run_batch_check111111() 
{
    global $opt_themes;

    // Safety: Cegah eksekusi bersamaan
    if ( get_transient( 'app_update_global_cron_lock' ) ) {
        return;
    }

    // Lock selama proses (maksimal 30 menit)
    set_transient( 'app_update_global_cron_lock', true, 30 * MINUTE_IN_SECONDS );

    // Pengaturan batch
    $batch_size     = isset( $opt_themes['lim_post'] ) ? max( 1, intval( $opt_themes['lim_post'] ) ) : 20;
    $max_execution  = 120; // detik maksimal per batch (sesuaikan dengan hosting)
    $start_time     = time();

    // Ambil post yang memiliki Google Play ID dan belum pernah/ lama dicek
    $args = [
        'post_type'      => 'post', // GANTI jika pakai custom post type
        'post_status'    => 'publish',
        'posts_per_page' => $batch_size,
        'fields'         => 'ids',
        'meta_query'     => [
            [
                'key'     => 'wp_GP_ID',
                'value'   => '',
                'compare' => '!=',
            ],
        ],
        'orderby'        => 'meta_value_num',
        'meta_key'       => '_time_scrape_app_update',
        'order'          => 'ASC', // Prioritaskan yang lama tidak dicek
    ];

    $query = new WP_Query( $args );

    if ( ! $query->have_posts() ) {
        delete_transient( 'app_update_global_cron_lock' );
        return;
    }

    $checked_count = 0;

    foreach ( $query->posts as $post_id ) {
        // Hentikan jika waktu eksekusi hampir habis
        if ( ( time() - $start_time ) > $max_execution ) {
            break;
        }

        // Jalankan pengecekan update (pastikan fungsi ini sudah ada dan aman)
        if ( function_exists( 'app_update_available' ) ) {
            app_update_available( $post_id, false ); // $debug = false
        }

        $checked_count++;
    }

    // Log untuk debugging (bisa dihapus di production)
    error_log( "[APK Updates Cron] Batch completed: Checked {$checked_count} apps." );

    // Jika batch penuh, kemungkinan masih ada yang belum dicek → jadwalkan batch berikutnya
    if ( $checked_count === $batch_size ) {
        wp_schedule_single_event( time() + 60, 'check_all_apps_cron' ); // Lanjut 1 menit lagi
    }

	
	    // Simpan log batch terakhir (maksimal 20 entri)
    $log_entry = [
        'time'    => current_time( 'mysql' ),
        'message' => "[APK Updates Cron] Batch completed: Checked {$checked_count} apps."
    ];

    $existing_log = get_option( 'app_update_cron_last_log', [] );
    if ( ! is_array( $existing_log ) ) $existing_log = [];

    array_unshift( $existing_log, $log_entry ); // tambah di atas
    $existing_log = array_slice( $existing_log, 0, 20 ); // simpan max 20

    update_option( 'app_update_cron_last_log', $existing_log );
	
    // Lepas lock
    delete_transient( 'app_update_global_cron_lock' );
}


/* add_action('init', function() 
{
	if (!isset($_GET['fastcheck'])) return;
	if (!current_user_can('manage_options')) wp_die('No access');

	$ids = array_filter(array_map('intval', explode(',', $_GET['fastcheck'])));
	echo "<pre style='background:#000;color:#0f0;padding:20px;font-family:monospace;'>";
	foreach ($ids as $id) {
		if (get_post($id)) {
			echo "POST ID $id → ";
			app_update_available($id, false);
			echo "\n\n";
		}
	}
	echo "</pre>";
	die();
}); */

/* 
// === Count apps with available updates (for menu badge) ===
if ( ! function_exists( 'apk_update_count_posts2' ) ) {
    function apk_update_count_posts2() {
        $posts = get_posts( [
            'post_type'      => 'post',
            'post_status'    => 'publish',
            'posts_per_page' => -1,
            'meta_query'     => [
                [
                    'key'   => 'available_updated',
                    'value' => 'yes',
                ],
            ],
            'fields'         => 'ids',
            'cache_results'  => false,
            'no_found_rows'  => true,
        ] );

        $count = 0;
        foreach ( $posts as $post_id ) {
            $current   = get_post_meta( $post_id, 'wp_version_GP', true );
            $available = get_post_meta( $post_id, 'available_version', true );

            if ( $available && $current && version_compare( $available, $current, '>' ) ) {
                $count++;
            }
        }

        return $count;
    }
}
*/


/**
 * Render Dashboard Widget: App Update Cron Summary
 * FINAL VERSION – Professional with Vanilla JS Live Countdown
 */
if ( ! function_exists( 'app_update_render_dashboard_widget_sadsadsadsa' ) ) 
{
	function app_update_render_dashboard_widget_sadsadsadsa() 
	{
		$next_scheduled = wp_next_scheduled( 'check_all_apps_cron' );
		$lock_active    = get_transient( 'app_update_global_cron_lock' );
		$last_log       = get_option( 'app_update_cron_last_log', array() );
		$count_updates  = function_exists( 'apk_update_count_posts' ) ? apk_update_count_posts() : 0;

		// Deteksi interval akurat
		$current_interval = __( 'Not scheduled', TEXT_DOMAIN );
		if ( $next_scheduled ) {
			$crons     = _get_cron_array();
			$schedules = wp_get_schedules();
			foreach ( $crons as $cron ) {
				if ( isset( $cron['check_all_apps_cron'] ) ) {
					foreach ( $cron['check_all_apps_cron'] as $hook_data ) {
						if ( isset( $hook_data['schedule'] ) && isset( $schedules[ $hook_data['schedule'] ] ) ) {
							$current_interval = $schedules[ $hook_data['schedule'] ]['display'];
							break 2;
						}
					}
				}
			}
		}

		// URL
		$force_url     = wp_nonce_url( add_query_arg( 'app_update_force_check', '1' ), 'app_update_force_check_all' );
		$status_page   = admin_url( 'admin.php?page=apps_updates' );
		$updates_page  = admin_url( 'admin.php?page=app-update-list' );

		// Format tanggal next run (jika ada)
		$next_formatted = $next_scheduled ? date_i18n( 'j M Y @ H:i', $next_scheduled ) : false;
		$countdown_id   = 'app-update-widget-countdown'; // ID unik untuk widget
		?>
		<div style="font-size:13px; line-height:1.6;">
			<!-- Status -->
			<p style="margin:0 0 12px 0;">
				<strong><?php esc_html_e( 'Background Checker Status', TEXT_DOMAIN ); ?>:</strong>
				<?php if ( $next_scheduled ) : ?>
					<span style="color:#46b450; font-weight:600;">✓ <?php esc_html_e( 'Active', TEXT_DOMAIN ); ?></span>
				<?php else : ?>
					<span style="color:#d63638; font-weight:600;">✗ <?php esc_html_e( 'Not Scheduled', TEXT_DOMAIN ); ?></span>
				<?php endif; ?>
			</p>

			<!-- Next Run with Live Countdown -->
			<!-- Next Run with Smart Overdue Handling -->
	<p style="margin:8px 0;">
		<strong><?php esc_html_e( 'Next Run', TEXT_DOMAIN ); ?>:</strong><br>
		<?php if ( $next_scheduled ) : ?>
			<span style="color:#2271b1;">
				<?php echo esc_html( $next_formatted ); ?>
			</span>
			<br>
			<span id="<?php echo esc_attr( $countdown_id ); ?>" style="font-weight:600;">
				<em><?php esc_html_e( 'Calculating...', TEXT_DOMAIN ); ?></em>
			</span>

			<script type="text/javascript">
			document.addEventListener('DOMContentLoaded', function() {
				var targetTime = <?php echo $next_scheduled * 1000; ?>;
				var el = document.getElementById('<?php echo esc_js( $countdown_id ); ?>');

				function updateCountdown() {
					var now = Date.now();
					var distance = targetTime - now;

					if (distance < -300000) { // lebih dari 5 menit overdue
						el.innerHTML = '<span style="color:#d63638;">⚠️ <?php echo esc_js( __( 'Overdue – cron may not be running properly', TEXT_DOMAIN ) ); ?></span>';
					} else if (distance < 0) {
						el.innerHTML = '<span style="color:#d63638;">✓ <?php echo esc_js( __( 'Just executed or overdue', TEXT_DOMAIN ) ); ?></span>';
					} else {
						var days    = Math.floor(distance / 86400000);
						var hours   = Math.floor((distance % 86400000) / 3600000);
						var minutes = Math.floor((distance % 3600000) / 60000);
						var seconds = Math.floor((distance % 60000) / 1000);

						var text = '';
						if (days > 0) text += days + ' <?php echo esc_js( __( 'days', TEXT_DOMAIN ) ); ?>, ';
						if (hours > 0 || days > 0) text += hours + ' <?php echo esc_js( __( 'hours', TEXT_DOMAIN ) ); ?>, ';
						text += minutes + ' <?php echo esc_js( __( 'minutes', TEXT_DOMAIN ) ); ?>, ';
						text += seconds + ' <?php echo esc_js( __( 'seconds', TEXT_DOMAIN ) ); ?>';

						if (distance < 60000) {
							el.innerHTML = '<span style="color:#d63638;">⏳ <?php echo esc_js( __( 'Almost due!', TEXT_DOMAIN ) ); ?> (' + seconds + 's)</span>';
						} else {
							el.innerHTML = '<span style="color:#46b450;">' + text + '</span>';
						}
					}
				}

				updateCountdown();
				setInterval(updateCountdown, 1000);
			});
			</script>

		<?php else : ?>
			<em style="color:#a00;"><?php esc_html_e( '—', TEXT_DOMAIN ); ?></em>
		<?php endif; ?>
	</p>

			<!-- Interval & Process -->
			<p style="margin:8px 0;">
				<strong><?php esc_html_e( 'Interval', TEXT_DOMAIN ); ?>:</strong> <?php echo esc_html( $current_interval ); ?><br>
				<strong><?php esc_html_e( 'Process', TEXT_DOMAIN ); ?>:</strong>
				<?php if ( $lock_active ) : ?>
					<span style="color:#ffb900;">🔒 <?php esc_html_e( 'Running...', TEXT_DOMAIN ); ?></span>
				<?php else : ?>
					<span style="color:#46b450;">✓ <?php esc_html_e( 'Idle', TEXT_DOMAIN ); ?></span>
				<?php endif; ?>
			</p>

			<!-- Apps Need Update -->
			<p style="margin:8px 0;">
				<strong><?php esc_html_e( 'Apps Need Update', TEXT_DOMAIN ); ?>:</strong>
				<?php if ( $count_updates > 0 ) : ?>
					<a href="<?php echo esc_url( $updates_page ); ?>" style="text-decoration:none;">
						<strong style="color:#d63638; font-size:1.2em;">
							<?php echo number_format_i18n( $count_updates ); ?>
						</strong>
					</a>
				<?php else : ?>
					<span style="color:#46b450; font-weight:600;"><?php esc_html_e( 'All up to date!', TEXT_DOMAIN ); ?></span>
				<?php endif; ?>
			</p>

			<!-- Last Batch -->
			<?php if ( ! empty( $last_log ) && is_array( $last_log ) ) : ?>
				<p style="margin:12px 0 8px 0; padding-top:8px; border-top:1px solid #eee;">
					<strong><?php esc_html_e( 'Last Batch', TEXT_DOMAIN ); ?>:</strong><br>
					<small style="color:#666;">
						<?php echo esc_html( $last_log[0]['message'] ?? '' ); ?><br>
						<em><?php echo esc_html( $last_log[0]['time'] ?? '' ); ?></em>
					</small>
				</p>
			<?php endif; ?>

			<!-- Tombol Aksi -->
			<p style="margin:20px 0 10px 0;">
				<a href="<?php echo esc_url( $force_url ); ?>" class="button button-primary">
					<?php esc_html_e( 'Run Check Now', TEXT_DOMAIN ); ?>
				</a>
				<a href="<?php echo esc_url( $status_page ); ?>" class="button" style="margin-left:8px;">
					<?php esc_html_e( 'View Details →', TEXT_DOMAIN ); ?>
				</a>
			</p>

			<!-- Pesan jika cron belum terjadwal -->
			<?php if ( ! $next_scheduled ) : ?>
				<p style="margin:15px 0 5px 0; padding:10px; background:#fff8e5; border-left:4px solid #ffb900; font-size:0.9em; color:#664400;">
					<strong><?php esc_html_e( 'Cron not scheduled yet?', TEXT_DOMAIN ); ?></strong><br>
					<?php esc_html_e( 'Just click "Run Check Now" — WordPress will automatically schedule the background checker.', TEXT_DOMAIN ); ?>
				</p>
			<?php endif; ?>
		</div>
		<?php
	}
}

// === SEMENTARA: Jalankan cron secara paksa sekali saja ===
//add_action( 'admin_init', 'force_run_app_update_cron_once222' );
function force_run_app_update_cron_once222() {
    if ( ! current_user_can( 'manage_options' ) ) return;

    // Hanya jalankan sekali (bisa dicek dengan transient)
    if ( get_transient( 'force_run_cron_done' ) ) return;

    // Jalankan fungsi cron langsung
    app_update_run_batch_check();

    // Tandai sudah dijalankan
    set_transient( 'force_run_cron_done', true, DAY_IN_SECONDS );

    // Tampilkan notice
    add_action( 'admin_notices', function() {
        echo '<div class="notice notice-success is-dismissible">
                <p><strong>Background check is forced to run now!</strong><br>
                Refresh the Cron Status page to see the results of the first batch.</p>
              </div>';
    } );
}


if ( ! function_exists( 'app_update_run_batch_check123' ) ) 
{
	//add_action( 'check_all_apps_cron', 'app_update_run_batch_check' );
	function app_update_run_batch_check123() 
	{
		global $opt_themes;

		// Safety: Cegah eksekusi bersamaan
		if ( get_transient( 'app_update_global_cron_lock' ) ) {
			return;
		}

		// Lock selama proses (maksimal 30 menit)
		set_transient( 'app_update_global_cron_lock', true, 30 * MINUTE_IN_SECONDS );

		// Pengaturan batch size
		$batch_sizex = get_option( 'app_update_batch_size', 20 );
		$batch_size  = ! empty( $batch_sizex ) ? max( 1, intval( $batch_sizex ) ) : 20;

		// Pengaturan interval pengecekan ulang (dalam jam)
		$current_interval_option = get_option( 'app_update_cron_interval', 'every_6_hours' );

		// Mapping string interval ke jumlah jam
		$interval_map = [
			'every_1_hours'	=> 1,
			'every_3_hours' => 3,
			'every_6_hours' => 6,
			'every_12_hours'=> 12,
			'every_24_hours'=> 24,
		];

		$min_interval_hours = isset( $interval_map[ $current_interval_option ] )
			? $interval_map[ $current_interval_option ]
			: 6; // fallback ke 6 jam jika option tidak valid

		$max_execution = 120; // detik maksimal per batch eksekusi
		$start_time    = time();

		// Hitung batas waktu terakhir pengecekan yang diizinkan
		$min_time = date( 'Y-m-d H:i:s', strtotime( "-{$min_interval_hours} hours" ) );

		$processed_ids = [];
		$checked_count = 0;

		// Tahap 1: Prioritas tertinggi → Aplikasi yang BELUM PERNAH dicek
		$never_checked = get_posts( [
			'post_type'      => 'post', // Ganti jika menggunakan Custom Post Type
			'post_status'    => 'publish',
			'posts_per_page' => $batch_size,
			'fields'         => 'ids',
			'meta_query'     => [
				'relation' => 'AND',
				[ 'key' => 'wp_GP_ID', 'value' => '', 'compare' => '!=' ],
				[ 'key' => '_time_scrape_app_update', 'compare' => 'NOT EXISTS' ],
			],
		] );

		if ( count( $never_checked ) >= $batch_size ) {
			$post_ids = $never_checked;
		} else {
			// Tahap 2: Ambil yang sudah lama tidak dicek
			$remaining_slots = $batch_size - count( $never_checked );

			$old_checked = get_posts( [
				'post_type'      => 'post',
				'post_status'    => 'publish',
				'posts_per_page' => $remaining_slots > 0 ? $remaining_slots : 0,
				'fields'         => 'ids',
				'meta_query'     => [
					'relation' => 'AND',
					[ 'key' => 'wp_GP_ID', 'value' => '', 'compare' => '!=' ],
					[
						'key'     => '_time_scrape_app_update',
						'value'   => $min_time,
						'compare' => '<',
						'type'    => 'DATETIME',
					],
				],
				'orderby'  => 'meta_value_datetime',
				'meta_key' => '_time_scrape_app_update',
				'order'    => 'ASC',
			] );

			$post_ids = array_merge( $never_checked, $old_checked );
		}

		// Jika tidak ada post yang memenuhi syarat
		if ( empty( $post_ids ) ) {
			delete_transient( 'app_update_global_cron_lock' );
			error_log( '[APK Updates Cron] There are no apps to check at this time.' );
			return;
		}

		// Proses pengecekan update
		foreach ( $post_ids as $post_id ) {
			if ( ( time() - $start_time ) > $max_execution ) {
				break; // Stop jika waktu eksekusi hampir habis
			}

			if ( function_exists( 'app_update_available' ) ) {
				app_update_available( $post_id, false );
				$processed_ids[] = $post_id;
				$checked_count++;
			} else {
				error_log( '[APK Updates Cron] Function app_update_available() not found!' );
				// Hanya log sekali agar tidak spam
				break;
			}
		}

		// Logging hasil batch
		$message = "[APK Updates Cron] Batch completed: Checked {$checked_count} application (ID: " . implode( ', ', $processed_ids ) . "). Interval: {$min_interval_hours} hours.";
		error_log( $message );

		// Simpan riwayat log (maksimal 20 entri terakhir)
		$log_entry = [
			'time'    => current_time( 'mysql' ),
			'message' => $message,
		];
		$existing_log = get_option( 'app_update_cron_last_log', [] );
		if ( ! is_array( $existing_log ) ) {
			$existing_log = [];
		}
		array_unshift( $existing_log, $log_entry );
		update_option( 'app_update_cron_last_log', array_slice( $existing_log, 0, 20 ) );

		// Jika batch terpakai penuh → kemungkinan masih banyak yang antri → jadwalkan lagi
		if ( $checked_count === $batch_size ) {
			wp_schedule_single_event( time() + 300, 'check_all_apps_cron' ); // delay 5 menit
		}

		// Lepas lock
		delete_transient( 'app_update_global_cron_lock' );
	}
}


if ( ! function_exists( 'app_update_handle_force_check123' ) ) 
{
	// 4. Handler tombol "Check All Apps Now" di halaman admin
	//add_action( 'admin_init', 'app_update_handle_force_check123' );
	function app_update_handle_force_check123() 
	{
		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		if ( isset( $_GET['app_update_force_check'] ) && 
			 check_admin_referer( 'app_update_force_check_all' ) ) {

			// Hapus lock jika ada, lalu mulai proses
			delete_transient( 'app_update_global_cron_lock' );

			// Jadwalkan eksekusi segera
			wp_schedule_single_event( time(), 'check_all_apps_cron' );

			// Tampilkan notice sukses
			add_action( 'admin_notices', function() {
				echo '<div class="notice notice-success is-dismissible">
						<p><strong>' . __( 'Manual app update check has been started!', 'your-text-domain' ) . '</strong><br>
						It will run in the background in batches. You can continue working.</p>
					  </div>';
			} );

			// Redirect bersih tanpa parameter
			wp_redirect( remove_query_arg( [ 'app_update_force_check', '_wpnonce' ] ) );
			exit;
		}
	}
}


if ( ! function_exists( 'apps_updates_page1234' ) ) 
{
	function apps_updates_page1234() 
	{
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( __( 'Permission denied.', TEXT_DOMAIN ) );
		}
		$nonce = wp_create_nonce( 'apps_updates_nonce' );
		$force_check_url = wp_nonce_url(
			add_query_arg( 'app_update_force_check', '1' ),
			'app_update_force_check_all'
		);
		$total = apk_update_count_posts();
		?>
		<div class="wrap">
			<h1 class="wp-heading-inline"><?php esc_html_e( 'Apps Updates List', TEXT_DOMAIN ); ?></h1>
			<a href="<?php echo esc_url( $force_check_url ); ?>" class="page-title-action">
				<?php esc_html_e( 'Check All Apps Now', TEXT_DOMAIN ); ?>
			</a>
			
			<hr class="wp-header-end">
	 
			<div id="fastcheck-results"></div>

			<div id="update-progress" style="display:none; margin:20px 0;">
				<div class="notice notice-info inline is-dismissible">
					<p><strong id="progress-title">Processing...</strong></p>
					<p><span id="progress-text">0 of 0</span></p>
					<div style="background:#ddd; height:20px; border-radius:4px; overflow:hidden; margin:10px 0;">
						<div id="progress-bar" style="width:0%; height:100%; background:#0073aa; transition:width .4s ease;"></div>
					</div>
					<p id="progress-status">Starting...</p>
				</div>
			</div>

			<h2 style="font-weight: 700;">
				<strong><span id="updates-count">Loading...</span></strong> app(s) need update
			</h2>

			<form id="apps-updates-form" method="get">
				<?php wp_nonce_field( 'apps_updates_nonce', 'apps_updates_nonce_field' ); ?>

				<div class="tablenav top">
					<div class="alignleft actions bulkactions">
						<select name="action" id="bulk-action-selector-top">
							<option value="-1"><?php esc_html_e( 'Bulk actions', TEXT_DOMAIN ); ?></option>
							<option value="update-selected"><?php esc_html_e( 'Update Selected', TEXT_DOMAIN ); ?></option>
							<option value="fastcheck-selected"><?php esc_html_e( 'Fast Check Selected', TEXT_DOMAIN ); ?></option>
							<option value="fastcheck-debug"><?php esc_html_e( 'Fast Check Selected (Debug Mode)', TEXT_DOMAIN ); ?></option>
						</select>
						<input type="button" id="doaction" class="button action" value="<?php esc_attr_e( 'Apply', TEXT_DOMAIN ); ?>">
						<input type="button" id="check-all-visible" class="button action" value="<?php esc_attr_e( '⚡ Check All Visible', TEXT_DOMAIN ); ?>" style="margin-left:8px;">
					</div>

					<!-- KOLOM PENCARIAN -->
					<div class="alignright">
						<input type="search" id="apps-search-input" placeholder="<?php esc_attr_e( 'Search apps...', TEXT_DOMAIN ); ?>" value="" />
						<input type="button" id="apps-search-submit" class="button" value="<?php esc_attr_e( 'Search Apps', TEXT_DOMAIN ); ?>">
						<input type="button" id="apps-search-reset" class="button" value="<?php esc_attr_e( 'Reset', TEXT_DOMAIN ); ?>" style="display:none;">
					</div>

					<div id="top-pagination" class="tablenav-pages"></div>
					<br class="clear">
				</div>

				<div id="updates-table-container">
					<?php esc_html_e( 'Loading...', TEXT_DOMAIN ); ?>
				</div>

				<div class="tablenav bottom">
					<div class="alignleft actions bulkactions">
						<select name="action2" id="bulk-action-selector-bottom">
							<option value="-1"><?php esc_html_e( 'Bulk actions', TEXT_DOMAIN ); ?></option>
							<option value="update-selected"><?php esc_html_e( 'Update Selected', TEXT_DOMAIN ); ?></option>
							<option value="fastcheck-selected"><?php esc_html_e( 'Fast Check Selected', TEXT_DOMAIN ); ?></option>
							<option value="fastcheck-debug"><?php esc_html_e( 'Fast Check Selected (Debug Mode)', TEXT_DOMAIN ); ?></option>
						</select>
						<input type="button" id="doaction2" class="button action" value="<?php esc_attr_e( 'Apply', TEXT_DOMAIN ); ?>">
						<input type="button" id="check-all-visible-bottom" class="button action" value="<?php esc_attr_e( '⚡ Check All Visible', TEXT_DOMAIN ); ?>" style="margin-left:8px;">
					</div>
					<div id="bottom-pagination" class="tablenav-pages"></div>
					<br class="clear">
				</div>
			</form>
		</div>

		<style>
			.updating-row { background:#fffbe6 !important; border-left:4px solid #ffb900; }
			.updated-row { background:#e6f7e6 !important; border-left:4px solid #00ba37; }
			.error-row { background:#fdeaea !important; border-left:4px solid #d63638; }
			.checking-row { background:#fff9e6 !important; border-left:4px solid #ffba00; }
			.no-update-row { background:#f8f8f8 !important; border-left:4px solid #aaa; }
		</style>

		<script>
		jQuery(function($) {
			const nonce = '<?php echo esc_js( $nonce ); ?>';
			let currentPage = 1;
			let currentSearch = '';
			let totalItems = 0;
			let isProcessing = false;
			let searchTimeout;

			function loadPage(page = 1, search = currentSearch) {
				currentPage = page;
				currentSearch = search.trim();

				$('#updates-table-container').html('<p>Loading...</p>');

				$.post(ajaxurl, {
					action: 'apk_render_updates_list',
					paged: page,
					s: currentSearch,
					nonce: nonce
				})
				.done(function(res) {
					if (res.success) {
						$('#updates-table-container').html(res.data.table);
						$('#top-pagination, #bottom-pagination').html(res.data.pagination);
						totalItems = res.data.total;
						$('#updates-count').text(totalItems > 0 ? totalItems : 'No');

						// Update admin menu badge
						const $badge = $('#toplevel_page_apps_updates .update-plugins');
						if (totalItems > 0) {
							$badge.show().find('.plugin-count').text(totalItems);
						} else {
							$badge.hide();
						}

						// Update search input & reset button
						$('#apps-search-input').val(currentSearch);
						$('#apps-search-reset').toggle(currentSearch !== '');
					}
				});
			}

			// Load pertama kali
			loadPage(1);

			// Auto refresh setiap 30 detik (hanya jika tidak ada pencarian aktif)
			setInterval(() => {
				if (isProcessing || currentSearch !== '') return;
				$.post(ajaxurl, {
					action: 'apk_render_updates_list',
					paged: currentPage,
					s: currentSearch,
					nonce: nonce
				})
				.done(res => {
					if (res.success && res.data.total != totalItems) {
						loadPage(currentPage, currentSearch);
					}
				});
			}, 30000);

			// Pagination
			$(document).on('click', '.tablenav-pages a', function(e) {
				e.preventDefault();
				const page = $(this).data('page');
				if (page) loadPage(page, currentSearch);
			});

			// Search: debounce input
			$('#apps-search-input').on('keyup', function(e) {
				clearTimeout(searchTimeout);
				const val = $(this).val().trim();

				// Enter key = langsung search
				if (e.which === 13) {
					e.preventDefault();
					loadPage(1, val);
					return;
				}

				searchTimeout = setTimeout(() => {
					loadPage(1, val);
				}, 500);
			});

			// Tombol Search
			$('#apps-search-submit').on('click', function() {
				const val = $('#apps-search-input').val().trim();
				loadPage(1, val);
			});

			// Tombol Reset
			$('#apps-search-reset').on('click', function() {
				$('#apps-search-input').val('');
				loadPage(1, '');
			});

			// Checkbox select all
			$(document).on('change', '#cb-select-all-1, #cb-select-all-2', function() {
				$('#the-list input[name="post[]"]').prop('checked', this.checked);
			});

			// Single actions
			$(document).on('click', '.single-update', function(e) {
				e.preventDefault();
				const id = $(this).data('id');
				if (id) runProcess([id], 'ajax_update_single_app', 'Updating', false);
			});

			$(document).on('click', '.single-fastcheck', function(e) {
				e.preventDefault();
				const id = $(this).data('id');
				if (id && confirm('Fast check this app only?')) {
					runProcess([id], 'ajax_fastcheck_single_app', 'Fast checking', false);
				}
			});

			// Bulk actions
			$('#doaction, #doaction2').on('click', function() {
				const action = $(this).prev('select').val();
				const ids = $('#the-list input[name="post[]"]:checked').map(function() {
					return parseInt(this.value, 10);
				}).get();

				if (ids.length === 0) {
					alert('Please select at least one app.');
					return;
				}

				if (action === 'update-selected') {
					runProcess(ids, 'ajax_update_single_app', 'Updating', false);
				} else if (action === 'fastcheck-selected') {
					runProcess(ids, 'ajax_fastcheck_single_app', 'Fast checking', false);
				} else if (action === 'fastcheck-debug') {
					runProcess(ids, 'ajax_fastcheck_single_app', 'Fast checking (DEBUG)', true);
				}
			});

			// Check all visible
			$('#check-all-visible, #check-all-visible-bottom').on('click', function() {
				const ids = $('#the-list input[name="post[]"]').map(function() {
					return parseInt(this.value, 10);
				}).get();

				if (ids.length === 0) {
					alert('No apps visible on this page.');
					return;
				}

				if (confirm(`Fast check ${ids.length} app${ids.length > 1 ? 's' : ''} on this page?`)) {
					runProcess(ids, 'ajax_fastcheck_single_app', 'Fast checking', false);
				}
			});

			// Proses bulk/single (tetap sama)
			function runProcess(ids, ajaxAction, titlePrefix, debugMode = false) {
				if (isProcessing) return;
				isProcessing = true;
				$('#update-progress').show();
				$('#progress-title').text(`${titlePrefix} ${ids.length} app${ids.length > 1 ? 's' : ''}...`);
				$('#progress-text').text('0 of ' + ids.length);
				$('#progress-bar').css('width', '0%');
				$('#progress-status').text('Starting...');

				let processed = 0;
				let updateFound = 0;
				let upToDate = 0;
				let errors = 0;
				let details = [];

				function processNext() {
					if (processed >= ids.length) {
						let resultHTML = '<div class="notice notice-success is-dismissible" style="margin:15px 0;">';
						resultHTML += `<p><strong>Process Completed!</strong> Processed ${ids.length} app${ids.length > 1 ? 's' : ''}. `;
						if (updateFound > 0) resultHTML += `<span style="color:#00a32a;">${updateFound} update available</span>. `;
						if (upToDate > 0) resultHTML += `${upToDate} up to date. `;
						if (errors > 0) resultHTML += `<span style="color:#d63638;">${errors} failed</span>.`;
						resultHTML += '</p></div>';

						if (details.length > 0) {
							resultHTML += '<div style="margin:15px 0; padding:10px; background:#f9f9f9; border-left:4px solid #0073aa; border-radius:4px;">';
							resultHTML += '<p><strong>Details:</strong></p><ul style="margin-left:20px;">';
							details.forEach(d => resultHTML += `<li>${d}</li>`);
							resultHTML += '</ul></div>';
						}

						$('#fastcheck-results').html(resultHTML);
						$('#progress-status').html('<span style="color:green;">Completed!</span>');
						$('#progress-bar').css('width', '100%');

						setTimeout(() => {
							$('#update-progress').hide();
							loadPage(currentPage, currentSearch); // reload dengan search term yang sama
							isProcessing = false;
						}, 2000);
						return;
					}

					const id = ids[processed];
					const $row = $('#post-' + id);
					const name = $row.find('.row-title').text().trim() || 'App #' + id;
					$row.addClass(ajaxAction === 'ajax_fastcheck_single_app' ? 'checking-row' : 'updating-row');
					$('#progress-status').text(`${titlePrefix}: ${name}`);

					$.post(ajaxurl, {
						action: ajaxAction,
						post_id: id,
						nonce: nonce,
						debug: debugMode ? 1 : 0
					})
					.done(res => {
						$row.removeClass('checking-row updating-row');
						let statusText = '';
						if (res.success) {
							if (res.data && res.data.needs_update) {
								$row.addClass('updated-row');
								updateFound++;
								statusText = `<strong>${name}</strong> → <span style="color:green;">Update available</span>`;
							} else {
								$row.addClass('no-update-row');
								upToDate++;
								statusText = `<strong>${name}</strong> → It's up to date`;
							}
						} else {
							$row.addClass('error-row');
							errors++;
							statusText = `<strong>${name}</strong> → <span style="color:red;">Failed check</span>`;
						}
						details.push(statusText);

						if (debugMode && res.data && res.data.debug) {
							console.log(`%c[DEBUG] ${name} (ID: ${id})`, 'color: #00bcd4; font-weight: bold;');
							console.log(res.data.debug);
						}
					})
					.fail(() => {
						$row.removeClass('checking-row updating-row').addClass('error-row');
						errors++;
						details.push(`<strong>${name}</strong> → <span style="color:red;">Request failed</span>`);
					})
					.always(() => {
						processed++;
						$('#progress-text').text(processed + ' of ' + ids.length);
						$('#progress-bar').css('width', (processed / ids.length * 100) + '%');
						setTimeout(processNext, debugMode ? 800 : 600);
					});
				}

				processNext();
			}
		});
		</script>
		<?php
	}
}


/* 2. Handle "Check All Now" click */
/* add_action( 'admin_init', 'available_updates_handle_force_check' );

function available_updates_handle_force_check() {
    if ( ! is_admin() || ! current_user_can( 'edit_posts' ) ) {
        return;
    }

    if ( ! isset( $_GET['app_update_force_check'] ) || $_GET['app_update_force_check'] !== '1' ) {
        return;
    }

    check_ajax_referer( 'app_update_force_check_all' );

    // Run the full update check
    available_updates_run_apk_update_checks();

    // Optional: add admin notice on redirect
    add_option( 'app_update_force_check_notice', 'Full update check completed!' );

    // Redirect to clean URL (remove query arg)
    wp_redirect( remove_query_arg( 'app_update_force_check' ) );
    exit;
} */

/* Optional: Show success notice after force check */
/* add_action( 'admin_notices', function() {
    if ( $msg = get_option( 'app_update_force_check_notice' ) ) {
        echo '<div class="notice notice-success is-dismissible"><p>' . esc_html( $msg ) . '</p></div>';
        delete_option( 'app_update_force_check_notice' );
    }
} ); */

/* 3. Full update checker function */
/* function available_updates_run_apk_update_checks( $debug = false ) {
    // Prevent overlapping runs
    if ( get_transient( 'available_updates_global_update_check_lock' ) ) {
        if ( $debug ) {
            echo "[SKIP] Another update check is already running.\n";
        }
        return;
    }

    set_transient( 'available_updates_global_update_check_lock', true, 15 * MINUTE_IN_SECONDS );

    if ( $debug ) {
        echo "Starting full Apps update check...\n";
    }

    $query = new WP_Query( array(
        'post_type'      => 'post',
        'post_status'    => 'publish',
        'posts_per_page' => -1,
        'meta_query'     => array(
            array(
                'key'     => 'wp_GP_ID',
                'value'   => '',
                'compare' => '!=',
            ),
        ),
        'fields'         => 'ids',
        'no_found_rows'  => true,
    ) );

    $total_apps = count( $query->posts );

    if ( $total_apps === 0 ) {
        if ( $debug ) {
            echo "No apps found with Google Play ID.\n";
        }
        delete_transient( 'available_updates_global_update_check_lock' );
        return;
    }

    if ( $debug ) {
        echo "Found {$total_apps} apps to check...\n";
    }

    $updated_count = 0;
    $checked_count  = 0;

    foreach ( $query->posts as $post_id ) {
        $checked_count++;
        @set_time_limit( 30 ); // Prevent timeout on large sites

        if ( $debug && $checked_count % 50 === 0 ) {
            echo "Checked {$checked_count}/{$total_apps}...\n";
        }

        $has_update = app_update_available( $post_id, $debug );

        if ( $has_update ) {
            $updated_count++;
            if ( $debug ) {
                $title = get_the_title( $post_id );
                $ver   = get_post_meta( $post_id, 'available_version', true );
                echo "UPDATE FOUND → #{$post_id} {$title} → v{$ver}\n";
            }
        }
    }

    delete_transient( 'available_updates_global_update_check_lock' );

    if ( $debug ) {
        echo "Finished! Checked: {$checked_count}, Updates found: {$updated_count}\n";
    }

    do_action( 'available_updates_full_update_check_complete', $updated_count, $total_apps );
} */

