<?php

/**
 * Admin Tools Handlers (Integrity Check & Data Recovery Waveform).
 *
 * @package TheStudioPlayer
 */
if ( !defined( 'ABSPATH' ) ) {
    exit;
}
/**
 * Handle AJAX integrity check (Batch Processing).
 *
 * @return void
 */
function thespl_handle_integrity_check() {
    check_ajax_referer( 'thespl_muxer_nonce', 'nonce' );
    if ( !thespl_current_user_can_policy( 'tools_diagnose' ) ) {
        wp_send_json_error( array(
            'message' => __( 'Permission denied', 'the-studio-player' ),
        ) );
    }
    $phase = ( isset( $_POST['phase'] ) ? sanitize_text_field( wp_unslash( $_POST['phase'] ) ) : 'index' );
    $user_id = get_current_user_id();
    $transient_key = 'thespl_integrity_list_' . $user_id;
    if ( 'index' === $phase ) {
        $attachments = get_posts( array(
            'post_type'      => 'attachment',
            'post_status'    => 'inherit',
            'posts_per_page' => -1,
            'fields'         => 'ids',
            'no_found_rows'  => true,
            'cache_results'  => false,
        ) );
        $items = array();
        $path_counts = array();
        foreach ( $attachments as $post_id ) {
            $post_id = (int) $post_id;
            $attached_file = get_post_meta( $post_id, '_wp_attached_file', true );
            $extension = '';
            if ( is_string( $attached_file ) && '' !== $attached_file ) {
                $extension = strtolower( (string) pathinfo( $attached_file, PATHINFO_EXTENSION ) );
            }
            if ( '' === $extension ) {
                $mime_type = get_post_mime_type( $post_id );
                if ( 'audio/flac' === $mime_type ) {
                    $extension = 'flac';
                } elseif ( 'application/json' === $mime_type ) {
                    $extension = 'json';
                }
            }
            if ( !in_array( $extension, array('flac', 'json'), true ) ) {
                continue;
            }
            $fingerprint = get_post_meta( $post_id, '_thespl_fingerprint', true );
            $fingerprint = ( is_string( $fingerprint ) ? trim( $fingerprint ) : '' );
            if ( is_string( $attached_file ) && '' !== $attached_file ) {
                if ( !isset( $path_counts[$attached_file] ) ) {
                    $path_counts[$attached_file] = 0;
                }
                ++$path_counts[$attached_file];
            }
            $items[] = array(
                'post_id'     => $post_id,
                'fingerprint' => (string) $fingerprint,
                'path'        => ( is_string( $attached_file ) ? $attached_file : '' ),
            );
        }
        foreach ( $items as $index => $item ) {
            $item_path = ( isset( $item['path'] ) ? (string) $item['path'] : '' );
            $dup_count = ( '' !== $item_path && isset( $path_counts[$item_path] ) ? (int) $path_counts[$item_path] : 0 );
            $items[$index]['duplicate_count'] = $dup_count;
        }
        if ( empty( $items ) ) {
            wp_send_json_error( array(
                'message' => __( 'No audio or meta files found to check.', 'the-studio-player' ),
            ) );
        }
        set_transient( $transient_key, $items, HOUR_IN_SECONDS );
        wp_send_json_success( array(
            'message' => __( 'Indexing complete.', 'the-studio-player' ),
            'total'   => count( $items ),
        ) );
    }
    // Phase 2: Processing.
    $items = get_transient( $transient_key );
    if ( !is_array( $items ) ) {
        wp_send_json_error( array(
            'message' => __( 'Session expired or indexing failed.', 'the-studio-player' ),
        ) );
    }
    $offset = ( isset( $_POST['offset'] ) ? intval( $_POST['offset'] ) : 0 );
    $batch_size = 20;
    $batch = array_slice( $items, $offset, $batch_size );
    $valid_count = 0;
    $invalid_count = 0;
    $missing_count = 0;
    $unprotected_count = 0;
    $duplicate_count = 0;
    $details = array();
    foreach ( $batch as $item ) {
        $post_id = (int) $item['post_id'];
        $stored_fp = $item['fingerprint'];
        $file_path = get_attached_file( $post_id );
        $post_title = get_the_title( $post_id );
        $mime_type = get_post_mime_type( $post_id );
        $extension = '';
        if ( !empty( $file_path ) ) {
            $extension = strtolower( (string) pathinfo( $file_path, PATHINFO_EXTENSION ) );
        } elseif ( !empty( $mime_type ) ) {
            if ( 'audio/flac' === $mime_type ) {
                $extension = 'flac';
            } elseif ( 'application/json' === $mime_type ) {
                $extension = 'json';
            }
        }
        if ( !thespl_init_filesystem() ) {
            ++$missing_count;
            continue;
        }
        global $wp_filesystem;
        if ( !$file_path || !$wp_filesystem->exists( $file_path ) ) {
            ++$missing_count;
            $details[] = array(
                'id'        => $post_id,
                'title'     => $post_title,
                'status'    => 'missing',
                'mime_type' => (string) $mime_type,
                'extension' => (string) $extension,
            );
            continue;
        }
        $item_duplicate_count = ( isset( $item['duplicate_count'] ) ? (int) $item['duplicate_count'] : 0 );
        if ( $item_duplicate_count > 1 ) {
            ++$duplicate_count;
            $details[] = array(
                'id'              => $post_id,
                'title'           => $post_title,
                'status'          => 'duplicate',
                'mime_type'       => (string) $mime_type,
                'extension'       => (string) $extension,
                'duplicate_count' => $item_duplicate_count,
            );
            continue;
        }
        if ( empty( $stored_fp ) ) {
            ++$unprotected_count;
            $details[] = array(
                'id'        => $post_id,
                'title'     => $post_title,
                'status'    => 'unprotected',
                'mime_type' => (string) $mime_type,
                'extension' => (string) $extension,
            );
            continue;
        }
        $current_fp = thespl_generate_file_fingerprint( $file_path );
        if ( $current_fp === $stored_fp ) {
            ++$valid_count;
            $details[] = array(
                'id'        => $post_id,
                'title'     => $post_title,
                'status'    => 'valid',
                'mime_type' => (string) $mime_type,
                'extension' => (string) $extension,
            );
        } else {
            ++$invalid_count;
            $details[] = array(
                'id'        => $post_id,
                'title'     => $post_title,
                'status'    => 'corrupted',
                'mime_type' => (string) $mime_type,
                'extension' => (string) $extension,
            );
        }
    }
    $new_offset = $offset + count( $batch );
    $is_done = $new_offset >= count( $items );
    wp_send_json_success( array(
        'message'     => ( $is_done ? __( 'Integrity check complete.', 'the-studio-player' ) : __( 'Verifying...', 'the-studio-player' ) ),
        'valid'       => $valid_count,
        'invalid'     => $invalid_count,
        'missing'     => $missing_count,
        'unprotected' => $unprotected_count,
        'duplicate'   => $duplicate_count,
        'details'     => $details,
        'offset'      => $new_offset,
        'is_done'     => $is_done,
    ) );
}

add_action( 'wp_ajax_thespl_integrity_check', 'thespl_handle_integrity_check' );
/**
 * AJAX handler that validates streaming route accessibility for FLAC attachments.
 *
 * Expects a valid nonce ('thespl_muxer_nonce') and supports batched processing via the 'offset' POST parameter.
 * Responds with wp_send_json_success() including per-item route details and aggregated stats.
 *
 * @return void
 */
