<?php
/**
 * Plugin Name: signwpdf PDF Sign & Fill
 * Plugin URI: https://www.signwpdf.com/plugin.html
 * Description: Professional PDF signature plugin - upload fillable PDFs, collect electronic signatures, and store signed documents securely. Perfect for contracts, agreements, waivers, and any document requiring signatures.
 * Version: 1.1.2
 * Requires at least: 5.0
 * Tested up to: 6.9
 * Requires PHP: 7.4
 * Author: signwpdf
 * Author URI: https://www.signwpdf.com/
 * License: GPL v2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: signwpdf-pdf-sign-fill
 */

if ( ! defined( 'ABSPATH' ) ) {
    exit;
}

/*
 * ============================================================================
 * DEVELOPER NOTES - READ BEFORE MAKING CHANGES
 * ============================================================================
 * 
 * 1. VERSION UPDATE: When updating the plugin version:
 *    - Update BOTH the "Version:" header above AND the SWPDF_VERSION constant below
 *    - The constant is used for cache-busting JS/CSS files
 *    - If you only update the header, users will get cached old JS files!
 * 
 * 2. NONCE USAGE:
 *    - Admin AJAX (logged in): Uses 'swpdf_admin_nonce' - verify with check_ajax_referer()
 *    - Public AJAX (front-end form): Uses 'swpdf_public_nonce' - verify is OPTIONAL 
 *      for get_pdf_template since public users need to load templates
 * 
 * 3. KEY FILES:
 *    - assets/js/admin.js - Admin template management, field editing, delete fields
 *    - assets/js/pdf-interactive.js - Front-end form filling, signature, PDF generation
 *    - assets/css/admin.css - Admin styles
 *    - assets/css/pdf-interactive.css - Front-end form styles
 * 
 * 4. FIELD HANDLING:
 *    - Signature field: Handled as drawn image, not text input
 *    - Date field: Auto-filled with current date when generating PDF
 *    - Other fields: Detected from PDF and shown as text inputs
 *    - Fields can be deleted in admin Edit Labels modal
 * 
 * ============================================================================
 * 
 * VERSION HISTORY:
 * v1.1.0 (Freemius Ready) - Integrated Freemius SDK for licensing
 *                         - Removed legacy custom license server
 *                         - All core features remain unlocked (soft activation)
 *                         - Free version updates via WordPress.org (no license needed)
 * v1.0.1 (Mobile Fix)   - Fixed mobile signature canvas rendering
 * v1.0.0 (Initial)      - First public release
 * 
 * ============================================================================
 */

