<?php
/**
 * Structure Viewer Pro — FlatPack AJAX Handlers
 *
 * Registers wp_ajax_ actions for the FlatPack feature.
 * CSS and JS assets are enqueued by SV_Loader::enqueue() in Loader.php,
 * following the same pattern as the Comparator and all other SV assets.
 *
 * phpcs:disable WordPress.Security.NonceVerification.Missing
 * -- Every public handler calls $this->verify_request() first, which calls
 *    check_ajax_referer( STRUCTUREVIEWER_NONCE ). PHPCS cannot trace the
 *    nonce check through a method call, so false-positives fire on subsequent
 *    $_POST / $_FILES accesses. Nonce IS verified for all handlers.
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit( 'Direct access denied.' );
}

// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedClassFound -- SV_ is the established plugin prefix used consistently across all plugin classes.
class SV_Pro_FlatPack_Ajax {

    public function __construct() {
        add_action( 'wp_ajax_structureviewer_fp_analyze', [ $this, 'handle_analyze' ] );
        add_action( 'wp_ajax_structureviewer_fp_extract', [ $this, 'handle_extract' ] );
        // Gated download handler — served as a file stream, one-time use.
        add_action( 'admin_post_sv_fp_download', [ 'SV_Pro_FlatPack', 'serve_download' ] );
    }

    // ── Auth ──────────────────────────────────────────────────────

    private function verify_request() {
        check_ajax_referer( STRUCTUREVIEWER_NONCE, 'nonce' );
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( [ 'message' => 'Permission denied' ] );
        }
    }

    // ── Analyze ───────────────────────────────────────────────────

    /**
     * Upload and extract ALL files from the ZIP.
     * No filter is applied here — the full file list is returned so the
     * front-end can live-filter it client-side without extra round-trips.
     * The chosen filter is only sent at extraction time.
     */
    public function handle_analyze() {
        $this->verify_request();

        if ( empty( $_FILES['file'] ) || $_FILES['file']['error'] !== UPLOAD_ERR_OK ) { // phpcs:ignore
            wp_send_json_error( [ 'message' => 'No file uploaded' ] );
        }

        $result = SV_Pro_FlatPack::analyze( $_FILES['file'] ); // phpcs:ignore

        if ( isset( $result['error'] ) ) {
            wp_send_json_error( [ 'message' => $result['error'] ] );
        }

        wp_send_json_success( $result );
    }

    // ── Extract ───────────────────────────────────────────────────

    /**
     * Apply the user's chosen filter to the stored file list and produce
     * the flat downloadable ZIP.
     *
     * The filter is supplied here (not during analyze) so the user can
     * change their selection after seeing the full preview without needing
     * to re-upload the ZIP.
     */
    public function handle_extract() {
        $this->verify_request();

        $temp_id    = isset( $_POST['temp_id'] )
            ? sanitize_text_field( wp_unslash( $_POST['temp_id'] ) )
            : '';

        // analyze() builds temp_id as 'sv_fp_' . md5(…). Reject anything that
        // doesn't match that shape before we hit get_transient() so a forged
        // or tampered ID can't probe unrelated transient keys.
        if ( ! preg_match( '/^sv_fp_[a-f0-9]{32}$/', $temp_id ) ) {
            wp_send_json_error( [ 'message' => 'Invalid session identifier.' ] );
        }

        $filter     = isset( $_POST['file_filter'] )
            ? sanitize_text_field( wp_unslash( $_POST['file_filter'] ) )
            : 'all';
        $custom_ext = isset( $_POST['custom_extensions'] )
            ? sanitize_text_field( wp_unslash( $_POST['custom_extensions'] ) )
            : '';

        $result = SV_Pro_FlatPack::extract( $temp_id, $filter, $custom_ext );

        if ( isset( $result['error'] ) ) {
            wp_send_json_error( [ 'message' => $result['error'] ] );
        }

        wp_send_json_success( $result );
    }
}