function thespl_handle_streaming_route_check() {
    check_ajax_referer( 'thespl_muxer_nonce', 'nonce' );
    if ( !thespl_current_user_can_policy( 'tools_diagnose' ) ) {
        wp_send_json_error( array(
            'message' => __( 'Permission denied', 'the-studio-player' ),
        ) );
    }
    $user_id = get_current_user_id();
    $transient_key = 'thespl_integrity_list_' . $user_id;
    $items = get_transient( $transient_key );
    if ( !is_array( $items ) || empty( $items ) ) {
        wp_send_json_error( array(
            'message' => __( 'Integrity session expired. Please run the integrity check again first.', 'the-studio-player' ),
        ) );
    }
    $offset = ( isset( $_POST['offset'] ) ? intval( $_POST['offset'] ) : 0 );
    $batch_size = 20;
    $batch = array_slice( $items, $offset, $batch_size );
    if ( empty( $batch ) ) {
        wp_send_json_success( array(
            'message' => __( 'Streaming route check complete.', 'the-studio-player' ),
            'details' => array(),
            'stats'   => array(),
            'offset'  => $offset,
            'is_done' => true,
        ) );
    }
    $stats = array(
        'ok'              => 0,
        'domain_mismatch' => 0,
        'http_4xx'        => 0,
        'http_5xx'        => 0,
        'redirect'        => 0,
        'error'           => 0,
        'no_url'          => 0,
        'unexpected'      => 0,
    );
    $details = array();
    foreach ( $batch as $item ) {
        $post_id = ( isset( $item['post_id'] ) ? (int) $item['post_id'] : 0 );
        $post_title = ( $post_id > 0 ? get_the_title( $post_id ) : '' );
        $route = array(
            'id'           => $post_id,
            'title'        => $post_title,
            'route_status' => 'error',
            'http_status'  => 0,
            'stream_host'  => '',
            'site_host'    => '',
        );
        if ( $post_id <= 0 ) {
            ++$stats['error'];
            $details[] = $route;
            continue;
        }
        $mime_type = get_post_mime_type( $post_id );
        if ( 'audio/flac' !== $mime_type ) {
            $route['route_status'] = 'meta_only';
            $details[] = $route;
            continue;
        }
        $stream_url = thespl_get_stream_url_for_attachment( $post_id );
        if ( '' === $stream_url ) {
            $route['route_status'] = 'no_url';
            ++$stats['no_url'];
            $details[] = $route;
            continue;
        }
        $stream_parts = wp_parse_url( $stream_url );
        $site_parts = wp_parse_url( site_url() );
        $stream_host = ( is_array( $stream_parts ) && isset( $stream_parts['host'] ) ? (string) $stream_parts['host'] : '' );
        $site_host = ( is_array( $site_parts ) && isset( $site_parts['host'] ) ? (string) $site_parts['host'] : '' );
        $route['stream_host'] = $stream_host;
        $route['site_host'] = $site_host;
        $args = array(
            'timeout'     => 5,
            'redirection' => 3,
        );
        $response = wp_remote_head( $stream_url, $args );
        if ( is_wp_error( $response ) ) {
            $route['route_status'] = 'error';
            ++$stats['error'];
            $details[] = $route;
            continue;
        }
        $code = wp_remote_retrieve_response_code( $response );
        $route['http_status'] = (int) $code;
        if ( $code >= 300 && $code < 400 ) {
            $route['route_status'] = 'redirect';
            ++$stats['redirect'];
            $details[] = $route;
            continue;
        }
        if ( $code >= 400 && $code < 500 ) {
            $route['route_status'] = 'http_4xx';
            ++$stats['http_4xx'];
            $details[] = $route;
            continue;
        }
        if ( $code >= 500 ) {
            $route['route_status'] = 'http_5xx';
            ++$stats['http_5xx'];
            $details[] = $route;
            continue;
        }
        if ( $code <= 0 ) {
            $route['route_status'] = 'error';
            ++$stats['error'];
            $details[] = $route;
            continue;
        }
        if ( '' !== $stream_host && '' !== $site_host && $stream_host !== $site_host ) {
            $route['route_status'] = 'domain_mismatch';
            ++$stats['domain_mismatch'];
            $details[] = $route;
            continue;
        }
        $route['route_status'] = 'ok';
        ++$stats['ok'];
        $details[] = $route;
    }
    $new_offset = $offset + count( $batch );
    $is_done = $new_offset >= count( $items );
    wp_send_json_success( array(
        'message' => ( $is_done ? __( 'Streaming route check complete.', 'the-studio-player' ) : __( 'Checking streaming routes...', 'the-studio-player' ) ),
        'details' => $details,
        'stats'   => $stats,
        'offset'  => $new_offset,
        'is_done' => $is_done,
    ) );
}

add_action( 'wp_ajax_thespl_streaming_route_check', 'thespl_handle_streaming_route_check' );
/**
 * AJAX handler that probes the playlist REST route responses.
 *
 * Iterates over all thespl_playlist posts and requests the endpoint /thespl/v1/playlist/{id},
 * collecting HTTP status and a derived route_status for reporting.
 *
 * @return void
 */
function thespl_handle_playlist_route_check() {
    check_ajax_referer( 'thespl_muxer_nonce', 'nonce' );
    if ( !thespl_current_user_can_policy( 'tools_diagnose' ) ) {
        wp_send_json_error( array(
            'message' => __( 'Permission denied', 'the-studio-player' ),
        ) );
    }
    $playlists = get_posts( array(
        'post_type'      => 'thespl_playlist',
        'post_status'    => array('publish', 'draft', 'private'),
        'posts_per_page' => -1,
        'fields'         => 'ids',
        'no_found_rows'  => true,
    ) );
    if ( empty( $playlists ) ) {
        wp_send_json_success( array(
            'message' => __( 'No playlists found for REST route check.', 'the-studio-player' ),
            'details' => array(),
            'stats'   => array(
                'ok'       => 0,
                'http_4xx' => 0,
                'http_5xx' => 0,
                'redirect' => 0,
                'error'    => 0,
            ),
        ) );
    }
    $base_rest = rest_url( 'thespl/v1' );
    $stats = array(
        'ok'       => 0,
        'http_4xx' => 0,
        'http_5xx' => 0,
        'redirect' => 0,
        'error'    => 0,
    );
    $details = array();
    foreach ( $playlists as $playlist_id ) {
        $playlist_id = (int) $playlist_id;
        if ( $playlist_id <= 0 ) {
            continue;
        }
        $title = get_the_title( $playlist_id );
        $url = trailingslashit( $base_rest ) . 'playlist/' . $playlist_id;
        $route = array(
            'id'           => $playlist_id,
            'title'        => $title,
            'http_status'  => 0,
            'route_status' => 'error',
            'url'          => $url,
        );
        $args = array(
            'timeout'     => 5,
            'redirection' => 3,
        );
        $response = wp_remote_get( $url, $args );
        if ( is_wp_error( $response ) ) {
            ++$stats['error'];
            $details[] = $route;
            continue;
        }
        $code = (int) wp_remote_retrieve_response_code( $response );
        $route['http_status'] = $code;
        if ( $code >= 300 && $code < 400 ) {
            $route['route_status'] = 'redirect';
            ++$stats['redirect'];
        } elseif ( $code >= 400 && $code < 500 ) {
            $route['route_status'] = 'http_4xx';
            ++$stats['http_4xx'];
        } elseif ( $code >= 500 ) {
            $route['route_status'] = 'http_5xx';
            ++$stats['http_5xx'];
        } elseif ( $code <= 0 ) {
            $route['route_status'] = 'error';
            ++$stats['error'];
        } else {
            $route['route_status'] = 'ok';
            ++$stats['ok'];
        }
        $details[] = $route;
    }
    wp_send_json_success( array(
        'message' => __( 'Playlist REST route check complete.', 'the-studio-player' ),
        'details' => $details,
        'stats'   => $stats,
    ) );
}