// Define plugin constants
define( 'SWPDF_VERSION', '1.1.2' );
define( 'SWPDF_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'SWPDF_PLUGIN_URL', plugin_dir_url( __FILE__ ) );

// Load required classes
require_once SWPDF_PLUGIN_DIR . 'includes/class-audit-certificate.php';

// ============================================================================
// FREEMIUS SDK INTEGRATION
// ============================================================================
// The Freemius SDK uses a built-in version selection mechanism (see start.php)
// that compares SDK versions across ALL active Freemius-powered plugins and
// loads only the NEWEST one. Each plugin MUST include its own start.php so
// the SDK can register its version in the global $fs_active_plugins array.
//
// We intentionally do NOT wrap start.php in a class_exists('Freemius') check
// because that would prevent version registration and break the selection
// logic that ensures backward-compatible, conflict-free operation.
//
// The function_exists('swpdf_fs') guard below prevents double-initialisation
// of THIS plugin's SDK instance.
// ============================================================================

if ( ! function_exists( 'swpdf_fs' ) ) {
    /**
     * Initialize Freemius SDK
     * 
     * Freemius handles licensing. The plugin works 100% without activation.
     * Free version updates come from WordPress.org automatically.
     * License ONLY enables: premium features + priority support.
     */
    function swpdf_fs() {
        global $swpdf_fs;

        if ( ! isset( $swpdf_fs ) ) {
            // Include Freemius SDK — always load start.php so the SDK's
            // built-in version selection can register this plugin's SDK copy.
            if ( file_exists( SWPDF_PLUGIN_DIR . 'freemius/start.php' ) ) {
                require_once SWPDF_PLUGIN_DIR . 'freemius/start.php';

                $swpdf_fs = fs_dynamic_init( array(
                    'id'                  => '24161',
                    'slug'                => 'signwpdf-pdf-sign-fill',
                    'premium_slug'        => 'signwpdf-pdf-sign-fill-premium',
                    'type'                => 'plugin',
                    'public_key'          => 'pk_8f32f0e6278751413a195e752d94e',
                    'is_premium'          => false,
                    'has_premium_version' => true,
                    'has_addons'          => false,
                    'has_paid_plans'      => true,
                    'is_org_compliant'    => true,
                    'menu'                => array(
                        'slug'           => 'signwpdf-pdf-sign-fill',
                        'account'        => true,
                        'contact'        => true,
                        'support'        => false,
                    ),
                ) );
            } else {
                // Freemius SDK not found - show admin notice but don't break plugin
                if ( is_admin() && current_user_can( 'manage_options' ) ) {
                    add_action( 'admin_notices', function() {
                        echo wp_kses_post( '<div class="notice notice-warning is-dismissible"><p><strong>signwpdf PDF Sign & Fill:</strong> Freemius SDK not found. Please upload the Freemius SDK to <code>/wp-content/plugins/signwpdf-pdf-sign-fill/freemius/</code> to enable license management. The plugin will continue to work normally without it.</p></div>' );
                    } );
                }
                // Return a mock object so code doesn't break
                $swpdf_fs = new class {
                    public function is_premium() { return false; }
                    public function can_use_premium_code() { return false; }
                    public function is_not_paying() { return true; }
                    public function is_free_plan() { return true; }
                    public function set_basename( $arg1 = null, $arg2 = null ) { return $this; }
                    public function add_action( $action = '', $callback = null ) { return $this; }
                };
            }
        }

        return $swpdf_fs;
    }

    // Initialize Freemius immediately (per Freemius best practices)
    swpdf_fs();
    
    // Signal to Freemius which plugin file contains header (for free→premium switching)
    swpdf_fs()->set_basename( true, __FILE__ );
}

/**
 * Helper function: Check if premium/paid license is active
 * 
 * Single-plugin model: Check if user has paid plan (not separate premium version)
 * 
 * @return bool True if premium license is active, false otherwise
 */
function swpdf_is_premium_active() {
    if ( function_exists( 'swpdf_fs' ) ) {
        $fs = swpdf_fs();
        // Check is_paying() for single-plugin model with paid plans
        if ( is_object( $fs ) && method_exists( $fs, 'is_paying' ) && $fs->is_paying() ) {
            return true;
        }
        // Also check is_premium() for backwards compatibility
        if ( is_object( $fs ) && method_exists( $fs, 'is_premium' ) && $fs->is_premium() ) {
            return true;
        }
    }
    return false;
}

/**
 * Helper function: Check if user can use premium features
 * 
 * @return bool True if premium features are available (license active or trial)
 */
function swpdf_can_use_premium_code() {
    if ( function_exists( 'swpdf_fs' ) ) {
        $fs = swpdf_fs();
        return ( is_object( $fs ) && method_exists( $fs, 'can_use_premium_code' ) && $fs->can_use_premium_code() );
    }
    return false;
}

/**
 * Helper function: Check if premium features are available
 * 
 * @return bool True if premium features are enabled
 */
function swpdf_premium_features_enabled() {
    return swpdf_is_premium_active();
}

/**
 * Helper function: Check if premium support is enabled
 * 
 * @return bool True if premium support is available
 */
function swpdf_premium_support_enabled() {
    // Premium support enabled for paid plans
    return swpdf_is_premium_active();
}

/**
 * Main Plugin Class
 */
class SWPDF_Sign_Fill {
    
    private static $instance = null;
    
    public static function get_instance() {
        if ( null === self::$instance ) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    private function __construct() {
        add_action( 'init', array( $this, 'create_uploads_directory' ) );
        add_action( 'admin_init', array( $this, 'maybe_update_database' ) ); // Run in admin only
        add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
        add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
        add_action( 'wp_ajax_swpdf_save_signed_pdf', array( $this, 'ajax_save_signed_pdf' ) );
        add_action( 'wp_ajax_nopriv_swpdf_save_signed_pdf', array( $this, 'ajax_save_signed_pdf' ) );
        add_action( 'wp_ajax_swpdf_upload_pdf_template', array( $this, 'ajax_upload_pdf_template' ) );
        add_action( 'wp_ajax_swpdf_save_template_fields', array( $this, 'ajax_save_template_fields' ) );
        add_action( 'wp_ajax_swpdf_save_field_labels', array( $this, 'ajax_save_field_labels' ) );
        add_action( 'wp_ajax_swpdf_get_template_for_edit', array( $this, 'ajax_get_template_for_edit' ) );
        add_action( 'wp_ajax_swpdf_delete_pdf_template', array( $this, 'ajax_delete_pdf_template' ) );
        add_action( 'wp_ajax_swpdf_get_pdf_template', array( $this, 'ajax_get_pdf_template' ) );
        add_action( 'wp_ajax_nopriv_swpdf_get_pdf_template', array( $this, 'ajax_get_pdf_template' ) );
        add_action( 'wp_ajax_swpdf_export_csv', array( $this, 'ajax_export_csv' ) );
        add_action( 'wp_ajax_swpdf_duplicate_template', array( $this, 'ajax_duplicate_template' ) );
        add_action( 'wp_ajax_swpdf_run_diagnostics', array( $this, 'ajax_run_diagnostics' ) );
        add_action( 'wp_ajax_swpdf_get_agreement_details', array( $this, 'ajax_get_agreement_details' ) ); // Secure modal AJAX
        add_action( 'wp_ajax_swpdf_delete_agreement', array( $this, 'ajax_delete_agreement' ) );
        add_shortcode( 'swpdf_signature_form', array( $this, 'render_signature_form' ) );
        add_shortcode( 'swpdf_form', array( $this, 'render_signature_form' ) );
        add_shortcode( 'swpdf_legacy_form', array( $this, 'render_signature_form' ) );
        add_shortcode( 'psf_signature_form', array( $this, 'render_signature_form' ) ); // Backward compat
        add_shortcode( 'PDF_Sign_Fill_form', array( $this, 'render_signature_form' ) ); // Legacy v1.x compat
        add_shortcode( 'pdf_sign_fill', array( $this, 'render_signature_form' ) ); // Legacy v1.x compat
        add_action( 'admin_menu', array( $this, 'add_admin_menu' ) );
        add_action( 'init', array( $this, 'register_gutenberg_block' ) );
    }
    
    /**
     * Ensure database table has all required columns (runs in admin_init only once)
     */
    public function maybe_update_database() {
        // Only run for admins
        if ( ! current_user_can( 'manage_options' ) ) {
            return;
        }
        
        // Migrate old prefixed options to swpdf_ (one-time, runs before version check)
        if ( ! get_option( 'swpdf_prefix_migrated_v3', false ) ) {
            $this->migrate_psf_to_swpdf_options();
            update_option( 'swpdf_prefix_migrated_v3', true );
        }
        
        global $wpdb;
        $table_name = $wpdb->prefix . 'swpdf_signed_docs';
        
        // Check if we've already updated (use a version option)
        $db_version = get_option( 'swpdf_db_version', '1.0' );
        if ( version_compare( $db_version, '3.14', '>=' ) ) {
            return;
        }
        
        // Check if stock_number column exists
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Safe: $table_name uses $wpdb->prefix
        $row = $wpdb->get_results( "SHOW COLUMNS FROM $table_name LIKE 'stock_number'" );
        if ( empty( $row ) ) {
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Safe: $table_name uses $wpdb->prefix
            $wpdb->query( "ALTER TABLE $table_name ADD stock_number varchar(100) DEFAULT NULL AFTER agreement_type" );
        }
        
        // v3.14: Migrate legacy options into swpdf_templates['fields'] (single source of truth)
        if ( ! get_option( 'swpdf_meta_keys_migrated', false ) ) {
            $this->migrate_field_config_to_templates();
            update_option( 'swpdf_meta_keys_migrated', true );
        }
        
        update_option( 'swpdf_db_version', '3.14' );
    }
    
    /**
     * Migrate old psf_ prefixed WordPress options to new swpdf_ prefix.
     * Also renames the database table from psf_signed_docs to swpdf_signed_docs if needed.
     */
    private function migrate_psf_to_swpdf_options() {
        // Map of old option names to new option names
        // Includes both psf_ prefix AND the original PDF_Sign_Fill_ prefix from v1.x
        $option_map = array(
            'psf_templates'              => 'swpdf_templates',
            'psf_settings'               => 'swpdf_settings',
            'psf_signature_settings'     => 'swpdf_signature_settings',
            'psf_date_settings'          => 'swpdf_date_settings',
            'psf_field_labels'           => 'swpdf_field_labels',
            'psf_field_required'         => 'swpdf_field_required',
            'psf_field_mappings'         => 'swpdf_field_mappings',
            'psf_field_meta_keys'        => 'swpdf_field_meta_keys',
            'psf_fields_lists'           => 'swpdf_fields_lists',
            'psf_db_version'             => 'swpdf_db_version',
            'psf_meta_keys_migrated'     => 'swpdf_meta_keys_migrated',
            // Original v1.x option names (PDF_Sign_Fill_ prefix)
            'PDF_Sign_Fill_settings'      => 'swpdf_signature_settings',
            'PDF_Sign_Fill_date_settings' => 'swpdf_date_settings',
        );

        foreach ( $option_map as $old_key => $new_key ) {
            $old_value = get_option( $old_key, null );
            if ( null === $old_value ) {
                continue; // Old option doesn't exist, skip
            }
            $new_value = get_option( $new_key, null );
            if ( null === $new_value || ( is_array( $new_value ) && empty( $new_value ) ) ) {
                // New option is missing or empty — copy old value
                update_option( $new_key, $old_value );
            } elseif ( is_array( $old_value ) && is_array( $new_value ) ) {
                // Both exist and are arrays — merge old keys into new (don't overwrite existing)
                $merged = $new_value;
                foreach ( $old_value as $k => $v ) {
                    if ( ! isset( $merged[ $k ] ) ) {
                        $merged[ $k ] = $v;
                    }
                }
                if ( $merged !== $new_value ) {
                    update_option( $new_key, $merged );
                }
            }
        }

        // Rename the database table if old one exists
        global $wpdb;
        $old_table = $wpdb->prefix . 'psf_signed_docs';
        $new_table = $wpdb->prefix . 'swpdf_signed_docs';
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Safe prefixed table names
        $old_exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $old_table ) );
        if ( $old_exists ) {
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Safe prefixed table names
            $new_exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $new_table ) );
            if ( ! $new_exists ) {
                // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Safe prefixed table names
                $wpdb->query( "RENAME TABLE `{$old_table}` TO `{$new_table}`" );
            }
        }
    }

    /**
     * Migrate all field config (labels, required, mappings, meta_keys) into swpdf_templates['fields']
     * This creates a single source of truth for field configuration
     */
    private function migrate_field_config_to_templates() {
        $templates = get_option( 'swpdf_templates', array() );
        $all_labels = get_option( 'swpdf_field_labels', array() );
        $all_required = get_option( 'swpdf_field_required', array() );
        $all_mappings = get_option( 'swpdf_field_mappings', array() );
        $all_meta_keys = get_option( 'swpdf_field_meta_keys', array() );
        $all_fields_lists = get_option( 'swpdf_fields_lists', array() );
        
        $migrated = false;
        
        foreach ( $templates as $type => &$template ) {
            // Get existing fields from fields_list if available
            $fields = isset( $all_fields_lists[ $type ] ) ? $all_fields_lists[ $type ] : array();
            
            // If template already has fields, use those as base
            if ( ! empty( $template['fields'] ) && is_array( $template['fields'] ) ) {
                $fields = $template['fields'];
            }
            
            $labels = isset( $all_labels[ $type ] ) ? $all_labels[ $type ] : array();
            $required = isset( $all_required[ $type ] ) ? $all_required[ $type ] : array();
            $mappings = isset( $all_mappings[ $type ] ) ? $all_mappings[ $type ] : array();
            $meta_keys = isset( $all_meta_keys[ $type ] ) ? $all_meta_keys[ $type ] : array();
            
            // Merge all config into each field
            foreach ( $fields as &$field ) {
                $name = isset( $field['name'] ) ? $field['name'] : '';
                if ( empty( $name ) ) continue;
                
                // Set label
                if ( isset( $labels[ $name ] ) && empty( $field['label'] ) ) {
                    $field['label'] = $labels[ $name ];
                }
                
                // Set required
                if ( isset( $required[ $name ] ) && ! isset( $field['required'] ) ) {
                    $field['required'] = (bool) $required[ $name ];
                }
                
                // Set maps_to
                if ( isset( $mappings[ $name ] ) && empty( $field['maps_to'] ) ) {
                    $field['maps_to'] = $mappings[ $name ];
                }
                
                // Set meta_key (only if maps_to === 'meta')
                // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Not a DB query; array key on custom data structure
                if ( isset( $meta_keys[ $name ] ) && empty( $field['meta_key'] ) ) {
                    if ( isset( $field['maps_to'] ) && $field['maps_to'] === 'meta' ) {
                        $field['meta_key'] = $meta_keys[ $name ];
                    }
                }
                
                $migrated = true;
            }
            unset( $field );
            
            // Store consolidated fields back into template
            $template['fields'] = $fields;
        }
        unset( $template );
        
        if ( $migrated ) {
            update_option( 'swpdf_templates', $templates );
        }
    }
    
    /**
     * Get uploads directory
     */
    private function get_uploads_dir() {
        $upload_dir = wp_upload_dir();
        return $upload_dir['basedir'] . '/swpdf-signed-docs/';
    }
    
    private function get_uploads_url() {
        $upload_dir = wp_upload_dir();
        return $upload_dir['baseurl'] . '/swpdf-signed-docs/';
    }
    
    private function get_templates_dir() {
        $upload_dir = wp_upload_dir();
        return $upload_dir['basedir'] . '/psf-templates/';
    }
    
    private function get_templates_url() {
        $upload_dir = wp_upload_dir();
        return $upload_dir['baseurl'] . '/psf-templates/';
    }
    
    /**
     * Create uploads directory for signed agreements
     */
    public function create_uploads_directory() {
        $uploads_dir = $this->get_uploads_dir();
        $templates_dir = $this->get_templates_dir();
        
        // Create signed agreements directory
        if ( ! file_exists( $uploads_dir ) ) {
            wp_mkdir_p( $uploads_dir );
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_chmod -- Safe internal path
            @chmod( $uploads_dir, 0755 );
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- Safe internal path
            file_put_contents( $uploads_dir . 'index.php', '<?php // Silence is golden' );
        }
        
        // Create PDF templates directory
        if ( ! file_exists( $templates_dir ) ) {
            wp_mkdir_p( $templates_dir );
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_chmod -- Safe internal path
            @chmod( $templates_dir, 0755 );
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- Safe internal path
            file_put_contents( $templates_dir . 'index.php', '<?php // Silence is golden' );
            
            // Add .htaccess to ensure PDFs are publicly accessible
            $htaccess_content = "# Allow direct access to PDF files\n";
            $htaccess_content .= "<FilesMatch \"\.(pdf|PDF)$\">\n";
            $htaccess_content .= "    Require all granted\n";
            $htaccess_content .= "</FilesMatch>\n";
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- Safe internal path
            file_put_contents( $templates_dir . '.htaccess', $htaccess_content );
        }
    }
    
    /**
     * Enqueue front-end scripts and styles
     */
    public function enqueue_scripts() {
        if ( ! is_singular() ) {
            return;
        }
        
        global $post;
        // Check for any of the supported shortcode names
        $has_shortcode = has_shortcode( $post->post_content, 'swpdf_signature_form' ) ||
                         has_shortcode( $post->post_content, 'swpdf_form' ) ||
                         has_shortcode( $post->post_content, 'swpdf_legacy_form' ) ||
                         has_shortcode( $post->post_content, 'psf_signature_form' ) ||
                         has_shortcode( $post->post_content, 'PDF_Sign_Fill_form' ) ||
                         has_shortcode( $post->post_content, 'pdf_sign_fill' );
        if ( ! $has_shortcode ) {
            return;
        }
        
        // Signature Pad library (included locally)
        wp_enqueue_script( 
            'signature-pad', 
            SWPDF_PLUGIN_URL . 'assets/js/signature_pad.min.js',
            array(), 
            '4.1.7', 
            true 
        );
        
        // PDF.js for displaying PDFs (included locally)
        wp_enqueue_script( 
            'pdfjs-dist', 
            SWPDF_PLUGIN_URL . 'assets/js/pdf.min.js',
            array(), 
            '5.4.624', 
            true 
        );
        
        // PDF-lib for filling PDFs (included locally)
        wp_enqueue_script( 
            'pdf-lib', 
            SWPDF_PLUGIN_URL . 'assets/js/pdf-lib.min.js',
            array(), 
            '1.17.1', 
            true 
        );
        
        // Custom plugin script
        wp_enqueue_script( 
            'signwpdf-pdf-sign-fill', 
            SWPDF_PLUGIN_URL . 'assets/js/pdf-interactive.js',
            array( 'jquery', 'signature-pad', 'pdfjs-dist', 'pdf-lib' ), 
            SWPDF_VERSION, 
            true 
        );
        
        // Localize script
        $swpdf_settings = get_option( 'swpdf_settings', array() );
        $show_branding = isset( $swpdf_settings['show_powered_by'] ) ? (bool) $swpdf_settings['show_powered_by'] : false;
        $is_premium = swpdf_is_premium_active();
        
        wp_localize_script( 'signwpdf-pdf-sign-fill', 'swpdfSignature', array(
            'ajaxUrl' => admin_url( 'admin-ajax.php' ),
            'nonce' => wp_create_nonce( 'swpdf_form_nonce' ),
            'templatesUrl' => $this->get_templates_url(),
            'pdfjsWorker' => SWPDF_PLUGIN_URL . 'assets/js/pdf.worker.min.js',
            'isPremium' => $is_premium,
            'showBranding' => $show_branding && ! $is_premium, // Show only if setting enabled AND not premium
            'strings' => array(
                'signatureRequired' => __( 'Please sign the agreement before submitting.', 'signwpdf-pdf-sign-fill' ),
                'fillAllFields' => __( 'Please fill in all required fields.', 'signwpdf-pdf-sign-fill' ),
                'submitting' => __( 'Submitting...', 'signwpdf-pdf-sign-fill' ),
                'success' => __( 'Your agreement has been submitted successfully!', 'signwpdf-pdf-sign-fill' ),
                'error' => __( 'An error occurred. Please try again.', 'signwpdf-pdf-sign-fill' ),
            )
        ) );
        
        // Custom styles
        wp_enqueue_style( 
            'signwpdf-pdf-sign-fill', 
            SWPDF_PLUGIN_URL . 'assets/css/pdf-interactive.css',
            array(), 
            SWPDF_VERSION 
        );
    }
    
    /**
     * Enqueue admin scripts
     */
    public function admin_enqueue_scripts( $hook ) {
        // Use $_GET['page'] for reliable page detection (hook names are unpredictable with complex slugs)
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Admin page detection only, no data processing
        $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : '';
        
        // Only load on our plugin pages
        $our_pages = array( 'signwpdf-pdf-sign-fill', 'swpdf-templates', 'swpdf-settings', 'swpdf-license' );
        if ( ! in_array( $page, $our_pages, true ) ) {
            return;
        }
        
        // Always load admin CSS on our pages
        wp_enqueue_style(
            'swpdf-admin',
            SWPDF_PLUGIN_URL . 'assets/css/admin.css',
            array(),
            SWPDF_VERSION
        );
        
        // License page
        if ( $page === 'swpdf-license' ) {
            wp_enqueue_script(
                'swpdf-license-admin',
                SWPDF_PLUGIN_URL . 'assets/js/license-admin.js',
                array( 'jquery' ),
                SWPDF_VERSION,
                true
            );
            
            wp_localize_script( 'swpdf-license-admin', 'swpdfLicense', array(
                'ajaxUrl' => admin_url( 'admin-ajax.php' ),
                'nonce' => wp_create_nonce( 'swpdf_license_nonce' ),
            ) );
            return;
        }
        
        // Main admin page (Signed Agreements list)
        if ( $page === 'signwpdf-pdf-sign-fill' ) {
            wp_enqueue_script(
                'swpdf-admin-page',
                SWPDF_PLUGIN_URL . 'assets/js/admin-page.js',
                array( 'jquery' ),
                SWPDF_VERSION,
                true
            );
            
            wp_localize_script( 'swpdf-admin-page', 'swpdfAdminPage', array(
                'ajaxUrl' => admin_url( 'admin-ajax.php' ),
                'adminNonce' => wp_create_nonce( 'swpdf_admin_nonce' ),
                'exportNonce' => wp_create_nonce( 'swpdf_export_csv' ),
            ) );
            return;
        }
        
        // Settings page — enqueue external CSS and JS
        if ( $page === 'swpdf-settings' ) {
            wp_enqueue_style(
                'swpdf-settings-css',
                SWPDF_PLUGIN_URL . 'assets/css/swpdf-settings.css',
                array(),
                SWPDF_VERSION
            );
            wp_enqueue_script(
                'swpdf-settings-js',
                SWPDF_PLUGIN_URL . 'assets/js/swpdf-settings.js',
                array(),
                SWPDF_VERSION,
                true
            );
            return;
        }
        
        // Templates page - needs PDF.js and admin scripts
        if ( $page === 'swpdf-templates' ) {
            wp_enqueue_script( 
                'pdfjs-dist', 
                SWPDF_PLUGIN_URL . 'assets/js/pdf.min.js',
                array(), 
                '5.4.624', 
                true 
            );
            
            wp_enqueue_script(
                'swpdf-admin-templates',
                SWPDF_PLUGIN_URL . 'assets/js/admin.js',
                array( 'jquery', 'pdfjs-dist' ),
                SWPDF_VERSION,
                true
            );
            
            wp_localize_script( 'swpdf-admin-templates', 'swpdfAdmin', array(
                'ajaxUrl' => admin_url( 'admin-ajax.php' ),
                'nonce' => wp_create_nonce( 'swpdf_admin_nonce' ),
                'templatesUrl' => $this->get_templates_url(),
                'pdfjsWorker' => SWPDF_PLUGIN_URL . 'assets/js/pdf.worker.min.js',
            ) );
            
            // DEV MODE: Load testing helpers
            if ( defined( 'SWPDF_DEV_MODE' ) && SWPDF_DEV_MODE ) {
                wp_enqueue_script(
                    'swpdf-dev-helpers',
                    SWPDF_PLUGIN_URL . 'assets/js/dev-helpers.js',
                    array( 'jquery', 'swpdf-admin-templates' ),
                    SWPDF_VERSION . '.' . time(),
                    true
                );
                
                wp_localize_script( 'swpdf-dev-helpers', 'swpdfDevMode', array(
                    'enabled' => true,
                    'version' => SWPDF_VERSION,
                ) );
            }
            return;
        }
    }
    
    /**
     * Render signature form shortcode
     */
    public function render_signature_form( $atts ) {
        $atts = shortcode_atts( array(
            'agreement_title' => '', // Empty = use template name
            'agreement_type' => 'purchase-to-order',
            'type' => '', // Alias for agreement_type
        ), $atts );
        
        // Allow 'type' as shorthand for 'agreement_type'
        if ( ! empty( $atts['type'] ) ) {
            $atts['agreement_type'] = $atts['type'];
        }
        
        // If no title specified, get the template name
        if ( empty( $atts['agreement_title'] ) ) {
            $templates = get_option( 'swpdf_templates', array() );
            if ( empty( $templates ) ) {
                $templates = get_option( 'psf_templates', array() );
            }
            if ( isset( $templates[ $atts['agreement_type'] ] ) && ! empty( $templates[ $atts['agreement_type'] ]['name'] ) ) {
                $atts['agreement_title'] = $templates[ $atts['agreement_type'] ]['name'];
            } else {
                // Fallback: convert agreement_type to title case
                $atts['agreement_title'] = ucwords( str_replace( array( '-', '_' ), ' ', $atts['agreement_type'] ) );
            }
        }
        
        ob_start();
        include SWPDF_PLUGIN_DIR . 'templates/signature-form-new.php';
        return ob_get_clean();
    }
    
    /**
     * AJAX handler to save signed PDF
     */
    public function ajax_save_signed_pdf() {
        // Use public nonce for front-end form submissions
        check_ajax_referer( 'swpdf_form_nonce', 'nonce' );
        
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- JSON string decoded and validated below
        $form_data_raw = isset( $_POST['form_data'] ) ? wp_unslash( $_POST['form_data'] ) : '';
        $form_data = ! empty( $form_data_raw ) ? json_decode( $form_data_raw, true ) : array();
        if ( ! is_array( $form_data ) ) {
            $form_data = array();
        }
        $signature_data = isset( $_POST['signature_data'] ) ? sanitize_text_field( wp_unslash( $_POST['signature_data'] ) ) : '';
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Base64-encoded PDF data, validated before use
        $pdf_data = isset( $_POST['pdf_data'] ) ? wp_unslash( $_POST['pdf_data'] ) : '';
        
        if ( empty( $form_data ) || empty( $signature_data ) || empty( $pdf_data ) ) {
            wp_send_json_error( array( 'message' => 'Missing required data.' ) );
        }
        
        $agreement_type = isset( $_POST['agreement_type'] ) ? sanitize_key( wp_unslash( $_POST['agreement_type'] ) ) : '';
        if ( empty( $agreement_type ) && isset( $form_data['agreement_type'] ) ) {
            $agreement_type = sanitize_key( $form_data['agreement_type'] );
        }
        
        // Get template config (SINGLE SOURCE OF TRUTH)
        $templates = get_option( 'swpdf_templates', array() );
        $template = isset( $templates[ $agreement_type ] ) ? $templates[ $agreement_type ] : array();
        $fields_config = isset( $template['fields'] ) ? $template['fields'] : array();
        
        // Build field lookup by name for type-based sanitization
        $field_config_map = array();
        foreach ( $fields_config as $f ) {
            if ( isset( $f['name'] ) ) {
                $field_config_map[ sanitize_key( $f['name'] ) ] = $f;
            }
        }
        
        // Sanitize submitted data based on field type
        $sanitized_data = array();
        foreach ( $form_data as $key => $value ) {
            $safe_key = sanitize_key( $key );
            $field_type = isset( $field_config_map[ $safe_key ]['type'] ) ? $field_config_map[ $safe_key ]['type'] : 'text';
            
            // Type-based sanitization
            switch ( $field_type ) {
                case 'email':
                    $sanitized_data[ $safe_key ] = sanitize_email( $value );
                    break;
                case 'phone':
                case 'tel':
                    $sanitized_data[ $safe_key ] = preg_replace( '/[^0-9+\-() ]/', '', $value );
                    break;
                case 'number':
                    $sanitized_data[ $safe_key ] = is_numeric( $value ) ? floatval( $value ) : '';
                    break;
                case 'date':
                    $sanitized_data[ $safe_key ] = sanitize_text_field( $value );
                    break;
                case 'checkbox':
                    $sanitized_data[ $safe_key ] = $value ? 'Yes' : 'No';
                    break;
                default:
                    $sanitized_data[ $safe_key ] = sanitize_text_field( $value );
            }
        }
        
        // Build metadata array from template-defined fields only
        // NEVER allow user-supplied meta_key - only use template-defined ones
        $metadata = array();
        foreach ( $fields_config as $field ) {
            if ( isset( $field['maps_to'] ) && $field['maps_to'] === 'meta' ) {
                $field_key = sanitize_key( $field['name'] );
                $value = isset( $sanitized_data[ $field_key ] ) ? $sanitized_data[ $field_key ] : '';
                
                if ( $value !== '' ) {
                    if ( ! empty( $field['meta_key'] ) && preg_match( '/^[a-z0-9_]{2,40}$/', $field['meta_key'] ) ) {
                        // Use template-defined meta_key
                        $metadata[ $field['meta_key'] ] = $value;
                    } else {
                        // Fallback: auto-generate from field name (swpdf_ prefix)
                        $auto_key = 'swpdf_' . preg_replace( '/[^a-z0-9_]/', '_', strtolower( $field['name'] ) );
                        $auto_key = substr( $auto_key, 0, 40 ); // Cap at 40 chars
                        $metadata[ $auto_key ] = $value;
                    }
                }
            }
        }
        
        // Legacy fallback: check old swpdf_field_mappings if no template fields
        if ( empty( $fields_config ) ) {
            $all_mappings = get_option( 'swpdf_field_mappings', array() );
            $field_mappings = isset( $all_mappings[ $agreement_type ] ) ? $all_mappings[ $agreement_type ] : array();
            
            $all_meta_keys = get_option( 'swpdf_field_meta_keys', array() );
            $legacy_meta_keys = isset( $all_meta_keys[ $agreement_type ] ) ? $all_meta_keys[ $agreement_type ] : array();
            
            foreach ( $field_mappings as $field_name => $maps_to ) {
                if ( $maps_to === 'meta' ) {
                    $field_key = sanitize_key( $field_name );
                    $value = isset( $sanitized_data[ $field_key ] ) ? $sanitized_data[ $field_key ] : '';
                    if ( $value !== '' ) {
                        $meta_key = isset( $legacy_meta_keys[ $field_name ] ) ? $legacy_meta_keys[ $field_name ] : '';
                        if ( ! empty( $meta_key ) && preg_match( '/^[a-z0-9_]{2,40}$/', $meta_key ) ) {
                            $metadata[ $meta_key ] = $value;
                        } else {
                            $auto_key = 'swpdf_' . preg_replace( '/[^a-z0-9_]/', '_', strtolower( $field_name ) );
                            $metadata[ $auto_key ] = $value;
                        }
                    }
                }
            }
        }
        
        // Initialize mapped column values
        $customer_name = '';
        $customer_email = '';
        $customer_phone = '';
        $stock_number = '';
        
        // DEBUG: Log field mapping process
        if ( defined( 'SWPDF_DEV_MODE' ) && SWPDF_DEV_MODE ) {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug only, guarded by SWPDF_DEV_MODE
            error_log( '[PSF DEBUG] Agreement type: ' . $agreement_type );
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
            error_log( '[PSF DEBUG] Fields config count: ' . count( $fields_config ) );
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
            error_log( '[PSF DEBUG] Sanitized data keys: ' . implode( ', ', array_keys( $sanitized_data ) ) );
            foreach ( $fields_config as $i => $f ) {
                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
                error_log( '[PSF DEBUG] Field ' . $i . ': name=' . ( $f['name'] ?? 'N/A' ) . ', maps_to=' . ( $f['maps_to'] ?? 'none' ) );
            }
        }
        
        // Apply mappings from template fields
        foreach ( $fields_config as $field ) {
            $field_key = sanitize_key( $field['name'] ?? '' );
            $maps_to = $field['maps_to'] ?? 'none';
            $value = $sanitized_data[ $field_key ] ?? '';
            
            // DEBUG: Show matching process
            if ( defined( 'SWPDF_DEV_MODE' ) && SWPDF_DEV_MODE && ! empty( $maps_to ) && $maps_to !== 'none' ) {
                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Debug only, guarded by SWPDF_DEV_MODE
                error_log( '[PSF DEBUG] Trying to map: field_key=' . $field_key . ', maps_to=' . $maps_to . ', found_value=' . ( $value ?: '(empty)' ) );
                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log
                error_log( '[PSF DEBUG] Key exists in sanitized_data? ' . ( isset( $sanitized_data[ $field_key ] ) ? 'YES' : 'NO' ) );
            }
            
            if ( ! empty( $value ) ) {
                switch ( $maps_to ) {
                    case 'customer_name':
                        $customer_name = $value;
                        break;
                    case 'customer_email':
                        $customer_email = $value;
                        break;
                    case 'customer_phone':
                        $customer_phone = $value;
                        break;
                    case 'stock_number':
                        $stock_number = $value;
                        break;
                }
            }
        }
        
        // Legacy fallback for mappings
        if ( empty( $fields_config ) ) {
            $all_mappings = get_option( 'swpdf_field_mappings', array() );
            $field_mappings = isset( $all_mappings[ $agreement_type ] ) ? $all_mappings[ $agreement_type ] : array();
            
            foreach ( $field_mappings as $field_name => $maps_to ) {
                $field_key = sanitize_key( $field_name );
                if ( ! empty( $sanitized_data[ $field_key ] ) ) {
                    switch ( $maps_to ) {
                        case 'customer_name':
                            $customer_name = $sanitized_data[ $field_key ];
                            break;
                        case 'customer_email':
                            $customer_email = $sanitized_data[ $field_key ];
                            break;
                        case 'customer_phone':
                            $customer_phone = $sanitized_data[ $field_key ];
                            break;
                        case 'stock_number':
                            $stock_number = $sanitized_data[ $field_key ];
                            break;
                    }
                }
            }
        }
        
        // Fall back to auto-detection for fields not explicitly mapped
        if ( empty( $customer_name ) ) {
            $name_fields = array( 'name_1', 'name', 'customer_name', 'full_name', 'client_name' );
            foreach ( $name_fields as $field ) {
                if ( ! empty( $sanitized_data[ $field ] ) ) {
                    $customer_name = $sanitized_data[ $field ];
                    break;
                }
            }
        }
        
        if ( empty( $customer_email ) ) {
            $email_fields = array( 'primary_email', 'email', 'customer_email', 'e_mail', 'email_address' );
            foreach ( $email_fields as $field ) {
                if ( ! empty( $sanitized_data[ $field ] ) ) {
                    $customer_email = $sanitized_data[ $field ];
                    break;
                }
            }
        }
        
        if ( empty( $customer_phone ) ) {
            $phone_fields = array( 'preferred_phone', 'phone', 'customer_phone', 'telephone', 'phone_number', 'undefined' );
            foreach ( $phone_fields as $field ) {
                if ( ! empty( $sanitized_data[ $field ] ) ) {
                    $customer_phone = $sanitized_data[ $field ];
                    break;
                }
            }
        }
        
        if ( empty( $stock_number ) ) {
            $stock_fields = array( 'stock_number_on_website', 'stock_number', 'stock', 'stock_no' );
            foreach ( $stock_fields as $field ) {
                if ( ! empty( $sanitized_data[ $field ] ) ) {
                    $stock_number = $sanitized_data[ $field ];
                    break;
                }
            }
        }
        
        $timestamp = time();
        $filename = sprintf( 
            '%s_%s_%s.pdf', 
            $agreement_type ?: 'agreement',
            sanitize_file_name( $customer_name ?: 'customer' ),
            $timestamp
        );
        
        // Validate PDF data size (max 50MB base64 = ~37MB file)
        if ( strlen( $pdf_data ) > 50 * 1024 * 1024 ) {
            wp_send_json_error( array( 'message' => 'PDF file too large.' ) );
        }
        
        $pdf_base64 = preg_replace( '#^data:application/pdf;base64,#i', '', $pdf_data );
        // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode -- Decoding client-submitted base64-encoded PDF data, not obfuscation
        $pdf_content = base64_decode( $pdf_base64, true ); // Strict mode
        
        if ( $pdf_content === false ) {
            wp_send_json_error( array( 'message' => 'Invalid PDF data encoding.' ) );
        }
        
        // Validate PDF magic bytes
        if ( substr( $pdf_content, 0, 4 ) !== '%PDF' ) {
            wp_send_json_error( array( 'message' => 'Invalid PDF file format.' ) );
        }
        
        $file_path = $this->get_uploads_dir() . $filename;
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- Writing binary PDF data to uploads directory
        $saved = file_put_contents( $file_path, $pdf_content );
        
        if ( $saved === false ) {
            wp_send_json_error( array( 'message' => 'Failed to save PDF file.' ) );
        }
        
        global $wpdb;
        $table_name = $wpdb->prefix . 'swpdf_signed_docs';
        
        // Build form_data with metadata included for easy retrieval
        // Structure: { "fields": {...}, "metadata": {...} }
        $form_data_with_meta = array(
            'fields' => $sanitized_data,
            'metadata' => $metadata,
        );
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Inserting signed document record
        $inserted = $wpdb->insert(
            $table_name,
            array(
                'customer_name' => $customer_name,
                'customer_email' => $customer_email,
                'customer_phone' => $customer_phone,
                'agreement_type' => $agreement_type,
                'stock_number' => $stock_number,
                'form_data' => wp_json_encode( $form_data_with_meta ),
                'file_path' => $filename,
                'ip_address' => $this->get_client_ip(),
                'user_agent' => sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ?? '' ) ),
                'signed_at' => current_time( 'mysql' ),
            ),
            array( '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s' )
        );
        
        if ( $inserted === false ) {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Logging database errors for debugging
            error_log( 'PDF Sign & Fill DB Error: ' . $wpdb->last_error );
            wp_send_json_error( array( 'message' => __( 'Failed to save agreement data. Please try again or contact the site administrator.', 'signwpdf-pdf-sign-fill' ) ) );
        }
        
        // Add audit certificate page if enabled
        $settings = $this->get_email_settings();
        if ( ! empty( $settings['audit_trail_in_pdf'] ) ) {
            $audit_data = array(
                'id' => $wpdb->insert_id,
                'customer_name' => $customer_name,
                'customer_email' => $customer_email,
                'customer_phone' => $customer_phone,
                'agreement_type' => $agreement_type,
                'file_name' => $filename,
                'signed_at' => current_time( 'F j, Y \a\t g:i:s A' ),
                'ip_address' => $this->get_client_ip(),
                'user_agent' => sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ?? '' ) ),
            );
            SWPDF_Audit_Certificate::add_audit_page( $file_path, $audit_data );
        }
        
        // Prepare data for email with mapped values
        $email_data = array(
            'customer_name' => $customer_name,
            'customer_email' => $customer_email,
            'customer_phone' => $customer_phone,
            'agreement_type' => $agreement_type,
            'stock_number' => $stock_number,
        );
        $this->send_email_notification( $email_data, $file_path );
        
        // Get settings for success screen
        $settings = $this->get_email_settings();
        $upload_dir = wp_upload_dir();
        $download_url = $settings['allow_signer_download'] ? $upload_dir['baseurl'] . '/swpdf-signed-docs/' . $filename : '';
        
        wp_send_json_success( array( 
            'message' => 'Agreement saved successfully!',
            'agreement_id' => $wpdb->insert_id,
            'download_url' => $download_url,
            'success_title' => $settings['success_title'],
            'success_message' => $settings['success_message'],
            'success_additional_info' => isset( $settings['success_additional_info'] ) ? $settings['success_additional_info'] : '',
            'redirect_url' => $settings['success_redirect_url'],
            'redirect_delay' => $settings['success_redirect_delay'],
            'allow_download' => $settings['allow_signer_download'],
        ) );
    }
    
    /**
     * Send email notification with customizable templates
     */
    private function send_email_notification( $data, $file_path ) {
        $settings = $this->get_email_settings();
        
        // Check if emails are enabled
        if ( ! $settings['email_enabled'] ) {
            return;
        }
        
        // Prepare replacement variables
        $replacements = array(
            '{customer_name}' => $data['customer_name'] ?? 'Customer',
            '{customer_email}' => $data['customer_email'] ?? '',
            '{customer_phone}' => $data['customer_phone'] ?? '',
            '{agreement_type}' => $data['agreement_type'] ?? '',
            '{signed_date}' => current_time( 'F j, Y \a\t g:i a' ),
            '{company_name}' => $settings['company_name'],
            '{signer_ip}' => $this->get_client_ip(),
        );
        
        $headers = array(
            'Content-Type: text/plain; charset=UTF-8',
            sprintf( 'From: %s <%s>', $settings['email_from_name'], $settings['email_from_address'] ),
        );
        
        // Send to admin
        if ( $settings['email_to_admin'] && ! empty( $settings['admin_email'] ) ) {
            $admin_subject = str_replace( array_keys( $replacements ), array_values( $replacements ), $settings['admin_email_subject'] );
            $admin_body = str_replace( array_keys( $replacements ), array_values( $replacements ), $settings['admin_email_body'] );
            
            wp_mail( $settings['admin_email'], $admin_subject, $admin_body, $headers, array( $file_path ) );
        }
        
        // Send to signer
        if ( $settings['email_to_signer'] && ! empty( $data['customer_email'] ) ) {
            $signer_subject = str_replace( array_keys( $replacements ), array_values( $replacements ), $settings['signer_email_subject'] );
            $signer_body = str_replace( array_keys( $replacements ), array_values( $replacements ), $settings['signer_email_body'] );
            
            wp_mail( $data['customer_email'], $signer_subject, $signer_body, $headers, array( $file_path ) );
        }
    }
    
    /**
     * Get email settings with defaults
     */
    private function get_email_settings() {
        $settings = get_option( 'swpdf_settings', array() );
        $defaults = array(
            'email_enabled' => 1,
            'email_to_admin' => 1,
            'email_to_signer' => 1,
            'admin_email' => get_option( 'admin_email' ),
            'email_from_name' => get_bloginfo( 'name' ),
            'email_from_address' => get_option( 'admin_email' ),
            'admin_email_subject' => 'New Signed Document: {customer_name}',
            'admin_email_body' => "A new document has been signed.\n\nCustomer: {customer_name}\nEmail: {customer_email}\nPhone: {customer_phone}\nDocument Type: {agreement_type}\nSigned: {signed_date}\n\nThe signed PDF is attached.",
            'signer_email_subject' => 'Your Signed Document - {company_name}',
            'signer_email_body' => "Dear {customer_name},\n\nThank you for signing the document. Please find your signed copy attached for your records.\n\nDocument Type: {agreement_type}\nSigned: {signed_date}\n\nBest regards,\n{company_name}",
            'audit_trail_enabled' => 1,
            'audit_trail_in_pdf' => 1,
            'company_name' => get_bloginfo( 'name' ),
            'success_title' => 'Thank You!',
            'success_message' => 'Your document has been signed successfully. You will receive a confirmation email shortly.',
            'success_redirect_url' => '',
            'success_redirect_delay' => 5,
            'allow_signer_download' => 1,
            'require_email_first' => 0,
        );
        return wp_parse_args( $settings, $defaults );
    }
    
    /**
     * Get client IP address
     */
    private function get_client_ip() {
        $ip_keys = array( 'HTTP_CF_CONNECTING_IP', 'HTTP_X_FORWARDED_FOR', 'HTTP_X_REAL_IP', 'REMOTE_ADDR' );
        foreach ( $ip_keys as $key ) {
            // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated -- Looping through known IP header keys
            if ( ! empty( $_SERVER[ $key ] ) ) {
                $ip = sanitize_text_field( wp_unslash( $_SERVER[ $key ] ) );
                // Handle comma-separated IPs (X-Forwarded-For)
                if ( strpos( $ip, ',' ) !== false ) {
                    $ip = trim( explode( ',', $ip )[0] );
                }
                if ( filter_var( $ip, FILTER_VALIDATE_IP ) ) {
                    return $ip;
                }
            }
        }
        return 'Unknown';
    }
    
    /**
     * Add admin menu
     */
    public function add_admin_menu() {
        add_menu_page(
            __( 'Signed Agreements', 'signwpdf-pdf-sign-fill' ),
            __( 'Signed Agreements', 'signwpdf-pdf-sign-fill' ),
            'manage_options',
            'signwpdf-pdf-sign-fill',
            array( $this, 'render_admin_page' ),
            'dashicons-media-document',
            30
        );
        
        add_submenu_page(
            'signwpdf-pdf-sign-fill',
            __( 'PDF Templates', 'signwpdf-pdf-sign-fill' ),
            __( 'PDF Templates', 'signwpdf-pdf-sign-fill' ),
            'manage_options',
            'swpdf-templates',
            array( $this, 'render_templates_page' )
        );
        
        add_submenu_page(
            'signwpdf-pdf-sign-fill',
            __( 'Settings', 'signwpdf-pdf-sign-fill' ),
            __( 'Settings', 'signwpdf-pdf-sign-fill' ),
            'manage_options',
            'swpdf-settings',
            array( $this, 'render_settings_page' )
        );
        
        add_submenu_page(
            'signwpdf-pdf-sign-fill',
            __( 'License', 'signwpdf-pdf-sign-fill' ),
            __( 'License', 'signwpdf-pdf-sign-fill' ),
            'manage_options',
            'swpdf-license',
            array( $this, 'render_license_page' )
        );
    }
    
    /**
     * Render admin page
     */
    public function render_admin_page() {
        include SWPDF_PLUGIN_DIR . 'templates/admin-page.php';
    }
    
    /**
     * Render templates page
     */
    public function render_templates_page() {
        include SWPDF_PLUGIN_DIR . 'templates/templates-page.php';
    }
    
    /**
     * Render settings page
     */
    public function render_settings_page() {
        include SWPDF_PLUGIN_DIR . 'templates/settings-page.php';
    }
    
    /**
     * Render license page
     */
    public function render_license_page() {
        include SWPDF_PLUGIN_DIR . 'admin/swpdf-license-page.php';
    }
    
    /**
     * Register Gutenberg Block
     */
    public function register_gutenberg_block() {
        if ( ! function_exists( 'register_block_type' ) ) {
            return;
        }
        
        // Register block editor script
        wp_register_script(
            'swpdf-block-editor',
            SWPDF_PLUGIN_URL . 'assets/js/block-editor.js',
            array( 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components', 'wp-i18n' ),
            SWPDF_VERSION,
            true
        );
        
        // Pass templates to block
        $templates = get_option( 'swpdf_templates', array() );
        $template_options = array();
        foreach ( $templates as $type => $template ) {
            $template_options[] = array(
                'value' => $type,
                'label' => $template['name'],
            );
        }
        
        wp_localize_script( 'swpdf-block-editor', 'swpdfBlockData', array(
            'templates' => $template_options,
        ) );
        
        // Register the block
        register_block_type( 'swpdf/signature-form', array(
            'editor_script' => 'swpdf-block-editor',
            'render_callback' => array( $this, 'render_gutenberg_block' ),
            'attributes' => array(
                'templateType' => array(
                    'type' => 'string',
                    'default' => '',
                ),
                'title' => array(
                    'type' => 'string',
                    'default' => 'Sign Document',
                ),
            ),
        ) );
    }
    
    /**
     * Render Gutenberg block on frontend
     */
    public function render_gutenberg_block( $attributes ) {
        $template_type = isset( $attributes['templateType'] ) ? $attributes['templateType'] : '';
        $title = isset( $attributes['title'] ) ? $attributes['title'] : 'Sign Document';
        
        if ( empty( $template_type ) ) {
            return '<p style="color: #999; padding: 20px; background: #f5f5f5; border-radius: 4px;">⚠️ Please select a PDF template in the block settings.</p>';
        }
        
        return $this->render_signature_form( array(
            'type' => $template_type,
            'agreement_title' => $title,
        ) );
    }
    
    /**
     * AJAX: Upload PDF template
     */
    public function ajax_upload_pdf_template() {
        check_ajax_referer( 'swpdf_admin_nonce', 'nonce' );
        
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Unauthorized' ) );
        }
        
        if ( empty( $_FILES['pdf_file'] ) ) {
            wp_send_json_error( array( 'message' => 'No file uploaded' ) );
        }
        
        $template_name = isset( $_POST['template_name'] ) ? sanitize_text_field( wp_unslash( $_POST['template_name'] ) ) : '';
        $agreement_type = isset( $_POST['agreement_type'] ) ? sanitize_key( wp_unslash( $_POST['agreement_type'] ) ) : '';
        
        if ( empty( $template_name ) || empty( $agreement_type ) ) {
            wp_send_json_error( array( 'message' => 'Template name and type are required' ) );
        }
        
        // Use wp_handle_upload with PDF-only mime type allowlist
        require_once ABSPATH . 'wp-admin/includes/file.php';
        
        $upload_overrides = array(
            'test_form' => false,
            'mimes'     => array( 'pdf' => 'application/pdf' ),
        );
        
        $uploaded_file = wp_handle_upload( $_FILES['pdf_file'], $upload_overrides );
        
        if ( isset( $uploaded_file['error'] ) ) {
            wp_send_json_error( array( 'message' => $uploaded_file['error'] ) );
        }
        
        // Move file to our templates directory with controlled filename
        $filename = $agreement_type . '_' . time() . '.pdf';
        $templates_dir = $this->get_templates_dir();
        $filepath = $templates_dir . $filename;
        
        // Ensure templates directory exists
        if ( ! file_exists( $templates_dir ) ) {
            wp_mkdir_p( $templates_dir );
        }
        
        // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.rename_rename -- Intentional error suppression, cross-filesystem fallback below
        if ( ! @rename( $uploaded_file['file'], $filepath ) ) {
            // Fallback: copy and delete if rename fails (cross-filesystem)
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_copy -- Cross-filesystem fallback for rename
            if ( ! copy( $uploaded_file['file'], $filepath ) ) {
                wp_send_json_error( array( 'message' => 'Failed to save PDF file' ) );
            }
            wp_delete_file( $uploaded_file['file'] );
        }
        
        // Set explicit permissions to ensure public accessibility
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_chmod
        chmod( $filepath, 0644 );
        
        // DON'T save to templates yet - just return info for preview
        // Template will be registered when user clicks "Save All Settings"
        wp_send_json_success( array(
            'message' => 'PDF uploaded - configure settings and click Save',
            'template_name' => $template_name,
            'agreement_type' => $agreement_type,
            'filename' => $filename,
            'url' => $this->get_templates_url() . $filename,
        ) );
    }
    
    /**
     * AJAX: Save template fields configuration
     */
    public function ajax_save_template_fields() {
        check_ajax_referer( 'swpdf_admin_nonce', 'nonce' );
        
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Unauthorized' ) );
        }
        
        $agreement_type = isset( $_POST['agreement_type'] ) ? sanitize_key( wp_unslash( $_POST['agreement_type'] ) ) : '';
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- JSON string decoded and validated below
        $fields_raw = isset( $_POST['fields'] ) ? wp_unslash( $_POST['fields'] ) : '';
        $fields = ! empty( $fields_raw ) ? json_decode( $fields_raw, true ) : null;
        
        if ( empty( $agreement_type ) || ! is_array( $fields ) ) {
            wp_send_json_error( array( 'message' => 'Invalid data' ) );
        }
        
        $templates = get_option( 'swpdf_templates', array() );
        
        if ( ! isset( $templates[ $agreement_type ] ) ) {
            wp_send_json_error( array( 'message' => 'Template not found' ) );
        }
        
        // Sanitize each field before saving
        $sanitized_fields = array();
        $allowed_field_keys = array( 'name', 'type', 'label', 'required', 'maps_to', 'meta_key', 'page', 'x', 'y', 'width', 'height' );
        foreach ( $fields as $field ) {
            if ( ! is_array( $field ) ) continue;
            $sanitized_field = array();
            foreach ( $allowed_field_keys as $key ) {
                if ( isset( $field[ $key ] ) ) {
                    if ( in_array( $key, array( 'page', 'x', 'y', 'width', 'height' ), true ) ) {
                        $sanitized_field[ $key ] = intval( $field[ $key ] );
                    } elseif ( $key === 'required' ) {
                        $sanitized_field[ $key ] = (bool) $field[ $key ];
                    } else {
                        $sanitized_field[ $key ] = sanitize_text_field( $field[ $key ] );
                    }
                }
            }
            if ( ! empty( $sanitized_field['name'] ) ) {
                $sanitized_fields[] = $sanitized_field;
            }
        }
        
        $templates[ $agreement_type ]['fields'] = $sanitized_fields;
        update_option( 'swpdf_templates', $templates );
        
        wp_send_json_success( array( 'message' => 'Template fields saved successfully' ) );
    }
    
    /**
     * AJAX: Delete PDF template
     */
    public function ajax_delete_pdf_template() {
        check_ajax_referer( 'swpdf_admin_nonce', 'nonce' );
        
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Unauthorized' ) );
        }
        
        $agreement_type = isset( $_POST['agreement_type'] ) ? sanitize_key( wp_unslash( $_POST['agreement_type'] ) ) : '';
        $filename = isset( $_POST['filename'] ) ? sanitize_file_name( wp_unslash( $_POST['filename'] ) ) : '';
        
        if ( empty( $agreement_type ) || empty( $filename ) ) {
            wp_send_json_error( array( 'message' => 'Missing required parameters' ) );
        }
        
        $templates = get_option( 'swpdf_templates', array() );
        
        if ( ! isset( $templates[ $agreement_type ] ) ) {
            wp_send_json_error( array( 'message' => 'Template not found' ) );
        }
        
        // Delete the physical file
        $filepath = $this->get_templates_dir() . $filename;
        if ( file_exists( $filepath ) ) {
            wp_delete_file( $filepath );
        }
        
        // Remove from database
        unset( $templates[ $agreement_type ] );
        update_option( 'swpdf_templates', $templates );
        
        wp_send_json_success( array( 'message' => 'Template deleted successfully' ) );
    }
    
    /**
     * AJAX: Duplicate PDF template
     */
    public function ajax_duplicate_template() {
        check_ajax_referer( 'swpdf_admin_nonce', 'nonce' );
        
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Unauthorized' ) );
        }
        
        $source_type = isset( $_POST['agreement_type'] ) ? sanitize_key( wp_unslash( $_POST['agreement_type'] ) ) : '';
        
        if ( empty( $source_type ) ) {
            wp_send_json_error( array( 'message' => 'Missing source template' ) );
        }
        
        $templates = get_option( 'swpdf_templates', array() );
        
        if ( ! isset( $templates[ $source_type ] ) ) {
            wp_send_json_error( array( 'message' => 'Source template not found' ) );
        }
        
        $source = $templates[ $source_type ];
        
        // Generate new unique type
        $new_type = $source_type . '-copy';
        $counter = 1;
        while ( isset( $templates[ $new_type ] ) ) {
            $new_type = $source_type . '-copy-' . $counter;
            $counter++;
        }
        
        // Copy the PDF file
        $source_file = $this->get_templates_dir() . $source['filename'];
        $new_filename = pathinfo( $source['filename'], PATHINFO_FILENAME ) . '-copy-' . time() . '.pdf';
        $new_file = $this->get_templates_dir() . $new_filename;
        
        if ( ! file_exists( $source_file ) ) {
            wp_send_json_error( array( 'message' => 'Source PDF file not found' ) );
        }
        
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_copy -- Duplicating PDF file within uploads directory
        copy( $source_file, $new_file );
        
        // Create new template entry
        $templates[ $new_type ] = array(
            'name' => $source['name'] . ' (Copy)',
            'filename' => $new_filename,
            'created' => current_time( 'mysql' ),
        );
        update_option( 'swpdf_templates', $templates );
        
        // Copy field labels
        $field_labels = get_option( 'swpdf_field_labels', array() );
        if ( isset( $field_labels[ $source_type ] ) ) {
            $field_labels[ $new_type ] = $field_labels[ $source_type ];
            update_option( 'swpdf_field_labels', $field_labels );
        }
        
        // Copy field required settings
        $field_required = get_option( 'swpdf_field_required', array() );
        if ( isset( $field_required[ $source_type ] ) ) {
            $field_required[ $new_type ] = $field_required[ $source_type ];
            update_option( 'swpdf_field_required', $field_required );
        }
        
        // Copy field mappings
        $field_mappings = get_option( 'swpdf_field_mappings', array() );
        if ( isset( $field_mappings[ $source_type ] ) ) {
            $field_mappings[ $new_type ] = $field_mappings[ $source_type ];
            update_option( 'swpdf_field_mappings', $field_mappings );
        }
        
        // Copy signature settings
        $signature_settings = get_option( 'swpdf_signature_settings', array() );
        if ( isset( $signature_settings[ $source_type ] ) ) {
            $signature_settings[ $new_type ] = $signature_settings[ $source_type ];
            update_option( 'swpdf_signature_settings', $signature_settings );
        }
        
        // Copy fields list
        $fields_lists = get_option( 'swpdf_fields_lists', array() );
        if ( isset( $fields_lists[ $source_type ] ) ) {
            $fields_lists[ $new_type ] = $fields_lists[ $source_type ];
            update_option( 'swpdf_fields_lists', $fields_lists );
        }

        // Copy date settings
        $date_settings = get_option( 'swpdf_date_settings', array() );
        if ( isset( $date_settings[ $source_type ] ) ) {
            $date_settings[ $new_type ] = $date_settings[ $source_type ];
            update_option( 'swpdf_date_settings', $date_settings );
        }

        // Copy field meta keys
        $meta_keys = get_option( 'swpdf_field_meta_keys', array() );
        if ( isset( $meta_keys[ $source_type ] ) ) {
            $meta_keys[ $new_type ] = $meta_keys[ $source_type ];
            update_option( 'swpdf_field_meta_keys', $meta_keys );
        }

        // Copy detected fields
        if ( isset( $source['fields'] ) ) {
            $templates[ $new_type ]['fields'] = $source['fields'];
            update_option( 'swpdf_templates', $templates );
        }
        
        wp_send_json_success( array( 
            'message' => 'Template duplicated successfully!',
            'new_type' => $new_type,
            'new_name' => $templates[ $new_type ]['name']
        ) );
    }
    
    /**
     * AJAX: Run license diagnostics
     */
    public function ajax_run_diagnostics() {
        check_ajax_referer( 'swpdf_license_nonce', 'nonce' );
        
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Unauthorized' ) );
        }
        
        $results = array();
        
        // Test outbound HTTP (using WordPress.org API for connectivity test)
        $response = wp_remote_get( 'https://api.wordpress.org/core/version-check/1.7/', array(
            'timeout' => 8,
            'sslverify' => true,
        ) );
        
        if ( is_wp_error( $response ) ) {
            $results['Outbound HTTP (SSL)'] = 'Failed: ' . $response->get_error_message();
        } else {
            $results['Outbound HTTP (SSL)'] = 'Success';
        }
        
        // Test without SSL verification
        $response_no_ssl = wp_remote_get( 'https://api.wordpress.org/core/version-check/1.7/', array(
            'timeout' => 8,
            'sslverify' => false,
        ) );
        
        if ( is_wp_error( $response_no_ssl ) ) {
            $results['Outbound HTTP (No SSL)'] = 'Failed: ' . $response_no_ssl->get_error_message();
        } else {
            $results['Outbound HTTP (No SSL)'] = 'Success';
        }
        
        // Check uploads writable
        $upload_dir = wp_upload_dir();
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable -- Diagnostic status check only
        $results['Uploads Directory'] = wp_is_writable( $upload_dir['basedir'] ) ? 'Writable' : 'Not Writable';
        
        // Check plugin upload dir
        $swpdf_upload_dir = $upload_dir['basedir'] . '/swpdf-signed-docs/';
        if ( file_exists( $swpdf_upload_dir ) ) {
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_is_writable -- Diagnostic status check only
            $results['Plugin Upload Dir'] = wp_is_writable( $swpdf_upload_dir ) ? 'Writable' : 'Not Writable';
        } else {
            $results['Plugin Upload Dir'] = 'Does not exist';
        }
        
        // cURL info
        $results['cURL Enabled'] = function_exists( 'curl_version' ) ? 'Yes' : 'No';
        
        // OpenSSL
        $results['OpenSSL Enabled'] = extension_loaded( 'openssl' ) ? 'Yes' : 'No';
        
        // Memory limit
        $results['PHP Memory Limit'] = ini_get( 'memory_limit' );
        
        // Max execution time
        $results['Max Execution Time'] = ini_get( 'max_execution_time' ) . 's';
        
        wp_send_json_success( $results );
    }
    
    /**
     * AJAX: Get PDF template
     */
    public function ajax_get_pdf_template() {
        // Always verify nonce — the front-end form passes it via swpdfSignature.nonce
        check_ajax_referer( 'swpdf_form_nonce', 'nonce' );
        
        $agreement_type = isset( $_POST['agreement_type'] ) ? sanitize_key( wp_unslash( $_POST['agreement_type'] ) ) : '';
        
        if ( empty( $agreement_type ) ) {
            wp_send_json_error( array( 'message' => 'Agreement type required' ) );
        }
        
        // Find template — check new option name first, then legacy
        $templates = get_option( 'swpdf_templates', array() );
        if ( ! isset( $templates[ $agreement_type ] ) ) {
            $legacy_templates = get_option( 'psf_templates', array() );
            if ( isset( $legacy_templates[ $agreement_type ] ) ) {
                $templates[ $agreement_type ] = $legacy_templates[ $agreement_type ];
            }
        }
        
        if ( empty( $templates ) ) {
            wp_send_json_error( array( 'message' => 'No templates found. Please upload a template first.' ) );
        }
        
        if ( ! isset( $templates[ $agreement_type ] ) ) {
            wp_send_json_error( array( 
                'message' => 'Template not found for the specified type.'
            ) );
        }
        
        $template = $templates[ $agreement_type ];
        $template['url'] = $this->get_templates_url() . $template['filename'];
        
        // Add custom field labels if available (check new then legacy)
        $field_labels = get_option( 'swpdf_field_labels', array() );
        if ( ! isset( $field_labels[ $agreement_type ] ) ) {
            $legacy = get_option( 'psf_field_labels', array() );
            if ( isset( $legacy[ $agreement_type ] ) ) {
                $field_labels[ $agreement_type ] = $legacy[ $agreement_type ];
            }
        }
        if ( isset( $field_labels[ $agreement_type ] ) ) {
            $template['field_labels'] = $field_labels[ $agreement_type ];
        }
        
        // Add required fields (check new then legacy)
        $field_required = get_option( 'swpdf_field_required', array() );
        if ( ! isset( $field_required[ $agreement_type ] ) ) {
            $legacy = get_option( 'psf_field_required', array() );
            if ( isset( $legacy[ $agreement_type ] ) ) {
                $field_required[ $agreement_type ] = $legacy[ $agreement_type ];
            }
        }
        if ( isset( $field_required[ $agreement_type ] ) ) {
            $template['field_required'] = $field_required[ $agreement_type ];
        }
        
        // Add saved fields list (check new then legacy)
        $fields_lists = get_option( 'swpdf_fields_lists', array() );
        if ( ! isset( $fields_lists[ $agreement_type ] ) ) {
            $legacy = get_option( 'psf_fields_lists', array() );
            if ( isset( $legacy[ $agreement_type ] ) ) {
                $fields_lists[ $agreement_type ] = $legacy[ $agreement_type ];
            }
        }
        if ( isset( $fields_lists[ $agreement_type ] ) ) {
            $template['fields_list'] = $fields_lists[ $agreement_type ];
        }
        
        // Add field mappings (check new then legacy)
        $field_mappings = get_option( 'swpdf_field_mappings', array() );
        if ( ! isset( $field_mappings[ $agreement_type ] ) ) {
            $legacy = get_option( 'psf_field_mappings', array() );
            if ( isset( $legacy[ $agreement_type ] ) ) {
                $field_mappings[ $agreement_type ] = $legacy[ $agreement_type ];
            }
        }
        if ( isset( $field_mappings[ $agreement_type ] ) ) {
            $template['field_mappings'] = $field_mappings[ $agreement_type ];
        }
        
        // Add signature position settings — check all option names per agreement_type
        $sig_found = null;
        foreach ( array( 'swpdf_signature_settings', 'PDF_Sign_Fill_settings', 'psf_signature_settings' ) as $opt ) {
            $sig_all = get_option( $opt, array() );
            if ( isset( $sig_all[ $agreement_type ] ) ) {
                $sig_found = $sig_all[ $agreement_type ];
                break;
            }
        }
        $template['signature_settings'] = $sig_found ? $sig_found : array( 'x' => 72, 'y' => 68, 'width' => 120, 'height' => 35, 'page' => 0 );
        
        // Add date position settings — check all option names per agreement_type
        $date_found = null;
        foreach ( array( 'swpdf_date_settings', 'PDF_Sign_Fill_date_settings', 'psf_date_settings' ) as $opt ) {
            $date_all = get_option( $opt, array() );
            if ( isset( $date_all[ $agreement_type ] ) ) {
                $date_found = $date_all[ $agreement_type ];
                break;
            }
        }
        $template['date_settings'] = $date_found ? $date_found : array( 'enabled' => false, 'x' => 350, 'y' => 68, 'fontSize' => 10, 'page' => 0 );
        
        wp_send_json_success( array( 'template' => $template ) );
    }
    
    /**
     * AJAX: Save custom field labels - stores in swpdf_templates as single source of truth
     */
    public function ajax_save_field_labels() {
        check_ajax_referer( 'swpdf_admin_nonce', 'nonce' );
        
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Permission denied' ) );
        }
        
        $agreement_type = isset( $_POST['agreement_type'] ) ? sanitize_key( wp_unslash( $_POST['agreement_type'] ) ) : '';
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- JSON string decoded and validated below
        $fields_list = isset( $_POST['fields_list'] ) ? wp_unslash( $_POST['fields_list'] ) : '';
        
        if ( empty( $agreement_type ) ) {
            wp_send_json_error( array( 'message' => 'Agreement type required' ) );
        }
        
        // Get existing templates
        $templates = get_option( 'swpdf_templates', array() );
        
        // Get filename from POST (for new uploads)
        $filename = isset( $_POST['filename'] ) ? sanitize_file_name( wp_unslash( $_POST['filename'] ) ) : '';
        $template_name = isset( $_POST['template_name'] ) ? sanitize_text_field( wp_unslash( $_POST['template_name'] ) ) : '';
        
        if ( ! isset( $templates[ $agreement_type ] ) ) {
            // Create new template entry if needed
            $templates[ $agreement_type ] = array(
                'name' => ! empty( $template_name ) ? $template_name : ucwords( str_replace( array( '-', '_' ), ' ', $agreement_type ) ),
                'type' => $agreement_type,
                'fields' => array(),
                'created' => current_time( 'mysql' ),
                'filename' => $filename, // Include filename for new uploads
            );
        }
        
        // Process fields_list - this is now the single source of truth
        $meta_key_errors = array();
        $duplicate_keys = array();
        
        if ( ! empty( $fields_list ) ) {
            $fields_list_array = json_decode( $fields_list, true );
            
            if ( is_array( $fields_list_array ) ) {
                // Track meta_keys for collision detection
                $used_meta_keys = array();
                
                // Validate and sanitize each field
                foreach ( $fields_list_array as &$field ) {
                    // Ensure required properties exist
                    $field['name'] = isset( $field['name'] ) ? sanitize_text_field( $field['name'] ) : '';
                    $field['type'] = isset( $field['type'] ) ? sanitize_text_field( $field['type'] ) : 'text';
                    $field['page'] = isset( $field['page'] ) ? intval( $field['page'] ) : 1;
                    $field['label'] = isset( $field['label'] ) ? sanitize_text_field( $field['label'] ) : '';
                    $field['required'] = isset( $field['required'] ) ? (bool) $field['required'] : false;
                    $field['maps_to'] = isset( $field['maps_to'] ) ? sanitize_key( $field['maps_to'] ) : 'none';
                    
                    // Process meta_key only if maps_to === 'meta'
                    if ( $field['maps_to'] === 'meta' && ! empty( $field['meta_key'] ) ) {
                        $raw_key = $field['meta_key'];
                        $sanitized_key = preg_replace( '/[^a-z0-9_]/', '', strtolower( $raw_key ) );
                        
                        // Validate pattern: 2-40 chars, only a-z 0-9 _
                        if ( ! preg_match( '/^[a-z0-9_]{2,40}$/', $sanitized_key ) ) {
                            $meta_key_errors[] = sprintf( 
                                'Invalid meta key for "%s": must be 2-40 lowercase alphanumeric chars or underscores', 
                                $field['name'] 
                            );
                            // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Not a DB query; array key on custom data structure
                            $field['meta_key'] = '';
                            $field['maps_to'] = 'none'; // Reset to none if invalid
                        } else {
                            // Check for duplicates within this template
                            if ( in_array( $sanitized_key, $used_meta_keys, true ) ) {
                                $duplicate_keys[] = $sanitized_key;
                            } else {
                                $used_meta_keys[] = $sanitized_key;
                                // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Not a DB query; array key on custom data structure
                                $field['meta_key'] = $sanitized_key;
                            }
                        }
                    } else {
                        // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- Not a DB query; array key on custom data structure
                        $field['meta_key'] = '';
                    }
                }
                unset( $field );
                
                // Block save if duplicate meta_keys found
                if ( ! empty( $duplicate_keys ) ) {
                    wp_send_json_error( array( 
                        'message' => 'Duplicate meta key(s) found: ' . implode( ', ', array_unique( $duplicate_keys ) ) . ' — please make each meta key unique within this template.',
                        'duplicate_keys' => array_unique( $duplicate_keys )
                    ) );
                    return;
                }
                
                // Check for duplicate core column mappings
                $core_columns = array( 'customer_name', 'customer_email', 'customer_phone', 'stock_number' );
                $core_column_labels = array(
                    'customer_name' => 'Name',
                    'customer_email' => 'Email', 
                    'customer_phone' => 'Phone',
                    'stock_number' => 'Stock #'
                );
                $column_field_map = array(); // Track which fields map to each column
                $duplicate_columns = array();
                $duplicate_fields = array();
                
                foreach ( $fields_list_array as $field ) {
                    if ( isset( $field['maps_to'] ) && in_array( $field['maps_to'], $core_columns, true ) ) {
                        $col = $field['maps_to'];
                        if ( ! isset( $column_field_map[ $col ] ) ) {
                            $column_field_map[ $col ] = array();
                        }
                        $column_field_map[ $col ][] = $field['name'];
                    }
                }
                
                // Find columns with duplicates
                foreach ( $column_field_map as $col => $field_names ) {
                    if ( count( $field_names ) > 1 ) {
                        $duplicate_columns[] = $core_column_labels[ $col ];
                        $duplicate_fields[ $col ] = $field_names;
                    }
                }
                
                if ( ! empty( $duplicate_columns ) ) {
                    wp_send_json_error( array(
                        'message' => 'Duplicate column mapping detected. Each core column can only have one field mapped to it.',
                        'duplicate_columns' => array_unique( $duplicate_columns ),
                        'duplicate_fields' => $duplicate_fields
                    ) );
                    return;
                }
                
                // Store fields in swpdf_templates (single source of truth)
                $templates[ $agreement_type ]['fields'] = $fields_list_array;
                update_option( 'swpdf_templates', $templates );
                
                // DEPRECATED: Also update legacy options for backward compatibility
                // These can be removed in a future version
                $this->sync_legacy_field_options( $agreement_type, $fields_list_array );
            }
        }
        
        // Save signature position settings if provided
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- JSON string decoded and validated with intval() below
        $signature_settings = isset( $_POST['signature_settings'] ) ? wp_unslash( $_POST['signature_settings'] ) : '';
        if ( ! empty( $signature_settings ) ) {
            $signature_settings_array = json_decode( $signature_settings, true );
            if ( is_array( $signature_settings_array ) ) {
                $signature_settings_array = array(
                    'x' => intval( $signature_settings_array['x'] ?? 72 ),
                    'y' => intval( $signature_settings_array['y'] ?? 68 ),
                    'width' => intval( $signature_settings_array['width'] ?? 120 ),
                    'height' => intval( $signature_settings_array['height'] ?? 35 ),
                    'page' => intval( $signature_settings_array['page'] ?? 0 )
                );
                $all_signature_settings = get_option( 'swpdf_signature_settings', array() );
                $all_signature_settings[ $agreement_type ] = $signature_settings_array;
                update_option( 'swpdf_signature_settings', $all_signature_settings );
            }
        }
        
        // Save date position settings if provided
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- JSON string decoded and validated with intval() below
        $date_settings = isset( $_POST['date_settings'] ) ? wp_unslash( $_POST['date_settings'] ) : '';
        if ( ! empty( $date_settings ) ) {
            $date_settings_array = json_decode( $date_settings, true );
            if ( is_array( $date_settings_array ) ) {
                $date_settings_array = array(
                    'enabled' => isset( $date_settings_array['enabled'] ) ? (bool) $date_settings_array['enabled'] : false,
                    'x' => intval( $date_settings_array['x'] ?? 350 ),
                    'y' => intval( $date_settings_array['y'] ?? 68 ),
                    'fontSize' => intval( $date_settings_array['fontSize'] ?? 10 ),
                    'page' => intval( $date_settings_array['page'] ?? 0 )
                );
                $all_date_settings = get_option( 'swpdf_date_settings', array() );
                $all_date_settings[ $agreement_type ] = $date_settings_array;
                update_option( 'swpdf_date_settings', $all_date_settings );
            }
        }
        
        // Register template if this is a new upload
        $template_name = isset( $_POST['template_name'] ) ? sanitize_text_field( wp_unslash( $_POST['template_name'] ) ) : '';
        $filename = isset( $_POST['filename'] ) ? sanitize_file_name( wp_unslash( $_POST['filename'] ) ) : '';
        
        if ( ! empty( $template_name ) ) {
            $templates[ $agreement_type ]['name'] = $template_name;
        }
        if ( ! empty( $filename ) ) {
            $templates[ $agreement_type ]['filename'] = $filename;
        }
        if ( ! empty( $template_name ) || ! empty( $filename ) ) {
            update_option( 'swpdf_templates', $templates );
        }
        
        $response = array( 'message' => 'Settings saved successfully' );
        if ( ! empty( $meta_key_errors ) ) {
            $response['warnings'] = $meta_key_errors;
        }
        
        wp_send_json_success( $response );
    }
    
    /**
     * Sync legacy field options for backward compatibility (DEPRECATED)
     */
    private function sync_legacy_field_options( $agreement_type, $fields_list ) {
        $labels = array();
        $required = array();
        $mappings = array();
        $meta_keys = array();
        
        foreach ( $fields_list as $field ) {
            $name = $field['name'] ?? '';
            if ( empty( $name ) ) continue;
            
            if ( ! empty( $field['label'] ) ) {
                $labels[ $name ] = $field['label'];
            }
            $required[ $name ] = $field['required'] ?? false;
            if ( ! empty( $field['maps_to'] ) ) {
                $mappings[ $name ] = $field['maps_to'];
            }
            if ( ! empty( $field['meta_key'] ) ) {
                $meta_keys[ $name ] = $field['meta_key'];
            }
        }
        
        // Update legacy options
        $all_labels = get_option( 'swpdf_field_labels', array() );
        $all_labels[ $agreement_type ] = $labels;
        update_option( 'swpdf_field_labels', $all_labels );
        
        $all_required = get_option( 'swpdf_field_required', array() );
        $all_required[ $agreement_type ] = $required;
        update_option( 'swpdf_field_required', $all_required );
        
        $all_mappings = get_option( 'swpdf_field_mappings', array() );
        $all_mappings[ $agreement_type ] = $mappings;
        update_option( 'swpdf_field_mappings', $all_mappings );
        
        $all_fields_lists = get_option( 'swpdf_fields_lists', array() );
        $all_fields_lists[ $agreement_type ] = $fields_list;
        update_option( 'swpdf_fields_lists', $all_fields_lists );
        
        if ( ! empty( $meta_keys ) ) {
            $all_meta_keys = get_option( 'swpdf_field_meta_keys', array() );
            $all_meta_keys[ $agreement_type ] = $meta_keys;
            update_option( 'swpdf_field_meta_keys', $all_meta_keys );
        }
    }
    
    /**
     * AJAX: Get template for editing labels
     */
    public function ajax_get_template_for_edit() {
        check_ajax_referer( 'swpdf_admin_nonce', 'nonce' );
        
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Permission denied' ) );
        }
        
        $agreement_type = isset( $_POST['agreement_type'] ) ? sanitize_key( wp_unslash( $_POST['agreement_type'] ) ) : '';
        
        if ( empty( $agreement_type ) ) {
            wp_send_json_error( array( 'message' => 'Agreement type required' ) );
        }
        
        // PRIMARY: Get fields from swpdf_templates (single source of truth)
        $templates = get_option( 'swpdf_templates', array() );
        $template = isset( $templates[ $agreement_type ] ) ? $templates[ $agreement_type ] : array();
        $fields_list = isset( $template['fields'] ) ? $template['fields'] : array();
        
        // Build labels, required, mappings, meta_keys from fields_list
        $current_labels = array();
        $current_required = array();
        $current_mappings = array();
        $current_meta_keys = array();
        
        foreach ( $fields_list as $field ) {
            $name = $field['name'] ?? '';
            if ( empty( $name ) ) continue;
            
            if ( ! empty( $field['label'] ) ) {
                $current_labels[ $name ] = $field['label'];
            }
            $current_required[ $name ] = $field['required'] ?? false;
            if ( ! empty( $field['maps_to'] ) ) {
                $current_mappings[ $name ] = $field['maps_to'];
            }
            if ( ! empty( $field['meta_key'] ) ) {
                $current_meta_keys[ $name ] = $field['meta_key'];
            }
        }
        
        // FALLBACK: If no fields in template, read from legacy options
        if ( empty( $fields_list ) ) {
            $field_labels = get_option( 'swpdf_field_labels', array() );
            $current_labels = isset( $field_labels[ $agreement_type ] ) ? $field_labels[ $agreement_type ] : array();
            
            $field_required = get_option( 'swpdf_field_required', array() );
            $current_required = isset( $field_required[ $agreement_type ] ) ? $field_required[ $agreement_type ] : array();
            
            $fields_lists = get_option( 'swpdf_fields_lists', array() );
            $fields_list = isset( $fields_lists[ $agreement_type ] ) ? $fields_lists[ $agreement_type ] : array();
            
            $field_mappings = get_option( 'swpdf_field_mappings', array() );
            $current_mappings = isset( $field_mappings[ $agreement_type ] ) ? $field_mappings[ $agreement_type ] : array();
            
            $field_meta_keys = get_option( 'swpdf_field_meta_keys', array() );
            $current_meta_keys = isset( $field_meta_keys[ $agreement_type ] ) ? $field_meta_keys[ $agreement_type ] : array();
        }
        
        // Get signature settings - per agreement_type (check all legacy option names)
        $current_signature_settings = null;
        foreach ( array( 'swpdf_signature_settings', 'PDF_Sign_Fill_settings', 'psf_signature_settings' ) as $opt ) {
            $sig_all = get_option( $opt, array() );
            if ( isset( $sig_all[ $agreement_type ] ) ) {
                $current_signature_settings = $sig_all[ $agreement_type ];
                break;
            }
        }
        if ( ! $current_signature_settings ) {
            $current_signature_settings = array( 'x' => 72, 'y' => 68, 'width' => 120, 'height' => 35, 'page' => 0 );
        }
        
        // Get date settings - per agreement_type (check all legacy option names)
        $current_date_settings = null;
        foreach ( array( 'swpdf_date_settings', 'PDF_Sign_Fill_date_settings', 'psf_date_settings' ) as $opt ) {
            $date_all = get_option( $opt, array() );
            if ( isset( $date_all[ $agreement_type ] ) ) {
                $current_date_settings = $date_all[ $agreement_type ];
                break;
            }
        }
        if ( ! $current_date_settings ) {
            $current_date_settings = array( 'enabled' => false, 'x' => 350, 'y' => 68, 'fontSize' => 10, 'page' => 0 );
        }
        
        wp_send_json_success( array( 
            'field_labels' => $current_labels,
            'field_required' => $current_required,
            'fields_list' => $fields_list,
            'field_mappings' => $current_mappings,
            'field_meta_keys' => $current_meta_keys,
            'signature_settings' => $current_signature_settings,
            'date_settings' => $current_date_settings
        ) );
    }
    
    /**
     * Export signed documents to CSV
     */
    public function ajax_export_csv() {
        check_ajax_referer( 'swpdf_export_csv', 'nonce' );
        
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( 'Unauthorized' );
        }
        
        global $wpdb;
        $table_name = $wpdb->prefix . 'swpdf_signed_docs';
        
        // Get filter parameters
        $date_from = isset( $_GET['date_from'] ) ? sanitize_text_field( wp_unslash( $_GET['date_from'] ) ) : '';
        $date_to = isset( $_GET['date_to'] ) ? sanitize_text_field( wp_unslash( $_GET['date_to'] ) ) : '';
        $agreement_type = isset( $_GET['agreement_type'] ) ? sanitize_text_field( wp_unslash( $_GET['agreement_type'] ) ) : '';
        
        // Get CSV export setting
        $settings = get_option( 'swpdf_settings', array() );
        $include_meta_columns = ! empty( $settings['csv_include_meta_columns'] );
        
        // Build query
        $where = array( '1=1' );
        $params = array();
        
        if ( $date_from ) {
            $where[] = 'signed_at >= %s';
            $params[] = $date_from . ' 00:00:00';
        }
        if ( $date_to ) {
            $where[] = 'signed_at <= %s';
            $params[] = $date_to . ' 23:59:59';
        }
        if ( $agreement_type ) {
            $where[] = 'agreement_type = %s';
            $params[] = $agreement_type;
        }
        
        $where_clause = implode( ' AND ', $where );
        
        if ( ! empty( $params ) ) {
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Safe: $table_name uses $wpdb->prefix, params are prepared
            $sql = $wpdb->prepare( "SELECT * FROM $table_name WHERE $where_clause ORDER BY signed_at DESC", $params );
        } else {
            // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Safe: $table_name uses $wpdb->prefix, no user input
            $sql = "SELECT * FROM $table_name WHERE $where_clause ORDER BY signed_at DESC";
        }
        
        // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- SQL prepared above
        $agreements = $wpdb->get_results( $sql );
        
        // Collect all unique metadata keys across all agreements (only if expanding columns)
        $all_meta_keys = array();
        if ( $include_meta_columns ) {
            foreach ( $agreements as $row ) {
                $form_data = json_decode( $row->form_data, true );
                if ( is_array( $form_data ) && isset( $form_data['metadata'] ) && is_array( $form_data['metadata'] ) ) {
                    foreach ( array_keys( $form_data['metadata'] ) as $key ) {
                        if ( ! in_array( $key, $all_meta_keys ) ) {
                            $all_meta_keys[] = $key;
                        }
                    }
                }
            }
            sort( $all_meta_keys );
            
            // Warn if too many columns (cap at 50)
            if ( count( $all_meta_keys ) > 50 ) {
                $all_meta_keys = array_slice( $all_meta_keys, 0, 50 );
            }
        }
        
        // Set headers for CSV download
        $filename = 'signed-agreements-' . gmdate( 'Y-m-d' ) . '.csv';
        header( 'Content-Type: text/csv; charset=utf-8' );
        header( 'Content-Disposition: attachment; filename=' . $filename );
        header( 'Pragma: no-cache' );
        header( 'Expires: 0' );
        
        // Open output stream
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fopen -- Required for php://output CSV stream
        $output = fopen( 'php://output', 'w' );
        
        // Add BOM for Excel compatibility
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fprintf -- Required for CSV output stream
        fprintf( $output, chr( 0xEF ) . chr( 0xBB ) . chr( 0xBF ) );
        
        // CSV headers - base columns
        $base_headers = array(
            'ID',
            'Customer Name',
            'Email',
            'Phone',
            'Agreement Type',
            'Stock Number',
            'IP Address',
            'Signed Date',
            'PDF File'
        );
        
        // Add metadata headers based on setting
        if ( $include_meta_columns ) {
            $meta_headers = array_map( function( $key ) {
                return 'meta_' . $key;
            }, $all_meta_keys );
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fputcsv -- Writing CSV to php://output stream
            fputcsv( $output, array_merge( $base_headers, $meta_headers ) );
        } else {
            // Single JSON column for metadata
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fputcsv -- Writing CSV to php://output stream
            fputcsv( $output, array_merge( $base_headers, array( 'meta_json' ) ) );
        }
        
        // CSV data rows
        foreach ( $agreements as $row ) {
            // Parse form_data to extract metadata
            $form_data = json_decode( $row->form_data, true );
            $metadata = array();
            
            // Handle both old format (flat) and new format {fields: {...}, metadata: {...}}
            if ( is_array( $form_data ) && isset( $form_data['metadata'] ) && is_array( $form_data['metadata'] ) ) {
                $metadata = $form_data['metadata'];
            }
            
            // Build base row data
            $row_data = array(
                $row->id,
                $row->customer_name,
                $row->customer_email,
                $row->customer_phone,
                $row->agreement_type,
                $row->stock_number ?? '',
                $row->ip_address ?? '',
                $row->signed_at,
                $row->file_path
            );
            
            // Add metadata based on setting
            if ( $include_meta_columns ) {
                // Add individual metadata columns
                foreach ( $all_meta_keys as $meta_key ) {
                    $row_data[] = isset( $metadata[ $meta_key ] ) ? $metadata[ $meta_key ] : '';
                }
            } else {
                // Add single JSON column
                $row_data[] = ! empty( $metadata ) ? wp_json_encode( $metadata ) : '';
            }
            
            // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fputcsv -- Writing CSV to php://output stream
            fputcsv( $output, $row_data );
        }
        
        // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_fclose -- Required for CSV output stream
        fclose( $output );
        exit;
    }
    
    /**
     * AJAX: Get agreement details for modal (secure endpoint)
     */
    public function ajax_get_agreement_details() {
        check_ajax_referer( 'swpdf_admin_nonce', 'nonce' );
        
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Permission denied' ) );
        }
        
        $agreement_id = isset( $_POST['agreement_id'] ) ? intval( wp_unslash( $_POST['agreement_id'] ) ) : 0;
        
        if ( empty( $agreement_id ) ) {
            wp_send_json_error( array( 'message' => 'Agreement ID required' ) );
        }
        
        global $wpdb;
        $table_name = $wpdb->prefix . 'swpdf_signed_docs';
        
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Safe: $table_name uses $wpdb->prefix
        $agreement = $wpdb->get_row( $wpdb->prepare(
            "SELECT * FROM $table_name WHERE id = %d",
            $agreement_id
        ) );
        
        if ( ! $agreement ) {
            wp_send_json_error( array( 'message' => 'Agreement not found' ) );
        }
        
        // Parse form_data
        $form_data = json_decode( $agreement->form_data, true );
        $fields = array();
        $metadata = array();
        
        if ( is_array( $form_data ) ) {
            if ( isset( $form_data['fields'] ) ) {
                $fields = $form_data['fields'];
                $metadata = isset( $form_data['metadata'] ) ? $form_data['metadata'] : array();
            } else {
                // Old format - all fields flat
                $fields = $form_data;
            }
        }
        
        // Escape all values for security
        $safe_fields = array();
        foreach ( $fields as $key => $value ) {
            $safe_fields[ esc_html( $key ) ] = esc_html( $value );
        }
        
        $safe_metadata = array();
        foreach ( $metadata as $key => $value ) {
            $safe_metadata[ esc_html( $key ) ] = esc_html( $value );
        }
        
        wp_send_json_success( array(
            'fields' => $safe_fields,
            'metadata' => $safe_metadata,
            'field_count' => count( $safe_fields ),
            'metadata_count' => count( $safe_metadata )
        ) );
    }
    
    /**
     * AJAX: Delete a signed agreement
     */
    public function ajax_delete_agreement() {
        check_ajax_referer( 'swpdf_admin_nonce', 'nonce' );

        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( array( 'message' => 'Permission denied' ) );
        }

        $agreement_id = isset( $_POST['agreement_id'] ) ? intval( wp_unslash( $_POST['agreement_id'] ) ) : 0;
        if ( empty( $agreement_id ) ) {
            wp_send_json_error( array( 'message' => 'Agreement ID required' ) );
        }

        global $wpdb;
        $table_name = $wpdb->prefix . 'swpdf_signed_docs';

        // Get the record first so we can delete the PDF file
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Safe: $table_name uses $wpdb->prefix
        $agreement = $wpdb->get_row( $wpdb->prepare( "SELECT file_path FROM $table_name WHERE id = %d", $agreement_id ) );

        if ( ! $agreement ) {
            wp_send_json_error( array( 'message' => 'Agreement not found' ) );
        }

        // Delete the PDF file if it exists
        $full_path = $this->get_uploads_dir() . $agreement->file_path;
        if ( ! empty( $agreement->file_path ) && file_exists( $full_path ) ) {
            wp_delete_file( $full_path );
        }

        // Delete the database row
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Safe deletion by ID
        $deleted = $wpdb->delete( $table_name, array( 'id' => $agreement_id ), array( '%d' ) );

        if ( false === $deleted ) {
            wp_send_json_error( array( 'message' => 'Failed to delete agreement' ) );
        }

        wp_send_json_success( array( 'message' => 'Agreement deleted' ) );
    }

    /**
     * Create database table on activation
     */
    public static function activate() {
        global $wpdb;
        $table_name = $wpdb->prefix . 'swpdf_signed_docs';
        $charset_collate = $wpdb->get_charset_collate();
        
        $sql = "CREATE TABLE IF NOT EXISTS $table_name (
            id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
            customer_name varchar(255) NOT NULL,
            customer_email varchar(255) NOT NULL,
            customer_phone varchar(50) DEFAULT NULL,
            agreement_type varchar(100) NOT NULL,
            stock_number varchar(100) DEFAULT NULL,
            form_data longtext NOT NULL,
            file_path varchar(500) NOT NULL,
            ip_address varchar(100) DEFAULT NULL,
            user_agent text DEFAULT NULL,
            signed_at datetime NOT NULL,
            PRIMARY KEY  (id),
            KEY customer_email (customer_email),
            KEY signed_at (signed_at)
        ) $charset_collate;";
        
        require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
        dbDelta( $sql );
        
        // Add stock_number column if it doesn't exist (for existing installations)
        // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Safe: checking INFORMATION_SCHEMA for column
        $row = $wpdb->get_results( $wpdb->prepare( "SELECT COLUMN_NAME FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA = %s AND TABLE_NAME = %s AND COLUMN_NAME = 'stock_number'", DB_NAME, $table_name ) );
        if ( empty( $row ) ) {
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Safe: $table_name uses $wpdb->prefix
            $wpdb->query( "ALTER TABLE $table_name ADD stock_number varchar(100) DEFAULT NULL AFTER agreement_type" );
        }
    }
}

// Initialize plugin
function swpdf_init() {
    return SWPDF_Sign_Fill::get_instance();
}
add_action( 'plugins_loaded', 'swpdf_init' );

// Activation hook
register_activation_hook( __FILE__, array( 'SWPDF_Sign_Fill', 'activate' ) );
