<?php
/**
 * Structure Viewer Pro — Comparator AJAX Handlers
 *
 * Registers and handles all wp_ajax_ actions for the Comparator feature.
 * Uses the plugin-wide STRUCTUREVIEWER_NONCE for authentication.
 *
 * phpcs:disable WordPress.Security.NonceVerification.Missing
 * -- Every public AJAX handler calls $this->verify_request() as its first
 *    statement, which in turn calls check_ajax_referer( STRUCTUREVIEWER_NONCE ).
 *    PHPCS cannot trace nonce verification through a method call, so the sniff
 *    fires as a false positive on every subsequent $_POST access in private
 *    methods. Nonce IS verified for all handlers in this file.
 */

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_Comparator_Ajax {

    public function __construct() {
        add_action( 'wp_ajax_structureviewer_comp_upload',           [ $this, 'handle_upload' ] );
        add_action( 'wp_ajax_structureviewer_comp_upload_file',      [ $this, 'handle_upload_file' ] );
        add_action( 'wp_ajax_structureviewer_comp_compare',          [ $this, 'handle_compare' ] );
        add_action( 'wp_ajax_structureviewer_comp_compare_files',    [ $this, 'handle_compare_files' ] );
        add_action( 'wp_ajax_structureviewer_comp_get_diff',         [ $this, 'handle_get_diff' ] );
        add_action( 'wp_ajax_structureviewer_comp_get_file_content', [ $this, 'handle_get_file_content' ] );
        add_action( 'wp_ajax_structureviewer_comp_cleanup',          [ $this, 'handle_cleanup' ] );
    }

    // ── Auth helper ───────────────────────────────────────────────

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

    // ── Installed plugin/theme data ───────────────────────────────
    // Static because page.php needs to read these at render time; calling
    // via an instance would re-run __construct() and double-register every
    // add_action() above on each admin page load.

    public static function get_installed_plugins() {
        if ( ! function_exists( 'get_plugins' ) ) {
            require_once ABSPATH . 'wp-admin/includes/plugin.php';
        }
        $result = [];
        foreach ( get_plugins() as $path => $data ) {
            $folder   = dirname( $path );
            if ( $folder === '.' ) {
                $folder = basename( $path, '.php' );
            }
            $result[] = [
                'slug'    => $folder,
                'path'    => $path,
                'name'    => $data['Name'],
                'version' => $data['Version'],
                'dir'     => WP_PLUGIN_DIR . '/' . $folder,
            ];
        }
        usort( $result, fn( $a, $b ) => strcasecmp( $a['name'], $b['name'] ) );
        return $result;
    }

    public static function get_installed_themes() {
        $result = [];
        foreach ( wp_get_themes() as $slug => $theme ) {
            $result[] = [
                'slug'    => $slug,
                'name'    => $theme->get( 'Name' ),
                'version' => $theme->get( 'Version' ),
                'dir'     => $theme->get_stylesheet_directory(),
            ];
        }
        usort( $result, fn( $a, $b ) => strcasecmp( $a['name'], $b['name'] ) );
        return $result;
    }

    // ── ZIP upload ────────────────────────────────────────────────

    public function handle_upload() {
        $this->verify_request();

        $num = isset( $_POST['plugin_num'] ) ? sanitize_text_field( wp_unslash( $_POST['plugin_num'] ) ) : '';
        if ( ! in_array( $num, [ '1', '2' ], true ) ) {
            wp_send_json_error( [ 'message' => 'Invalid upload slot' ] );
        }

        $file_key = 'plugin' . $num;
        if ( empty( $_FILES[ $file_key ] ) ) {
            wp_send_json_error( [ 'message' => 'No file uploaded' ] );
        }

        $result = SV_Pro_File_Handler::upload_zip( $_FILES[ $file_key ], 'p' . $num ); // phpcs:ignore
        if ( isset( $result['error'] ) ) {
            wp_send_json_error( [ 'message' => $result['error'] ] );
        }

        $uid = get_current_user_id();
        SV_Pro_File_Handler::set_session( 'plugin' . $num . '_' . $uid, [
            'path' => $result['path'],
            'name' => $result['name'],
            'type' => 'zip',
        ] );

        wp_send_json_success( [ 'message' => 'Uploaded successfully', 'name' => $result['name'] ] );
    }

    // ── Single file upload ────────────────────────────────────────

    public function handle_upload_file() {
        $this->verify_request();

        $num = isset( $_POST['file_num'] ) ? sanitize_text_field( wp_unslash( $_POST['file_num'] ) ) : '';
        if ( ! in_array( $num, [ '1', '2' ], true ) ) {
            wp_send_json_error( [ 'message' => 'Invalid file slot' ] );
        }

        $file_key = 'file' . $num;
        if ( empty( $_FILES[ $file_key ] ) ) {
            wp_send_json_error( [ 'message' => 'No file uploaded' ] );
        }

        $result = SV_Pro_File_Handler::upload_single_file( $_FILES[ $file_key ], 'f' . $num ); // phpcs:ignore
        if ( isset( $result['error'] ) ) {
            wp_send_json_error( [ 'message' => $result['error'] ] );
        }

        $uid = get_current_user_id();
        SV_Pro_File_Handler::set_session( 'file' . $num . '_' . $uid, [
            'path' => $result['path'],
            'dir'  => $result['dir'],
            'name' => $result['name'],
            'size' => $result['size'],
        ] );

        wp_send_json_success( [
            'message' => 'Uploaded successfully',
            'name'    => $result['name'],
            'size'    => size_format( $result['size'] ),
        ] );
    }

    // ── Compare dispatcher ────────────────────────────────────────

    public function handle_compare() {
        $this->verify_request();

        $mode = isset( $_POST['mode'] ) ? sanitize_text_field( wp_unslash( $_POST['mode'] ) ) : 'zip';
        $uid  = get_current_user_id();

        switch ( $mode ) {
            case 'zip':
                $result = $this->compare_zip_mode( $uid );
                break;
            case 'plugin':
                $result = $this->compare_plugin_mode( $uid );
                break;
            case 'theme':
                $result = $this->compare_theme_mode( $uid );
                break;
            default:
                $result = [ 'error' => 'Invalid comparison mode' ];
        }

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

        wp_send_json_success( $result );
    }

    // ── ZIP vs ZIP ────────────────────────────────────────────────

    private function compare_zip_mode( $uid ) {
        $p1 = SV_Pro_File_Handler::get_session( 'plugin1_' . $uid );
        $p2 = SV_Pro_File_Handler::get_session( 'plugin2_' . $uid );

        if ( ! $p1 || ! $p2 ) {
            return [ 'error' => 'Please upload both files first' ];
        }
        if ( ! file_exists( $p1['path'] ) || ! file_exists( $p2['path'] ) ) {
            return [ 'error' => 'Uploaded files not found. Please upload again.' ];
        }

        $files1 = SV_Pro_File_Handler::scan_directory( $p1['path'] );
        $files2 = SV_Pro_File_Handler::scan_directory( $p2['path'] );
        $result = SV_Pro_Comparator::compare( $files1, $files2, true, true );

        $result['plugin1_name'] = $p1['name'];
        $result['plugin2_name'] = $p2['name'];
        SV_Pro_File_Handler::set_session( 'comparison_' . $uid, [ 'result' => $result ] );

        return $result;
    }

    // ── Installed plugin vs ZIP ───────────────────────────────────

    private function compare_plugin_mode( $uid ) {
        $slug       = isset( $_POST['installed_slug'] ) ? sanitize_text_field( wp_unslash( $_POST['installed_slug'] ) ) : '';
        $compare_as = isset( $_POST['compare_as'] )     ? sanitize_text_field( wp_unslash( $_POST['compare_as'] ) ) : 'old';

        if ( empty( $slug ) ) {
            return [ 'error' => 'Please select a plugin' ];
        }

        $p_zip = SV_Pro_File_Handler::get_session( 'plugin1_' . $uid );
        if ( ! $p_zip ) {
            return [ 'error' => 'Please upload a ZIP file first' ];
        }

        $installed = null;
        foreach ( self::get_installed_plugins() as $p ) {
            if ( $p['slug'] === $slug ) {
                $installed = $p;
                break;
            }
        }

        if ( ! $installed || ! is_dir( $installed['dir'] ) ) {
            return [ 'error' => 'Installed plugin directory not found' ];
        }

        $files_installed = SV_Pro_File_Handler::scan_directory( $installed['dir'] );
        $files_zip       = SV_Pro_File_Handler::scan_directory( $p_zip['path'] );

        if ( $compare_as === 'old' ) {
            $result                  = SV_Pro_Comparator::compare( $files_installed, $files_zip, false, true );
            $result['plugin1_name']  = $installed['name'] . ' (Installed v' . $installed['version'] . ')';
            $result['plugin2_name']  = $p_zip['name'] . ' (Uploaded)';
        } else {
            $result                  = SV_Pro_Comparator::compare( $files_zip, $files_installed, true, false );
            $result['plugin1_name']  = $p_zip['name'] . ' (Uploaded)';
            $result['plugin2_name']  = $installed['name'] . ' (Installed v' . $installed['version'] . ')';
        }

        SV_Pro_File_Handler::set_session( 'comparison_' . $uid, [ 'result' => $result ] );
        return $result;
    }

    // ── Installed theme vs ZIP ────────────────────────────────────

    private function compare_theme_mode( $uid ) {
        $slug       = isset( $_POST['installed_slug'] ) ? sanitize_text_field( wp_unslash( $_POST['installed_slug'] ) ) : '';
        $compare_as = isset( $_POST['compare_as'] )     ? sanitize_text_field( wp_unslash( $_POST['compare_as'] ) ) : 'old';

        if ( empty( $slug ) ) {
            return [ 'error' => 'Please select a theme' ];
        }

        $t_zip = SV_Pro_File_Handler::get_session( 'plugin1_' . $uid );
        if ( ! $t_zip ) {
            return [ 'error' => 'Please upload a ZIP file first' ];
        }

        $installed = null;
        foreach ( self::get_installed_themes() as $t ) {
            if ( $t['slug'] === $slug ) {
                $installed = $t;
                break;
            }
        }

        if ( ! $installed || ! is_dir( $installed['dir'] ) ) {
            return [ 'error' => 'Installed theme directory not found' ];
        }

        $files_installed = SV_Pro_File_Handler::scan_directory( $installed['dir'] );
        $files_zip       = SV_Pro_File_Handler::scan_directory( $t_zip['path'] );

        if ( $compare_as === 'old' ) {
            $result                  = SV_Pro_Comparator::compare( $files_installed, $files_zip, false, true );
            $result['plugin1_name']  = $installed['name'] . ' (Installed v' . $installed['version'] . ')';
            $result['plugin2_name']  = $t_zip['name'] . ' (Uploaded)';
        } else {
            $result                  = SV_Pro_Comparator::compare( $files_zip, $files_installed, true, false );
            $result['plugin1_name']  = $t_zip['name'] . ' (Uploaded)';
            $result['plugin2_name']  = $installed['name'] . ' (Installed v' . $installed['version'] . ')';
        }

        SV_Pro_File_Handler::set_session( 'comparison_' . $uid, [ 'result' => $result ] );
        return $result;
    }

    // ── File vs File ──────────────────────────────────────────────

    public function handle_compare_files() {
        $this->verify_request();
        $uid = get_current_user_id();

        $f1 = SV_Pro_File_Handler::get_session( 'file1_' . $uid );
        $f2 = SV_Pro_File_Handler::get_session( 'file2_' . $uid );

        if ( ! $f1 || ! $f2 ) {
            wp_send_json_error( [ 'message' => 'Please upload both files first' ] );
        }
        if ( ! file_exists( $f1['path'] ) || ! file_exists( $f2['path'] ) ) {
            wp_send_json_error( [ 'message' => 'Files not found. Please upload again.' ] );
        }

        $result = SV_Pro_Comparator::compare_single_files( $f1['path'], $f2['path'], $f1['name'], $f2['name'] );

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

        wp_send_json_success( $result );
    }

    // ── Get diff for a modified file ──────────────────────────────

    public function handle_get_diff() {
        $this->verify_request();

        $file = isset( $_POST['file'] ) ? sanitize_text_field( wp_unslash( $_POST['file'] ) ) : '';
        if ( empty( $file ) ) {
            wp_send_json_error( [ 'message' => 'No file specified' ] );
        }

        $uid        = get_current_user_id();
        $comparison = SV_Pro_File_Handler::get_session( 'comparison_' . $uid );

        if ( ! $comparison || ! isset( $comparison['result'] ) ) {
            wp_send_json_error( [ 'message' => 'No comparison data found — please run a comparison first' ] );
        }

        $target = null;
        foreach ( $comparison['result']['modified'] as $mod ) {
            if ( $mod['file'] === $file ) {
                $target = $mod;
                break;
            }
        }

        if ( ! $target ) {
            wp_send_json_error( [ 'message' => 'File not found in comparison results' ] );
        }
        if ( ! $target['can_diff'] ) {
            wp_send_json_error( [ 'message' => 'Cannot generate diff for this file (binary or too large)' ] );
        }

        $diff = SV_Pro_Comparator::get_diff( $target['old_path'], $target['new_path'] );

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

        wp_send_json_success( $diff );
    }

    // ── Get content for added/removed file ────────────────────────

    public function handle_get_file_content() {
        $this->verify_request();

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

        if ( empty( $file ) || ! in_array( $type, [ 'added', 'removed' ], true ) ) {
            wp_send_json_error( [ 'message' => 'Invalid request' ] );
        }

        $uid        = get_current_user_id();
        $comparison = SV_Pro_File_Handler::get_session( 'comparison_' . $uid );

        if ( ! $comparison || ! isset( $comparison['result'] ) ) {
            wp_send_json_error( [ 'message' => 'No comparison data found' ] );
        }

        $list   = ( $type === 'added' ) ? $comparison['result']['added'] : $comparison['result']['removed'];
        $target = null;
        foreach ( $list as $f ) {
            if ( $f['file'] === $file ) {
                $target = $f;
                break;
            }
        }

        if ( ! $target ) {
            wp_send_json_error( [ 'message' => 'File not found in results' ] );
        }
        if ( ! $target['can_view'] ) {
            wp_send_json_error( [ 'message' => 'Cannot view this file (binary or too large)' ] );
        }

        $content = SV_Pro_Comparator::get_file_content( $target['path'], $type );

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

        wp_send_json_success( $content );
    }

    // ── Cleanup ───────────────────────────────────────────────────

    public function handle_cleanup() {
        $this->verify_request();
        $uid        = get_current_user_id();
        $upload_dir = SV_Pro_File_Handler::get_upload_dir();

        $session_keys = [
            'plugin1_' . $uid,
            'plugin2_' . $uid,
            'file1_' . $uid,
            'file2_' . $uid,
        ];

        foreach ( $session_keys as $key ) {
            $data = SV_Pro_File_Handler::get_session( $key );
            if ( $data ) {
                if ( isset( $data['path'] ) && strpos( $data['path'], $upload_dir ) === 0 ) {
                    if ( is_dir( $data['path'] ) ) {
                        SV_Pro_File_Handler::delete_directory( $data['path'] );
                    }
                }
                if ( isset( $data['dir'] ) && strpos( $data['dir'], $upload_dir ) === 0 ) {
                    SV_Pro_File_Handler::delete_directory( $data['dir'] );
                }
                SV_Pro_File_Handler::delete_session( $key );
            }
        }

        SV_Pro_File_Handler::delete_session( 'comparison_' . $uid );
        wp_send_json_success( [ 'message' => 'Cleaned up successfully' ] );
    }
}