add_action( 'wp_ajax_thespl_playlist_route_check', 'thespl_handle_playlist_route_check' );
/**
 * Get absolute session directory for sample import.
 *
 * @param string $session Session ID.
 * @return string
 */
function thespl_sample_session_dir(  $session  ) {
    $uploads = wp_get_upload_dir();
    return trailingslashit( $uploads['basedir'] ) . 'the-studio-player/sample-import/' . sanitize_file_name( $session ) . '/';
}

/**
 * Resolve a sample import manifest path inside the current session directory.
 *
 * @param string $base_dir      Absolute session base directory.
 * @param string $relative_path Relative path from the manifest entry.
 * @return string
 */
function thespl_sample_resolve_manifest_path(  $base_dir, $relative_path  ) {
    if ( !is_string( $base_dir ) || '' === $base_dir || !is_string( $relative_path ) ) {
        return '';
    }
    $base_real = realpath( $base_dir );
    if ( false === $base_real || !is_dir( $base_real ) ) {
        return '';
    }
    $relative_path = trim( $relative_path );
    if ( '' === $relative_path ) {
        return '';
    }
    $relative_path = ltrim( $relative_path, '/\\' );
    $relative_path = str_replace( '\\', '/', $relative_path );
    if ( 0 !== validate_file( $relative_path ) ) {
        return '';
    }
    $base_normalized = trailingslashit( wp_normalize_path( $base_real ) );
    $candidate = $base_normalized . ltrim( $relative_path, '/' );
    $candidate_real = realpath( $candidate );
    if ( false === $candidate_real || !is_file( $candidate_real ) ) {
        return '';
    }
    $candidate_normalized = wp_normalize_path( $candidate_real );
    if ( 0 !== strpos( $candidate_normalized, $base_normalized ) ) {
        return '';
    }
    return $candidate_real;
}

/**
 * Cleanup session directory and transient for sample import.
 *
 * @param string $session Session ID.
 * @return void
 */
function thespl_sample_cleanup_by_session(  $session  ) {
    $base = thespl_sample_session_dir( $session );
    if ( is_dir( $base ) && thespl_init_filesystem() ) {
        global $wp_filesystem;
        $wp_filesystem->rmdir( $base, true );
    }
    $user_id = get_current_user_id();
    if ( $user_id ) {
        delete_transient( 'thespl_sample_import_' . $user_id . '_' . $session );
    }
}

/**
 * Unzip a sample package with WordPress core file helpers.
 *
 * @param string $zip_path   Absolute path to ZIP file.
 * @param string $target_dir Target directory for extracted files.
 * @return true|WP_Error
 */
function thespl_sample_unzip_direct(  $zip_path, $target_dir  ) {
    if ( !is_readable( $zip_path ) ) {
        return new WP_Error('thespl_zip_not_readable', __( 'Sample ZIP is not readable.', 'the-studio-player' ));
    }
    if ( !function_exists( 'unzip_file' ) ) {
        /*
         * Load the core file helpers inside the function and use unzip_file()
         * immediately afterwards. This follows the allowed WordPress.org pattern
         * for core admin includes that are needed for a concrete file operation.
         */
        require_once ABSPATH . 'wp-admin/includes/file.php';
    }
    if ( !thespl_init_filesystem() ) {
        return new WP_Error('thespl_unzip_filesystem_init_failed', __( 'Filesystem initialization failed.', 'the-studio-player' ));
    }
    global $wp_filesystem;
    if ( !$wp_filesystem->is_dir( $target_dir ) && !$wp_filesystem->mkdir( $target_dir, FS_CHMOD_DIR ) ) {
        return new WP_Error('thespl_unzip_mkdir_failed', __( 'Could not create sample import directory.', 'the-studio-player' ));
    }
    $unzip = unzip_file( $zip_path, $target_dir );
    if ( is_wp_error( $unzip ) ) {
        return $unzip;
    }
    return true;
}

/**
 * Check whether a sample package download URL is allowed.
 *
 * @param string $url Raw download URL.
 * @return bool True when the URL uses HTTPS and the allowed host.
 */
function thespl_is_allowed_sample_download_url(  $url  ) {
    if ( !is_string( $url ) ) {
        return false;
    }
    $url = trim( $url );
    if ( '' === $url ) {
        return false;
    }
    $parts = wp_parse_url( $url );
    if ( !is_array( $parts ) ) {
        return false;
    }
    $scheme = ( isset( $parts['scheme'] ) ? strtolower( (string) $parts['scheme'] ) : '' );
    $host = ( isset( $parts['host'] ) ? strtolower( (string) $parts['host'] ) : '' );
    if ( 'https' !== $scheme || 'studioplayer.de' !== $host ) {
        return false;
    }
    if ( isset( $parts['user'] ) || isset( $parts['pass'] ) ) {
        return false;
    }
    return true;
}

/**
 * Initialize the sample data import and create a session.
 *
 * @return void
 */
