<?php

namespace RemoveUnusedMedia\Queue;

require_once 'rum_util.php';
require_once 'rum_db.php';
use RemoveUnusedMedia\Util as Util;
use RemoveUnusedMedia\DB as DB;
use RemoveUnusedMedia\Core as Core;
use function RemoveUnusedMedia\Util\debug_logging;
function get_post_batch_size() : int {
    return 15;
}

function create_queue_table() : array {
    global $wpdb;
    $table_name = $wpdb->prefix . 'rum_queue';
    if ( $wpdb->get_var( "SHOW TABLES LIKE '{$table_name}'" ) === $table_name ) {
        return [];
    }
    $charset_collate = $wpdb->get_charset_collate();
    $sql = "CREATE TABLE {$table_name} (\n      id BIGINT AUTO_INCREMENT PRIMARY KEY,\n      task VARCHAR(32) NOT NULL,\n      data VARCHAR(32),\n      status VARCHAR(20) DEFAULT 'pending',\n      created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\n      updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP\n    ) {$charset_collate};";
    require_once ABSPATH . 'wp-admin/includes/upgrade.php';
    return dbDelta( $sql );
}

function start_analysing_queue() : void {
    update_option( 'rum_analysis_running', __( 'Starting Analysis', 'remove-unused-media' ) );
    update_option( 'rum_analysis_running', [
        'status' => __( 'Starting Analysis (Free Version - Limited to 15 images)', 'remove-unused-media' ),
        'media'  => [0, min( 15, Util\num_media() )],
        'posts'  => [0, Util\num_posts()],
    ] );
    update_option( 'rum_error_types', [] );
    DB\drop( 'rum_result' );
    DB\create_result_table();
    clear_queue();
    create_queue_table();
    enqueue_task( 'list_of_images', 0 );
}

function clear_queue() : void {
    global $wpdb;
    $table = $wpdb->prefix . 'rum_queue';
    $wpdb->query( "DROP TABLE {$table}" );
}

function enqueue_task(  string $task, $data = null  ) : void {
    global $wpdb;
    $table_name = $wpdb->prefix . 'rum_queue';
    $wpdb->insert( $table_name, [
        'task'   => $task,
        'data'   => maybe_serialize( $data ),
        'status' => 'pending',
    ], ['%s', '%s', '%s'] );
}

function process_next_task() : bool {
    global $wpdb;
    $table = $wpdb->prefix . 'rum_queue';
    $task_row = $wpdb->get_row( "SELECT * FROM {$table} WHERE status = 'pending' ORDER BY id ASC LIMIT 1" );
    if ( !$task_row ) {
        finalize_analyse();
        return false;
    }
    // Update status before processing
    $wpdb->update( $table, [
        'status' => 'processing',
    ], [
        'id' => $task_row->id,
    ] );
    $task_function = "\\RemoveUnusedMedia\\Queue\\task_" . $task_row->task;
    if ( is_callable( $task_function ) ) {
        $data = maybe_unserialize( $task_row->data );
        try {
            debug_logging( 'Running task: ' . $task_function . ' - with data: ' . print_r( $data, true ) );
            call_user_func( $task_function, $data );
        } catch ( \Throwable $e ) {
            debug_logging( 'Can not run task: ' . $e->getMessage() );
            $wpdb->update( $table, [
                'status' => 'failed',
            ], [
                'id' => $task_row->id,
            ] );
            update_remaining_task_status();
            throw $e;
        }
    } else {
        $wpdb->update( $table, [
            'status' => 'invalid_task',
        ], [
            'id' => $task_row->id,
        ] );
        update_remaining_task_status();
        return true;
    }
    // Delete completed task
    $wpdb->delete( $table, [
        'id' => $task_row->id,
    ] );
    // Update status again
    update_remaining_task_status();
    return true;
}

function update_remaining_task_status() : void {
    global $wpdb;
    $table = $wpdb->prefix . 'rum_queue';
    $remaining = (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$table} WHERE status = 'pending'" );
    debug_logging( "Remaining tasks: {$remaining}" );
    if ( $remaining <= 0 ) {
        finalize_analyse();
    }
}

register_deactivation_hook( __FILE__, function () {
    clear_queue();
} );
function cron_process_queue() {
    process_next_task();
}

// Queue Tasks
function task_list_of_images(  int $batch = 0  ) {
    $offset = $batch * 15;
    $total = Util\num_media();
    $total = min( 15, $total );
    Util\debug_logging( "list_of_images batch {$batch} (offset {$offset}) - total images: {$total}" );
    Core\update_status( __( 'Compiling list of media', 'remove-unused-media' ) );
    $to_posts = $offset + 15;
    if ( $to_posts > $total ) {
        $to_posts = $total;
    }
    Core\update_status( sprintf(
        __( 'Compiling list of media %d to %d of %d (Free version limited to 15)', 'remove-unused-media' ),
        $offset,
        $to_posts,
        $total
    ) );
    $site_url_len = strlen( get_site_url() );
    foreach ( Util\get_media( $offset ) as $id ) {
        $url = wp_get_attachment_url( $id );
        $url_warning = !filter_var( $url, FILTER_VALIDATE_URL );
        DB\insert( DB\RESULT, [
            'id'          => $id,
            'url'         => substr( $url, $site_url_len ),
            'url_warning' => $url_warning,
        ] );
    }
    enqueue_task( 'find_media', 0 );
}

function task_find_media(  int $batch = 0  ) {
    $batch_size = get_post_batch_size();
    $offset = $batch * $batch_size;
    $total_post_number = Util\num_posts();
    Util\debug_logging( "find_media batch {$batch} (offset {$offset})" );
    $to_posts = $offset + $batch_size;
    if ( $to_posts > $total_post_number ) {
        $to_posts = $total_post_number;
    }
    Core\update_status( sprintf(
        __( 'Analyzing posts %d to %d of %d', 'remove-unused-media' ),
        $offset,
        $to_posts,
        $total_post_number
    ) );
    foreach ( Util\get_posts( false, $offset ) as $post_id ) {
        Core\find_media_in_content();
        Core\find_media_in_thumbnail();
        Core\find_media_meta();
    }
    $total = Util\num_posts();
    $next_offset = ($batch + 1) * $batch_size;
    if ( $next_offset < $total ) {
        enqueue_task( 'find_media', $batch + 1 );
    } else {
        enqueue_task( 'global_scan', 0 );
    }
}

function task_global_scan() {
    Util\debug_logging( "Starting global scan" );
    Core\update_status( __( 'Compiling results (Free version - limited scan)', 'remove-unused-media' ) );
    Core\update_status( __( 'Compiling results', 'remove-unused-media' ) );
    Core\analytics();
    Util\debug_logging( "Global scan completed" );
}

function finalize_analyse() {
    update_option( 'rum_analysis_running', __( 'Analysis complete (Free version - upgrade for full analysis).', 'remove-unused-media' ) );
    Util\debug_logging( "analysis complete" );
    update_option( 'rum_time', current_time( 'timestamp' ) );
    $analysis_counter = get_option( 'rum_analysis_counter', 0 );
    ++$analysis_counter;
    update_option( 'rum_analysis_counter', $analysis_counter, false );
    if ( !get_option( 'rum_dismissed_backup', false ) && $analysis_counter >= 3 ) {
        update_option( 'rum_dismissed_backup', true, false );
    }
    delete_option( 'rum_analysis_running' );
    delete_option( 'rum_error' );
    delete_option( 'rum_crashed' );
}