function thespl_ajax_sample_import_start() {
    check_ajax_referer( 'thespl_sample_import', '_wpnonce' );
    if ( !current_user_can( 'manage_options' ) ) {
        wp_send_json_error( array(
            'message' => __( 'Permission denied - This action is available for administrators only.', 'the-studio-player' ),
        ) );
    }
    $base = ( function_exists( 'thespl_get_remote_base_api_url' ) ? thespl_get_remote_base_api_url() : '' );
    if ( '' === $base ) {
        wp_send_json_error( array(
            'message' => __( 'Remote API unavailable.', 'the-studio-player' ),
        ) );
    }
    $url = $base . '/sample-pack';
    if ( function_exists( 'thespl_get_remote_common_query_args' ) ) {
        $url = add_query_arg( thespl_get_remote_common_query_args(), $url );
    }
    $url = apply_filters( 'thespl_sample_pack_endpoint', $url );
    $r = wp_remote_get( $url, array(
        'timeout'     => 15,
        'redirection' => 3,
    ) );
    if ( is_wp_error( $r ) ) {
        wp_send_json_error( array(
            'message' => __( 'Request failed.', 'the-studio-player' ),
        ) );
    }
    $code = (int) wp_remote_retrieve_response_code( $r );
    if ( $code < 200 || $code >= 300 ) {
        $body = wp_remote_retrieve_body( $r );
        $msg = '';
        if ( is_string( $body ) && '' !== $body ) {
            $decoded = json_decode( $body, true );
            if ( is_array( $decoded ) && isset( $decoded['message'] ) && is_string( $decoded['message'] ) && '' !== $decoded['message'] ) {
                $msg = $decoded['message'];
            }
        }
        if ( '' === $msg ) {
            $msg = __( 'HTTP error.', 'the-studio-player' );
        }
        wp_send_json_error( array(
            'message' => $msg,
        ) );
    }
    $body = wp_remote_retrieve_body( $r );
    $j = json_decode( (string) $body, true );
    if ( !is_array( $j ) ) {
        wp_send_json_error( array(
            'message' => __( 'Invalid response.', 'the-studio-player' ),
        ) );
    }
    $pack_id = ( isset( $j['pack_id'] ) ? (string) $j['pack_id'] : '' );
    $pack_version = ( isset( $j['pack_version'] ) ? (string) $j['pack_version'] : '' );
    $size = ( isset( $j['size'] ) ? (int) $j['size'] : 0 );
    $checksum = ( isset( $j['checksum'] ) ? (string) $j['checksum'] : '' );
    $download_url = ( isset( $j['download_url'] ) ? (string) $j['download_url'] : '' );
    $sample = ( isset( $j['sample'] ) ? (bool) $j['sample'] : false );
    if ( '' === $pack_id || '' === $pack_version || $size <= 0 || '' === $checksum || !$sample ) {
        wp_send_json_error( array(
            'message' => __( 'Invalid pack.', 'the-studio-player' ),
        ) );
    }
    if ( '' === $download_url ) {
        $download_url = trailingslashit( $base ) . 'sample-pack/download';
        $download_url = apply_filters( 'thespl_sample_pack_download_endpoint', $download_url );
    }
    if ( !thespl_is_allowed_sample_download_url( $download_url ) ) {
        wp_send_json_error( array(
            'message' => __( 'Sample package download host is not allowed.', 'the-studio-player' ),
        ) );
    }
    $session = wp_generate_password( 12, false, false );
    $base_dir = thespl_sample_session_dir( $session );
    if ( !is_dir( $base_dir ) && !wp_mkdir_p( $base_dir ) ) {
        wp_send_json_error( array(
            'message' => __( 'Could not create session directory.', 'the-studio-player' ),
        ) );
    }
    $user_id = get_current_user_id();
    $key = 'thespl_sample_import_' . $user_id . '_' . $session;
    $state = array(
        'session'          => $session,
        'pack_id'          => $pack_id,
        'pack_version'     => $pack_version,
        'download_url'     => $download_url,
        'total_bytes'      => $size,
        'downloaded_bytes' => 0,
        'checksum'         => $checksum,
    );
    set_transient( $key, $state, HOUR_IN_SECONDS );
    wp_send_json_success( array(
        'session'     => $session,
        'total_bytes' => $size,
    ) );
}

/**
 * Download next chunk of the sample package.
 *
 * @return void
 */
function thespl_ajax_sample_import_fetch() {
    check_ajax_referer( 'thespl_sample_import', '_wpnonce' );
    if ( !current_user_can( 'manage_options' ) ) {
        wp_send_json_error( array(
            'message' => __( 'Permission denied - This action is available for administrators only.', 'the-studio-player' ),
        ) );
    }
    $session = ( isset( $_POST['session'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['session'] ) ) : '' );
    if ( '' === $session ) {
        wp_send_json_error( array(
            'message' => __( 'Missing session.', 'the-studio-player' ),
        ) );
    }
    $user_id = get_current_user_id();
    $key = 'thespl_sample_import_' . $user_id . '_' . $session;
    $state = get_transient( $key );
    if ( !is_array( $state ) ) {
        wp_send_json_error( array(
            'message' => __( 'Session expired.', 'the-studio-player' ),
        ) );
    }
    $total = ( isset( $state['total_bytes'] ) ? (int) $state['total_bytes'] : 0 );
    $done = ( isset( $state['downloaded_bytes'] ) ? (int) $state['downloaded_bytes'] : 0 );
    if ( $done >= $total && $total > 0 ) {
        wp_send_json_success( array(
            'downloaded_bytes' => $done,
            'done'             => true,
        ) );
    }
    $url = ( isset( $state['download_url'] ) ? (string) $state['download_url'] : '' );
    if ( '' === $url ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'Download URL missing.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    if ( !thespl_is_allowed_sample_download_url( $url ) ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'Sample package download host is not allowed.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    $chunk = ( defined( 'THESPL_SAMPLE_CHUNK_BYTES' ) ? (int) THESPL_SAMPLE_CHUNK_BYTES : 2097152 );
    $end = min( $done + $chunk - 1, $total - 1 );
    $headers = array();
    if ( $total > 0 ) {
        $headers['Range'] = 'bytes=' . $done . '-' . $end;
    }
    $r = wp_remote_get( $url, array(
        'timeout' => 20,
        'headers' => $headers,
    ) );
    if ( is_wp_error( $r ) ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'Fetch failed.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    $code = (int) wp_remote_retrieve_response_code( $r );
    if ( !in_array( $code, array(200, 206), true ) ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'HTTP error.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    $body = wp_remote_retrieve_body( $r );
    $dir = thespl_sample_session_dir( $session );
    if ( !is_dir( $dir ) && !wp_mkdir_p( $dir ) ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'Could not create session directory.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    $zip = $dir . 'sample.zip';
    $ok = false;
    if ( '' !== $body ) {
        // Append mode is required for chunk downloads; WP_Filesystem has no native append API.
        // This runs in nonce/capability-protected admin-ajax flow and writes to a controlled temp path.
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_file_put_contents
        $bytes = file_put_contents( $zip, $body, FILE_APPEND | LOCK_EX );
        $ok = false !== $bytes;
    }
    if ( !$ok ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'Write failed.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    clearstatcache( false, $zip );
    $size = ( file_exists( $zip ) ? (int) filesize( $zip ) : 0 );
    $state['downloaded_bytes'] = $size;
    set_transient( $key, $state, HOUR_IN_SECONDS );
    $done_now = $size >= $total && $total > 0;
    wp_send_json_success( array(
        'downloaded_bytes' => $size,
        'done'             => $done_now,
    ) );
}

/**
 * Verify, unzip and prepare manifest from the sample package.
 *
 * @return void
 */
function thespl_ajax_sample_import_finalize() {
    check_ajax_referer( 'thespl_sample_import', '_wpnonce' );
    if ( !current_user_can( 'manage_options' ) ) {
        wp_send_json_error( array(
            'message' => __( 'Permission denied - This action is available for administrators only.', 'the-studio-player' ),
        ) );
    }
    $session = ( isset( $_POST['session'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['session'] ) ) : '' );
    if ( '' === $session ) {
        wp_send_json_error( array(
            'message' => __( 'Missing session.', 'the-studio-player' ),
        ) );
    }
    $user_id = get_current_user_id();
    $key = 'thespl_sample_import_' . $user_id . '_' . $session;
    $state = get_transient( $key );
    $base_dir = thespl_sample_session_dir( $session );
    $zip_path = $base_dir . 'sample.zip';
    if ( !is_array( $state ) || !file_exists( $zip_path ) ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'Session expired.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    $total = ( isset( $state['total_bytes'] ) ? (int) $state['total_bytes'] : 0 );
    $size = ( file_exists( $zip_path ) ? (int) filesize( $zip_path ) : 0 );
    if ( $total > 0 && $size !== $total ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'Size mismatch.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    $expected_checksum = ( isset( $state['checksum'] ) && is_string( $state['checksum'] ) ? trim( $state['checksum'] ) : '' );
    if ( '' === $expected_checksum ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'Expected checksum missing.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    $checksum = hash_file( 'sha256', $zip_path );
    if ( !is_string( $checksum ) || '' === $checksum ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'Checksum failed.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    if ( $expected_checksum !== $checksum ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'Checksum verification failed.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    $un = thespl_sample_unzip_direct( $zip_path, $base_dir );
    if ( is_wp_error( $un ) ) {
        $msg = $un->get_error_message();
        if ( !is_string( $msg ) || '' === $msg ) {
            $msg = __( 'Unzip failed.', 'the-studio-player' );
        } else {
            /* translators: %s: unzip error message. */
            $msg = sprintf( __( 'Unzip failed: %s', 'the-studio-player' ), $msg );
        }
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => $msg,
            'reset'   => true,
        ) );
    }
    $manifest_path = trailingslashit( $base_dir ) . 'manifest.json';
    if ( !file_exists( $manifest_path ) ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'manifest.json not found in the package.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    if ( !thespl_init_filesystem() ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'Filesystem init failed.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    global $wp_filesystem;
    $raw = $wp_filesystem->get_contents( $manifest_path );
    if ( !is_string( $raw ) || strlen( $raw ) > 1048576 ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'Manifest too large or unreadable.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    $m = json_decode( (string) $raw, true );
    if ( !is_array( $m ) || !isset( $m['playlists'] ) || !is_array( $m['playlists'] ) || empty( $m['sample'] ) ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_error( array(
            'message' => __( 'Invalid manifest.json.', 'the-studio-player' ),
            'reset'   => true,
        ) );
    }
    wp_delete_file( $manifest_path );
    $state['playlists'] = $m['playlists'];
    $state['options'] = ( isset( $m['options'] ) && is_array( $m['options'] ) ? $m['options'] : array() );
    $state['export_host'] = ( isset( $m['export_host'] ) && is_string( $m['export_host'] ) ? sanitize_text_field( $m['export_host'] ) : '' );
    $state['index'] = 0;
    $state['total'] = count( (array) $state['playlists'] );
    set_transient( $key, $state, HOUR_IN_SECONDS );
    wp_send_json_success( array(
        'session'         => $session,
        'total_playlists' => $state['total'],
    ) );
}

/**
 * Process one playlist from the sample manifest.
 *
 * @return void
 */
function thespl_ajax_sample_import_step() {
    check_ajax_referer( 'thespl_sample_import', '_wpnonce' );
    if ( !current_user_can( 'manage_options' ) ) {
        wp_send_json_error( array(
            'message' => __( 'Permission denied - This action is available for administrators only.', 'the-studio-player' ),
        ) );
    }
    $session = ( isset( $_POST['session'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['session'] ) ) : '' );
    if ( '' === $session ) {
        wp_send_json_error( array(
            'message' => __( 'Missing session.', 'the-studio-player' ),
        ) );
    }
    $user_id = get_current_user_id();
    $key = 'thespl_sample_import_' . $user_id . '_' . $session;
    $state = get_transient( $key );
    $base_dir = thespl_sample_session_dir( $session );
    if ( !is_array( $state ) || !isset( $state['playlists'] ) || !is_array( $state['playlists'] ) ) {
        wp_send_json_error( array(
            'message' => __( 'Session expired.', 'the-studio-player' ),
        ) );
    }
    $index = ( isset( $state['index'] ) ? (int) $state['index'] : 0 );
    $total = ( isset( $state['total'] ) ? (int) $state['total'] : count( (array) $state['playlists'] ) );
    if ( $index >= $total ) {
        thespl_sample_cleanup_by_session( $session );
        wp_send_json_success( array(
            'done'      => true,
            'processed' => $total,
        ) );
    }
    $current = $state['playlists'][$index];
    if ( !is_array( $current ) ) {
        $state['index'] = $index + 1;
        set_transient( $key, $state, HOUR_IN_SECONDS );
        $done = $index + 1 >= $total;
        if ( $done ) {
            thespl_sample_cleanup_by_session( $session );
        }
        wp_send_json_success( array(
            'done'      => $done,
            'processed' => $index + 1,
        ) );
    }
    $post_id = wp_insert_post( array(
        'post_type'   => 'thespl_playlist',
        'post_status' => 'draft',
        'post_title'  => ( isset( $current['title'] ) ? sanitize_text_field( $current['title'] ) : 'Sample Playlist' ),
    ), true );
    if ( is_wp_error( $post_id ) ) {
        $state['index'] = $index + 1;
        set_transient( $key, $state, HOUR_IN_SECONDS );
        wp_send_json_success( array(
            'done'      => $index + 1 >= $total,
            'processed' => $index + 1,
        ) );
    }
    update_post_meta( $post_id, '_thespl_sample', 1 );
    $pack_id = ( isset( $state['pack_id'] ) ? (string) $state['pack_id'] : '' );
    if ( '' !== $pack_id ) {
        update_post_meta( $post_id, '_thespl_sample_pack', $pack_id );
    }
    $template = ( isset( $current['template'] ) && is_string( $current['template'] ) ? sanitize_key( $current['template'] ) : '' );
    if ( '' !== $template ) {
        update_post_meta( $post_id, '_thespl_playlist_template', $template );
    }
    if ( isset( $current['design'] ) && is_array( $current['design'] ) ) {
        update_post_meta( $post_id, '_thespl_playlist_design', $current['design'] );
    }
    $export_host = ( isset( $state['export_host'] ) && is_string( $state['export_host'] ) ? trim( (string) $state['export_host'] ) : '' );
    if ( '' !== $export_host ) {
        $title = get_the_title( $post_id );
        $suf = ' (Imported from ' . sanitize_text_field( $export_host ) . ')';
        wp_update_post( array(
            'ID'         => $post_id,
            'post_title' => $title . $suf,
        ) );
    }
    $tracks_out = array();
    $sample_upload_dir_filter = null;
    $uploads = wp_get_upload_dir();
    if ( is_array( $uploads ) && empty( $uploads['error'] ) && !empty( $uploads['basedir'] ) && !empty( $uploads['baseurl'] ) && is_string( $uploads['basedir'] ) && is_string( $uploads['baseurl'] ) ) {
        $sample_subdir = '/the-studio-player/audio/sample-data';
        if ( '' !== $pack_id ) {
            $sample_subdir .= '/' . sanitize_title( $pack_id );
        }
        $sample_upload_dir_filter = static function ( $u ) use($sample_subdir) {
            $u['subdir'] = $sample_subdir;
            $u['path'] = trailingslashit( $u['basedir'] ) . ltrim( $sample_subdir, '/' );
            $u['url'] = trailingslashit( $u['baseurl'] ) . ltrim( $sample_subdir, '/' );
            return $u;
        };
    }
    if ( isset( $current['tracks'] ) && is_array( $current['tracks'] ) ) {
        foreach ( $current['tracks'] as $t ) {
            if ( !is_array( $t ) ) {
                continue;
            }
            $audio_id = 0;
            $cover_id = 0;
            $wave_id = 0;
            $files = ( isset( $t['files'] ) && is_array( $t['files'] ) ? $t['files'] : array() );
            $audio = ( isset( $files['audio'] ) ? (string) $files['audio'] : '' );
            $cover = ( isset( $files['cover'] ) ? (string) $files['cover'] : '' );
            $wave = ( isset( $files['waveform'] ) ? (string) $files['waveform'] : '' );
            $audio_p = thespl_sample_resolve_manifest_path( $base_dir, $audio );
            $cover_p = thespl_sample_resolve_manifest_path( $base_dir, $cover );
            $wave_p = thespl_sample_resolve_manifest_path( $base_dir, $wave );
            if ( '' !== $audio_p && file_exists( $audio_p ) ) {
                $fingerprint = ( function_exists( 'thespl_generate_file_fingerprint' ) ? thespl_generate_file_fingerprint( $audio_p ) : '' );
                $reused_id = ( '' !== $fingerprint ? (int) apply_filters( 'thespl_attachment_reuse_id', 0, $fingerprint ) : 0 );
                if ( $reused_id > 0 ) {
                    $audio_id = $reused_id;
                } else {
                    $file_array = array(
                        'name'     => basename( $audio_p ),
                        'tmp_name' => $audio_p,
                    );
                    if ( null !== $sample_upload_dir_filter ) {
                        add_filter( 'upload_dir', $sample_upload_dir_filter );
                    }
                    $attach_id = thespl_media_handle_sideload( $file_array, 0 );
                    if ( null !== $sample_upload_dir_filter ) {
                        remove_filter( 'upload_dir', $sample_upload_dir_filter );
                    }
                    if ( is_int( $attach_id ) && $attach_id > 0 ) {
                        $audio_id = $attach_id;
                        update_post_meta( $attach_id, '_thespl_sample', 1 );
                        if ( '' !== $pack_id ) {
                            update_post_meta( $attach_id, '_thespl_sample_pack', $pack_id );
                        }
                        if ( '' !== $fingerprint ) {
                            update_post_meta( $attach_id, '_thespl_fingerprint', $fingerprint );
                        }
                    }
                }
            }
            if ( '' !== $cover_p && file_exists( $cover_p ) ) {
                $fingerprint = ( function_exists( 'thespl_generate_file_fingerprint' ) ? thespl_generate_file_fingerprint( $cover_p ) : '' );
                $reused_id = ( '' !== $fingerprint ? (int) apply_filters( 'thespl_attachment_reuse_id', 0, $fingerprint ) : 0 );
                if ( $reused_id > 0 ) {
                    $cover_id = $reused_id;
                } else {
                    $file_array = array(
                        'name'     => basename( $cover_p ),
                        'tmp_name' => $cover_p,
                    );
                    $attach_id = thespl_media_handle_sideload( $file_array, 0 );
                    if ( is_int( $attach_id ) && $attach_id > 0 ) {
                        $cover_id = $attach_id;
                        update_post_meta( $attach_id, '_thespl_sample', 1 );
                        if ( '' !== $pack_id ) {
                            update_post_meta( $attach_id, '_thespl_sample_pack', $pack_id );
                        }
                        if ( '' !== $fingerprint ) {
                            update_post_meta( $attach_id, '_thespl_fingerprint', $fingerprint );
                        }
                    }
                }
            }
            if ( $audio_id > 0 && '' !== $wave_p && file_exists( $wave_p ) ) {
                $audio_target = get_attached_file( $audio_id );
                if ( is_string( $audio_target ) && '' !== $audio_target && file_exists( $audio_target ) ) {
                    $dir = dirname( $audio_target );
                    $base = pathinfo( $audio_target, PATHINFO_FILENAME );
                    $json_path = $dir . DIRECTORY_SEPARATOR . $base . '.json';
                    if ( thespl_init_filesystem() ) {
                        global $wp_filesystem;
                        if ( !$wp_filesystem->exists( $json_path ) ) {
                            $content = $wp_filesystem->get_contents( $wave_p );
                            if ( is_string( $content ) && '' !== $content ) {
                                $wp_filesystem->put_contents( $json_path, $content, FS_CHMOD_FILE );
                                if ( !thespl_validate_file_content( $json_path ) ) {
                                    $wp_filesystem->delete( $json_path );
                                }
                            }
                        }
                        if ( $wp_filesystem->exists( $json_path ) ) {
                            $fingerprint = ( function_exists( 'thespl_generate_file_fingerprint' ) ? thespl_generate_file_fingerprint( $json_path ) : '' );
                            $reused_id = ( '' !== $fingerprint ? (int) apply_filters( 'thespl_attachment_reuse_id', 0, $fingerprint ) : 0 );
                            if ( $reused_id > 0 ) {
                                $wave_id = $reused_id;
                            } else {
                                $uploads = wp_get_upload_dir();
                                if ( is_array( $uploads ) && !empty( $uploads['baseurl'] ) ) {
                                    $rel = ( function_exists( 'thespl_get_upload_relative_path' ) ? thespl_get_upload_relative_path( $json_path ) : '' );
                                    if ( '' !== $rel && function_exists( 'thespl_build_upload_url' ) && function_exists( 'thespl_register_media_attachment' ) ) {
                                        $url = thespl_build_upload_url( $rel, $uploads['baseurl'] );
                                        $attach_id = thespl_register_media_attachment( $json_path, $url );
                                        if ( $attach_id > 0 ) {
                                            $wave_id = $attach_id;
                                            update_post_meta( $attach_id, '_thespl_sample', 1 );
                                            if ( '' !== $pack_id ) {
                                                update_post_meta( $attach_id, '_thespl_sample_pack', $pack_id );
                                            }
                                            if ( '' !== $fingerprint ) {
                                                update_post_meta( $attach_id, '_thespl_fingerprint', $fingerprint );
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            $tracks_out[] = array(
                'title'                  => ( isset( $t['title'] ) && is_string( $t['title'] ) ? sanitize_text_field( $t['title'] ) : '' ),
                'artist'                 => ( isset( $t['artist'] ) && is_string( $t['artist'] ) ? sanitize_text_field( $t['artist'] ) : '' ),
                'credits'                => ( isset( $t['credits'] ) && is_string( $t['credits'] ) ? sanitize_text_field( $t['credits'] ) : '' ),
                'variants'               => ( isset( $t['variants'] ) && is_array( $t['variants'] ) ? array_map( 'sanitize_text_field', $t['variants'] ) : array() ),
                'variant_info'           => ( isset( $t['variant_info'] ) && is_array( $t['variant_info'] ) ? array_map( 'sanitize_text_field', $t['variant_info'] ) : array() ),
                'social'                 => ( isset( $t['social'] ) && is_string( $t['social'] ) ? esc_url_raw( $t['social'] ) : '' ),
                'audio_attachment_id'    => $audio_id,
                'cover_attachment_id'    => $cover_id,
                'waveform_attachment_id' => $wave_id,
            );
        }
    }
    $json = wp_json_encode( array(
        'tracks' => $tracks_out,
    ) );
    if ( function_exists( 'thespl_sanitize_playlist_json_string' ) ) {
        $json = thespl_sanitize_playlist_json_string( $json );
    }
    update_post_meta( $post_id, '_thespl_playlist_json', $json );
    $state['index'] = $index + 1;
    set_transient( $key, $state, HOUR_IN_SECONDS );
    $done = $index + 1 >= $total;
    if ( $done ) {
        thespl_sample_cleanup_by_session( $session );
    }
    wp_send_json_success( array(
        'done'      => $done,
        'processed' => $index + 1,
        'post_id'   => $post_id,
    ) );
}

/**
 * Remove all imported sample data.
 *
 * @return void
 */
function thespl_ajax_sample_remove() {
    check_ajax_referer( 'thespl_sample_import', '_wpnonce' );
    if ( !current_user_can( 'manage_options' ) ) {
        wp_send_json_error( array(
            'message' => __( 'Permission denied - This action is available for administrators only.', 'the-studio-player' ),
        ) );
    }
    $pack_id = ( isset( $_POST['pack_id'] ) ? sanitize_text_field( wp_unslash( (string) $_POST['pack_id'] ) ) : '' );
    $args_p = array(
        'post_type'      => 'thespl_playlist',
        'post_status'    => array('publish', 'draft', 'private'),
        'fields'         => 'ids',
        'posts_per_page' => -1,
        'no_found_rows'  => true,
        'meta_query'     => array(array(
            'key'   => '_thespl_sample',
            'value' => '1',
        )),
    );
    if ( '' !== $pack_id ) {
        $args_p['meta_query'][] = array(
            'key'   => '_thespl_sample_pack',
            'value' => $pack_id,
        );
    }
    $q = new WP_Query($args_p);
    if ( $q->have_posts() ) {
        foreach ( $q->posts as $pid ) {
            wp_delete_post( (int) $pid, true );
        }
    }
    $args_a = array(
        'post_type'      => 'attachment',
        'post_status'    => 'inherit',
        'fields'         => 'ids',
        'posts_per_page' => -1,
        'no_found_rows'  => true,
        'meta_query'     => array(array(
            'key'   => '_thespl_sample',
            'value' => '1',
        )),
    );
    if ( '' !== $pack_id ) {
        $args_a['meta_query'][] = array(
            'key'   => '_thespl_sample_pack',
            'value' => $pack_id,
        );
    }
    $qa = new WP_Query($args_a);
    if ( $qa->have_posts() ) {
        foreach ( $qa->posts as $aid ) {
            wp_delete_attachment( (int) $aid, true );
        }
    }
    wp_send_json_success( array(
        'message' => __( 'Done', 'the-studio-player' ),
    ) );
}

/**
 * Render Tools page.
 *
 * @return void
 */
function thespl_render_tools_page() {
    if ( !thespl_current_user_can_policy( 'tools_diagnose' ) ) {
        return;
    }
    $ver = thespl_get_readme_stable_tag_version();
    $plugin_name = __( 'The Studio Player', 'the-studio-player' );
    $page_label = __( 'Tools', 'the-studio-player' );
    $page_title = $plugin_name;
    $profile = thespl_get_capability_profile();
    $has_pro_build = ( isset( $profile['is_pro'] ) ? (bool) $profile['is_pro'] : false );
    $has_recovery = ( isset( $profile['supports_data_recovery'] ) ? (bool) $profile['supports_data_recovery'] : false );
    if ( '' !== $ver ) {
        $page_title .= ' - ' . $ver;
        if ( $has_pro_build ) {
            $page_title .= ' Pro';
        }
    }
    $page_title .= ' - ' . $page_label;
    $is_pro = $has_recovery;
    ?>
	<div class="wrap thespl-admin-wrapper">
		<h1><?php 
    echo esc_html( $page_title );
    ?></h1>

		<?php 
    thespl_render_remote_admin_banners();
    ?>

		<?php 
    thespl_render_admin_top_nav( 'thespl-tools' );
    ?>

		<div class="section-box">
			<span class="section-title"><?php 
    esc_html_e( 'System Tools', 'the-studio-player' );
    ?></span>
			<p class="description">
				<?php 
    esc_html_e( 'Maintenance tasks for your Studio Player installation.', 'the-studio-player' );
    ?>
			</p>

			<div class="thespl-admin-grid">
				<div class="thespl-admin-card" id="thespl-sample-data">
					<h3><?php 
    esc_html_e( 'Sample Data', 'the-studio-player' );
    ?></h3>
					<p>
						<?php 
    esc_html_e( 'Install demo playlists and media from the Studio Player server to explore the plugin without setting up your own content.', 'the-studio-player' );
    echo ' ';
    esc_html_e( 'This feature downloads a sample package from studioplayer.de and stores it temporarily in wp-content/uploads/the-studio-player/.', 'the-studio-player' );
    echo ' ';
    esc_html_e( 'No media files or playlists from your site are uploaded; you can remove all sample data at any time.', 'the-studio-player' );
    ?>
					</p>
					<div id="thespl-sample-status" class="thespl-status-box" style="display:none;">
						<div class="thespl-status-header">
							<span class="thespl-status-label"><?php 
    esc_html_e( 'Status:', 'the-studio-player' );
    ?></span>
							<span class="thespl-sample-message"></span>
						</div>
						<div class="thespl-status-progress">
							<div class="thespl-progress-bar"></div>
						</div>
					</div>
					<div id="thespl-sample-success" style="display:none;margin-top:8px;padding:8px;border:1px solid #46b450;background:#edf7ed;color:#1e6b2c;">
						<?php 
    $playlists_url = admin_url( 'edit.php?post_type=thespl_playlist' );
    printf( '<a href="%1$s" class="button button-secondary">%2$s</a>', esc_url( $playlists_url ), esc_html__( 'Open playlist editor', 'the-studio-player' ) );
    ?>
					</div>
					<p style="display:flex;gap:8px;flex-wrap:wrap;">
						<button id="thespl-sample-install" class="button button-primary"><?php 
    esc_html_e( 'Install Sample Data', 'the-studio-player' );
    ?></button>
						<button id="thespl-sample-remove" class="button"><?php 
    esc_html_e( 'Remove Sample Data', 'the-studio-player' );
    ?></button>
					</p>
				</div>

				<!-- Integrity Scanner -->
				<div class="thespl-admin-card" id="thespl-integrity">
					<h3><?php 
    esc_html_e( 'Integrity Scanner', 'the-studio-player' );
    ?></h3>
					<p><?php 
    esc_html_e( 'Verify all Studio Player files in the Media Library. Detects missing files or unauthorized modifications (via Fingerprint).', 'the-studio-player' );
    ?></p>
					
					<div id="thespl-integrity-status" class="thespl-status-box" style="display:none;">
						<div class="thespl-status-header">
							<span class="thespl-status-label"><?php 
    esc_html_e( 'Status:', 'the-studio-player' );
    ?></span>
							<span class="thespl-integrity-message"></span>
						</div>
						<div class="thespl-status-progress">
							<div class="thespl-progress-bar"></div>
						</div>
						<div class="thespl-status-stats">
							<span class="stat-valid">0 <?php 
    esc_html_e( 'Valid', 'the-studio-player' );
    ?></span> |
							<span class="stat-invalid">0 <?php 
    esc_html_e( 'Modified', 'the-studio-player' );
    ?></span> |
							<span class="stat-missing">0 <?php 
    esc_html_e( 'Missing', 'the-studio-player' );
    ?></span>
						</div>
						<div class="thespl-status-stats thespl-status-stats-routes" style="display:none;">
							<span class="stat-route-ok">0 <?php 
    esc_html_e( 'Routes OK', 'the-studio-player' );
    ?></span> |
							<span class="stat-route-domain">0 <?php 
    esc_html_e( 'Domain mismatches', 'the-studio-player' );
    ?></span> |
							<span class="stat-route-http">0 <?php 
    esc_html_e( 'HTTP errors', 'the-studio-player' );
    ?></span>
						</div>
						<div class="thespl-integrity-report">
							<table class="thespl-integrity-details-table">
								<thead>
									<tr>
										<th><?php 
    esc_html_e( 'Media', 'the-studio-player' );
    ?></th>
										<th><?php 
    esc_html_e( 'Integrity', 'the-studio-player' );
    ?></th>
										<th><?php 
    esc_html_e( 'Route', 'the-studio-player' );
    ?></th>
									</tr>
								</thead>
								<tbody class="thespl-integrity-details-body"></tbody>
							</table>
						</div>
					</div>

					<button id="thespl-start-integrity" class="button button-primary">
						<?php 
    esc_html_e( 'Run Integrity Check', 'the-studio-player' );
    ?>
					</button>
					<button id="thespl-start-streaming-check" class="button button-secondary" disabled="disabled">
						<?php 
    esc_html_e( 'Check Streaming Routes', 'the-studio-player' );
    ?>
					</button>
				</div>

				<!-- Data Recovery (Pro) -->
				<div class="thespl-admin-card <?php 
    echo ( !$is_pro ? 'pro-locked' : '' );
    ?>">
					<h3>
						<?php 
    esc_html_e( 'Data Recovery', 'the-studio-player' );
    ?>
						<?php 
    if ( !$is_pro ) {
        ?>
							<span class="thespl-pro-badge"><?php 
        esc_html_e( 'PRO', 'the-studio-player' );
        ?></span>
						<?php 
    }
    ?>
					</h3>
					<p><?php 
    esc_html_e( 'Scans the entire uploads folder for Studio Player files (FLAC/JSON) that are NOT in the Media Library and re-indexes them automatically.', 'the-studio-player' );
    ?></p>
					
					<?php 
    if ( !$is_pro ) {
        ?>
						<p class="thespl-pro-notice">
							<?php 
        esc_html_e( 'This tool is only available in the Pro version.', 'the-studio-player' );
        ?>
							<a href="<?php 
        echo esc_url( thespl_get_marketing_pricing_url() );
        ?>" target="_blank" rel="noopener noreferrer">
								<?php 
        esc_html_e( 'Upgrade now', 'the-studio-player' );
        ?>
							</a>
						</p>
					<?php 
    }
    ?>

					<div id="thespl-recovery-status" class="thespl-status-box" style="display:none;">
						<div class="thespl-status-header">
							<span class="thespl-status-label"><?php 
    esc_html_e( 'Status:', 'the-studio-player' );
    ?></span>
							<span class="thespl-recovery-message"></span>
						</div>
						<div class="thespl-status-progress">
							<div class="thespl-progress-bar"></div>
						</div>
						<div class="thespl-status-stats">
							<span class="stat-recovered">0 <?php 
    esc_html_e( 'Recovered', 'the-studio-player' );
    ?></span> | 
							<span class="stat-skipped">0 <?php 
    esc_html_e( 'Skipped', 'the-studio-player' );
    ?></span>
						</div>
					</div>

					<button id="thespl-start-recovery" class="button" <?php 
    disabled( !$is_pro );
    ?>>
						<?php 
    esc_html_e( 'Start Recovery Scan', 'the-studio-player' );
    ?>
					</button>
				</div>

				<div class="thespl-admin-card <?php 
    echo ( !$is_pro ? 'pro-locked' : '' );
    ?>">
					<h3>
						<?php 
    esc_html_e( 'Waveform Rebuilder', 'the-studio-player' );
    ?>
						<?php 
    if ( !$is_pro ) {
        ?>
							<span class="thespl-pro-badge"><?php 
        esc_html_e( 'PRO', 'the-studio-player' );
        ?></span>
						<?php 
    }
    ?>
					</h3>
					<p><?php 
    esc_html_e( 'Generates missing waveform JSON files for existing FLAC audio created with the Muxer. After upgrading from a free to a pro license, you do not need to re-upload the audio.', 'the-studio-player' );
    ?></p>

					<?php 
    if ( !$is_pro ) {
        ?>
						<p class="thespl-pro-notice">
							<?php 
        esc_html_e( 'This tool is only available in the Pro version.', 'the-studio-player' );
        ?>
							<a href="<?php 
        echo esc_url( thespl_get_marketing_pricing_url() );
        ?>" target="_blank" rel="noopener noreferrer">
								<?php 
        esc_html_e( 'Upgrade now', 'the-studio-player' );
        ?>
							</a>
						</p>
					<?php 
    }
    ?>

					<div id="thespl-waveform-status" class="thespl-status-box" style="display:none;">
						<div class="thespl-status-header">
							<span class="thespl-status-label"><?php 
    esc_html_e( 'Status:', 'the-studio-player' );
    ?></span>
							<span class="thespl-waveform-message"></span>
							<span class="spinner thespl-waveform-spinner" aria-hidden="true"></span>
						</div>
						<div class="thespl-status-progress">
							<div class="thespl-progress-bar"></div>
						</div>
						<div class="thespl-status-stats">
							<span class="stat-generated">0 <?php 
    esc_html_e( 'Generated', 'the-studio-player' );
    ?></span> | 
							<span class="stat-skipped">0 <?php 
    esc_html_e( 'Skipped', 'the-studio-player' );
    ?></span>
						</div>
					</div>

					<button id="thespl-start-waveform-rebuild" class="button" <?php 
    disabled( !$is_pro );
    ?>>
						<?php 
    esc_html_e( 'Generate Missing Waveforms', 'the-studio-player' );
    ?>
					</button>
				</div>
				<?php 
    thespl_render_tools_media_import_export();
    ?>
			</div>
		</div>
	</div>
	<?php 
}

/**
 * Bootstraps admin AJAX routes for Sample Data tools (Free + Pro).
 *
 * @return void
 */
function thespl_bootstrap_sample_tools() {
    if ( !is_admin() ) {
        return;
    }
    add_action( 'wp_ajax_thespl_sample_import_start', 'thespl_ajax_sample_import_start' );
    add_action( 'wp_ajax_thespl_sample_import_fetch', 'thespl_ajax_sample_import_fetch' );
    add_action( 'wp_ajax_thespl_sample_import_finalize', 'thespl_ajax_sample_import_finalize' );
    add_action( 'wp_ajax_thespl_sample_import_step', 'thespl_ajax_sample_import_step' );
    add_action( 'wp_ajax_thespl_sample_remove', 'thespl_ajax_sample_remove' );
}

/**
 * Renders the Tools page card for media import/export.
 *
 * @return void
 */
function thespl_render_tools_media_import_export() {
    ?>
	<div class="thespl-admin-card pro-locked">
		<h3>
			<?php 
    esc_html_e( 'Import/Export', 'the-studio-player' );
    ?>
			<span class="thespl-pro-badge"><?php 
    esc_html_e( 'PRO', 'the-studio-player' );
    ?></span>
		</h3>
		<p><?php 
    esc_html_e( 'Export playlists and their media as a ZIP package or import a previously exported package.', 'the-studio-player' );
    ?></p>
		<p class="thespl-pro-notice">
			<?php 
    esc_html_e( 'This tool is only available in the Pro version.', 'the-studio-player' );
    ?>
			<a href="<?php 
    echo esc_url( thespl_get_marketing_pricing_url() );
    ?>" target="_blank" rel="noopener noreferrer">
				<?php 
    esc_html_e( 'Upgrade now', 'the-studio-player' );
    ?>
			</a>
		</p>
		<p>
			<button type="button" class="button" disabled="disabled">
				<?php 
    esc_html_e( 'Export ZIP', 'the-studio-player' );
    ?>
			</button>
			<button type="button" class="button" disabled="disabled">
				<?php 
    esc_html_e( 'Import ZIP', 'the-studio-player' );
    ?>
			</button>
		</p>
	</div>
	<?php 
}
