<?php
/**
 * Property Setup Wizard 
 *
 * Exact design implementation with images and animations
 *
 * @package     Havenlytics
 * @subpackage  Admin
 * @since       2.0.0
 */

namespace HvnlyNab\Admin;

use HvnlyNab\Admin\Data\TabData;
use HvnlyNab\Admin\Data\DemoData;

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

/**
 * Class PropertyImportWizard
 */
class PropertyImportWizard {

    /**
     * Post type slug
     *
     * @var string
     */
    private $post_type = 'hvnly_property';

    /**
     * Option name for tracking import
     *
     * @var string
     */
    private $import_option = 'hvnly_demo_properties_imported';

    /**
     * Option name for import count
     *
     * @var string
     */
    private $count_option = 'hvnly_demo_properties_count';

    /**
     * Maximum file size for downloads (5MB)
     *
     * @var int
     */
    private $max_file_size = 5242880;

    /**
     * Allowed image mime types
     *
     * @var array
     */
    private $allowed_mime_types = [
        'image/jpeg',
        'image/jpg',
        'image/png',
        'image/gif',
        'image/webp',
    ];

    /**
     * Demo data instance
     *
     * @var DemoData
     */
    private $demo_data;

    /**
     * Allowed image domains for download
     *
     * @var array
     */
    private $allowed_image_domains = [
        'images.pexels.com',
        'img.youtube.com',
        'demo.havenlytics.com',
        'localhost',
        '127.0.0.1',
    ];

    /**
     * Debug mode flag - DISABLED FOR PRODUCTION
     *
     * @var bool
     */
    private $debug_mode = false;

    /**
     * Import running flag - prevents recursive processing
     *
     * @var bool
     */
    private $import_running = false;

    /**
     * Original cache invalidation state
     *
     * @var bool
     */
    private $original_cache_state = false;

    /**
     * Original term counting state
     *
     * @var bool
     */
    private $original_term_state = false;

    /**
     * Original comment counting state
     *
     * @var bool
     */
    private $original_comment_state = false;

    /**
     * Active theme name
     *
     * @var string
     */
    private $active_theme = '';

    /**
     * Heavy themes list that need special handling
     *
     * @var array
     */
    private $heavy_themes = [
        'Porto',
        'Divi',
        'Avada',
        'Extra',
        'Jupiter',
        'The7',
        'Enfold',
        'Salient',
        'Bridge',
        'X Theme',
    ];

    /**
     * Property builder storage keys
     *
     * @var array
     */
    private $property_builder_keys = [
        'hvnly_property_builder.sections',
        'hvnly_pb_dnd_sections',
        'hvnly_property_builder_sections',
        'hvnly_property_builder_tabs',
    ];

    /**
     * Card builder storage keys
     *
     * @var array
     */
    private $card_builder_keys = [
        'hvnly_property_card.sections',
        'hvnly_pb_card_builder_sections',
        'hvnly_property_card_layout',
        'hvnly_card_builder_config',
    ];

    /**
     * Constructor
     */
    public function __construct() {
        // Initialize demo data
        $this->demo_data = new DemoData();

        // Debug mode disabled for production
        $this->debug_mode = false;

        // Get active theme
        $this->active_theme = wp_get_theme()->get( 'Name' );

        add_action( 'admin_menu', [ $this, 'add_import_submenu' ], 20 );
        add_action( 'wp_ajax_hvnly_import_properties', [ $this, 'ajax_import_properties' ] );
        add_action( 'wp_ajax_hvnly_cancel_import', [ $this, 'ajax_cancel_import' ] );
        add_action( 'wp_ajax_hvnly_dismiss_video_tutorial', [ $this, 'ajax_dismiss_video_tutorial' ] );
        add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
        
        // ========== NEW: Suppress all admin notices on import wizard page ==========
        add_action( 'admin_init', [ $this, 'suppress_admin_notices' ] );
        add_action( 'admin_head', [ $this, 'add_notice_suppression_css' ] );
    }

    /**
     * Register hooks
     *
     * @return void
     */
    public function register(): void {
        // Hooks are already registered in constructor
    }

    /**
     * Add import submenu - Only show when no properties exist
     *
     * @return void
     */
    public function add_import_submenu() {
        $property_count  = wp_count_posts( $this->post_type );
        $published_count = isset( $property_count->publish ) ? absint( $property_count->publish ) : 0;

        if ( $published_count > 0 ) {
            return;
        }

        add_submenu_page(
            'edit.php?post_type=' . $this->post_type,
            esc_html__( 'Property Setup Wizard', 'havenlytics' ),
            esc_html__( 'Setup Wizard', 'havenlytics' ),
            'manage_options',
            'hvnly-property-import',
            [ $this, 'render_wizard_page' ]
        );
    }

    /**
     * Render wizard page
     *
     * @return void
     */
    public function render_wizard_page() {
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_die( esc_html__( 'You do not have sufficient permissions.', 'havenlytics' ) );
        }

        $hvnly_imported     = get_option( 'hvnly_demo_properties_imported', false );
        $hvnly_import_count = absint( get_option( 'hvnly_demo_properties_count', 0 ) );

        include __DIR__ . '/Importer/property-import-wizard.php';
    }

    /**
     * Suppress all admin notices on the import wizard page
     * This removes notices from WordPress, plugins, and themes
     *
     * @return void
     */
    public function suppress_admin_notices() {
        // Only run on our specific import wizard page
        if ( ! $this->is_import_wizard_page() ) {
            return;
        }

        // Remove all admin notices actions
        remove_all_actions( 'admin_notices' );
        remove_all_actions( 'all_admin_notices' );
        remove_all_actions( 'network_admin_notices' );
        remove_all_actions( 'user_admin_notices' );
        
        // Also remove any WooCommerce-specific notices if WooCommerce is active
        remove_all_actions( 'woocommerce_admin_notices' );
        remove_all_actions( 'woocommerce_before_settings_errors' );
        
        // Remove Elementor notices
        remove_all_actions( 'elementor/admin/after_create_settings/' );
        
        // Remove Yoast SEO notices
        remove_all_actions( 'admin_print_scripts' );
        
        // Add a custom empty action to prevent any default notices
        add_action( 'admin_notices', [ $this, 'empty_notice_handler' ], PHP_INT_MAX );
        add_action( 'all_admin_notices', [ $this, 'empty_notice_handler' ], PHP_INT_MAX );
    }

    /**
     * Empty notice handler - does nothing but prevents default notices
     *
     * @return void
     */
    public function empty_notice_handler() {
        // This intentionally does nothing to override any notices
    }

    /**
     * Add CSS to hide any remaining notices that might have been added via other hooks
     *
     * @return void
     */
    public function add_notice_suppression_css() {
        if ( ! $this->is_import_wizard_page() ) {
            return;
        }
        ?>
<style type="text/css">
/* Hide all admin notices on import wizard page */
.notice,
.notice-warning,
.notice-error,
.notice-success,
.notice-info,
.updated,
.update-nag,
.error,
.is-dismissible,
.wp-header-end,
#wpbody-content>.notice,
#wpbody-content>.updated,
#wpbody-content>.error,
#wpbody-content>.update-nag,
div.notice,
div.updated,
div.error,
div.update-nag,
.settings-error,
.woocommerce-message,
.woocommerce-error,
.woocommerce-info,
.elementor-message,
.yoast-notice {
    display: none !important;
    visibility: hidden !important;
    height: 0 !important;
    min-height: 0 !important;
    margin: 0 !important;
    padding: 0 !important;
    border: none !important;
    opacity: 0 !important;
}

/* Hide any wrapper that might contain notices */
.notice-wrapper,
.wp-notice-wrapper {
    display: none !important;
}

/* Ensure no extra spacing remains */
#wpbody-content {
    padding-top: 0 !important;
}

/* Hide any admin notices container */
.wrap .notice,
.wrap .updated,
.wrap .error {
    display: none !important;
}

/* Suppress WordPress update nag */
.update-nag {
    display: none !important;
}
</style>
<?php
    }

    /**
     * Check if current page is the import wizard page
     *
     * @return bool
     */
    private function is_import_wizard_page(): bool {
        global $current_screen;
        
        // Check via screen ID
        if ( $current_screen && 'hvnly_property_page_hvnly-property-import' === $current_screen->id ) {
            return true;
        }
        
        // Also check via GET parameter (fallback)
        if ( isset( $_GET['page'] ) && 'hvnly-property-import' === $_GET['page'] && isset( $_GET['post_type'] ) && 'hvnly_property' === $_GET['post_type'] ) {
            return true;
        }
        
        return false;
    }

    /**
     * Enqueue assets
     *
     * @param string $hook Current admin page.
     * @return void
     */
    public function enqueue_assets( $hook ) {
        if ( 'hvnly_property_page_hvnly-property-import' !== $hook ) {
            return;
        }

        $version = defined( 'HVNLYNAB_VERSION' ) ? HVNLYNAB_VERSION : '2.0.0';

        wp_enqueue_style(
            'hvnly-import-wizard',
            HVNLYNAB_ASSETS_URL . '/admin/css/hvnly-import-wizard.css',
            [],
            $version
        );

        wp_enqueue_script(
            'hvnly-import-wizard',
            HVNLYNAB_ASSETS_URL . '/admin/js/hvnly-import-wizard.js',
            [ 'jquery' ],
            $version,
            true
        );

        // Add REST API URL and nonce for builder reset
        $rest_url = rest_url( 'hvnlynab/v1' );
        
        $localized_data = [
            'ajaxurl'          => admin_url( 'admin-ajax.php' ),
            'resturl'          => $rest_url,
            'nonce'            => wp_create_nonce( 'hvnly_import_nonce' ),
            'rest_nonce'       => wp_create_nonce( 'wp_rest' ),
            'csrf_token'       => wp_create_nonce( 'hvnly_import_csrf' ),
            'imported'         => get_option( $this->import_option, false ),
            'importCount'      => absint( get_option( $this->count_option, 0 ) ),
            'totalProperties'  => absint( wp_count_posts( $this->post_type )->publish ?? 0 ),
            'maxImportLimit'   => 200,
            'batchSize'        => 5,
            'debug'            => false,
            'activeTheme'      => $this->active_theme,
            'isHeavyTheme'     => $this->is_heavy_theme(),
            'strings'          => [
                /* translators: Confirmation message before starting import */
                'confirmImport'      => esc_html__( 'Are you sure you want to import demo properties?', 'havenlytics' ),
                /* translators: Message shown during import process */
                'importing'          => esc_html__( 'Importing properties...', 'havenlytics' ),
                /* translators: Message shown when import completes */
                'complete'           => esc_html__( 'Import complete!', 'havenlytics' ),
                /* translators: Generic error message */
                'error'              => esc_html__( 'An error occurred during import.', 'havenlytics' ),
                /* translators: Label for error details section */
                'error_details'      => esc_html__( 'Error details:', 'havenlytics' ),
                /* translators: Retry button text */
                'retry'              => esc_html__( 'Retry', 'havenlytics' ),
                /* translators: Server error message with auto-retry */
                'server_error'       => esc_html__( 'Server error (500). The import will retry automatically.', 'havenlytics' ),
                /* translators: Message when heavy theme is detected */
                'heavy_theme_detected' => esc_html__( 'Heavy theme detected. Applying compatibility mode.', 'havenlytics' ),
                /* translators: Contact support message */
                'contact_support'    => esc_html__( 'If the problem persists, please contact support.', 'havenlytics' ),
                /* translators: Link text to view imported properties */
                'viewProperties'     => esc_html__( 'View Properties', 'havenlytics' ),
                /* translators: Confirmation for cancelling import */
                'cancelConfirm'      => esc_html__( 'Are you sure you want to cancel the import? Already imported properties will be saved.', 'havenlytics' ),
                /* translators: Message shown while cancelling */
                'cancelling'         => esc_html__( 'Cancelling...', 'havenlytics' ),
                /* translators: Message when import is paused */
                'paused'             => esc_html__( 'Import paused. Click Resume to continue.', 'havenlytics' ),
                /* translators: Resume button text */
                'resume'             => esc_html__( 'Resume Import', 'havenlytics' ),
                /* translators: Pause button text */
                'pause'              => esc_html__( 'Pause Import', 'havenlytics' ),
                /* translators: Cancel button text */
                'cancel'             => esc_html__( 'Cancel Import', 'havenlytics' ),
                /* translators: Builders reset message */
                'buildersReset'      => esc_html__( 'Property Builders Reset', 'havenlytics' ),
                /* translators: Reset success message */
                'resetSuccess'       => esc_html__( 'Property builder configurations have been reset to default.', 'havenlytics' ),
                /* translators: Resetting builders message */
                'resettingBuilders'  => esc_html__( 'Resetting property builders...', 'havenlytics' ),
                /* translators: Builders reset success message */
                'buildersResetSuccess' => esc_html__( 'Property builders reset successfully!', 'havenlytics' ),
            ],
        ];

        wp_localize_script( 'hvnly-import-wizard', 'hvnlyImportWizard', $localized_data );
    }

    /**
     * Check if current theme is a heavy theme that needs special handling
     *
     * @return bool
     */
    private function is_heavy_theme(): bool {
        foreach ( $this->heavy_themes as $theme ) {
            if ( stripos( $this->active_theme, $theme ) !== false ) {
                return true;
            }
        }
        return false;
    }
    
    /**
     * AJAX handler for dismissing video tutorial
     *
     * @return void
     */
    public function ajax_dismiss_video_tutorial() {
        try {
            // Security checks
            if ( ! check_ajax_referer( 'hvnly_import_nonce', 'nonce', false ) ) {
                wp_send_json_error( esc_html__( 'Security check failed.', 'havenlytics' ) );
                return;
            }

            if ( ! isset( $_POST['csrf_token'] ) ) {
                wp_send_json_error( esc_html__( 'CSRF token missing.', 'havenlytics' ) );
                return;
            }

            $csrf_token = sanitize_text_field( wp_unslash( $_POST['csrf_token'] ) );
            if ( ! wp_verify_nonce( $csrf_token, 'hvnly_import_csrf' ) ) {
                wp_send_json_error( esc_html__( 'CSRF validation failed.', 'havenlytics' ) );
                return;
            }

            if ( ! current_user_can( 'manage_options' ) ) {
                wp_send_json_error( esc_html__( 'Insufficient permissions.', 'havenlytics' ) );
                return;
            }

            // Save user meta to indicate video tutorial has been dismissed
            update_user_meta( get_current_user_id(), 'hvnly_video_tutorial_dismissed', true );

            wp_send_json_success( esc_html__( 'Video tutorial dismissed.', 'havenlytics' ) );

        } catch ( \Exception $e ) {
            wp_send_json_error( $e->getMessage() );
        }
    }
    
    /**
     * Reset Add Property Form configuration (Property Builder)
     *
     * @return bool True if reset was successful, false otherwise
     */
    private function reset_add_property_form(): bool {
        $success = true;
        
        // Delete all property builder storage keys
        foreach ( $this->property_builder_keys as $key ) {
            if ( get_option( $key ) !== false ) {
                $deleted = delete_option( $key );
                if ( ! $deleted ) {
                    $success = false;
                    $this->log_error( 'Failed to delete option: ' . $key );
                }
            }
        }
        
        // Clear property builder transients
        $this->clear_builder_transients( 'pb_' );
        $this->clear_builder_transients( 'property_builder_' );
        
        // Clear cache via engine if available
        if ( function_exists( 'HVN' ) && method_exists( HVNLY_NAB(), 'engine' ) ) {
            HVNLY_NAB()->engine()->clear_transients_by_pattern( 'pb_' );
            HVNLY_NAB()->engine()->clear_transients_by_pattern( 'property_builder_' );
        }
        
        return $success;
    }

    /**
     * Reset Property Card Builder configuration
     *
     * @return bool True if reset was successful, false otherwise
     */
    private function reset_property_card_builder(): bool {
        $success = true;
        
        // Delete all card builder storage keys
        foreach ( $this->card_builder_keys as $key ) {
            if ( get_option( $key ) !== false ) {
                $deleted = delete_option( $key );
                if ( ! $deleted ) {
                    $success = false;
                    $this->log_error( 'Failed to delete option: ' . $key );
                }
            }
        }
        
        // Clear card builder transients
        $this->clear_builder_transients( 'card_' );
        $this->clear_builder_transients( 'card_builder_' );
        
        // Clear cache via engine if available
        if ( function_exists( 'HVN' ) && method_exists( HVNLY_NAB(), 'engine' ) ) {
            HVNLY_NAB()->engine()->clear_transients_by_pattern( 'card_' );
            HVNLY_NAB()->engine()->clear_transients_by_pattern( 'card_builder_' );
        }
        
        return $success;
    }

    /**
     * Clear builder-related transients from database
     *
     * @param string $pattern Pattern to match in transient names
     * @return void
     */
    private function clear_builder_transients( string $pattern ): void {
        global $wpdb;
        
        // Clear transients with the given pattern
        $wpdb->query(
            $wpdb->prepare(
                "DELETE FROM {$wpdb->options} 
                WHERE option_name LIKE %s 
                OR option_name LIKE %s",
                $wpdb->esc_like( '_transient_hvnly_' . $pattern ) . '%',
                $wpdb->esc_like( '_transient_timeout_hvnly_' . $pattern ) . '%'
            )
        );
        
        // Also clear any pattern with the full prefix
        $wpdb->query(
            $wpdb->prepare(
                "DELETE FROM {$wpdb->options} 
                WHERE option_name LIKE %s 
                OR option_name LIKE %s",
                $wpdb->esc_like( '_transient_' . $pattern ) . '%',
                $wpdb->esc_like( '_transient_timeout_' . $pattern ) . '%'
            )
        );
    }

    /**
     * AJAX handler for import with optimized bulk processing
     *
     * @return void
     */
    public function ajax_import_properties() {
        try {
            // Prevent recursive processing
            if ( $this->import_running ) {
                wp_send_json_error( esc_html__( 'Import already in progress.', 'havenlytics' ) );
                return;
            }

            // Security checks
            if ( ! check_ajax_referer( 'hvnly_import_nonce', 'nonce', false ) ) {
                wp_send_json_error( esc_html__( 'Security check failed.', 'havenlytics' ) );
                return;
            }

            if ( ! isset( $_POST['csrf_token'] ) ) {
                wp_send_json_error( esc_html__( 'CSRF token missing.', 'havenlytics' ) );
                return;
            }

            $csrf_token = sanitize_text_field( wp_unslash( $_POST['csrf_token'] ) );
            if ( ! wp_verify_nonce( $csrf_token, 'hvnly_import_csrf' ) ) {
                wp_send_json_error( esc_html__( 'CSRF validation failed.', 'havenlytics' ) );
                return;
            }

            if ( ! current_user_can( 'manage_options' ) ) {
                wp_send_json_error( esc_html__( 'Insufficient permissions.', 'havenlytics' ) );
                return;
            }

            // Set import running flag
            $this->import_running = true;

            // Optimize for bulk import
            $this->optimize_for_bulk_import();

            // Use filter_input instead of wp_unslash for safety
            $batch           = absint( filter_input( INPUT_POST, 'batch', FILTER_VALIDATE_INT ) ?: 0 );
            $imported        = absint( filter_input( INPUT_POST, 'imported', FILTER_VALIDATE_INT ) ?: 0 );
            $total_to_import = min( absint( filter_input( INPUT_POST, 'total_to_import', FILTER_VALIDATE_INT ) ?: 25 ), 200 );
            $skip_builder_reset = filter_input( INPUT_POST, 'skip_builder_reset', FILTER_VALIDATE_BOOLEAN ) ?: false;

            if ( $total_to_import > 200 ) {
                throw new \Exception( esc_html__( 'Import limit exceeded.', 'havenlytics' ) );
            }

            // Sanitize options array using filter_input
            $raw_options = filter_input( INPUT_POST, 'options', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY ) ?: [];
            $options = [];

            if ( is_array( $raw_options ) ) {
                foreach ( $raw_options as $key => $value ) {
                    $safe_key = sanitize_key( $key );

                    if ( is_array( $value ) ) {
                        $options[ $safe_key ] = $this->sanitize_import_options( $value );
                    } elseif ( is_numeric( $value ) ) {
                        $options[ $safe_key ] = floatval( $value );
                    } elseif ( is_string( $value ) ) {
                        $options[ $safe_key ] = sanitize_text_field( $value );
                    } elseif ( is_bool( $value ) || 'true' === $value || 'false' === $value ) {
                        $options[ $safe_key ] = rest_sanitize_boolean( $value );
                    } elseif ( filter_var( $value, FILTER_VALIDATE_URL ) ) {
                        $options[ $safe_key ] = esc_url_raw( $value );
                    } else {
                        $options[ $safe_key ] = $value;
                    }
                }
            }

            $result = $this->process_import_batch( $batch, $imported, $total_to_import, $options );

            // Restore WordPress to normal state
            $this->restore_wordpress_state();

            // Reset import running flag
            $this->import_running = false;

            wp_send_json_success( $result );

        } catch ( \Exception $e ) {
            // Restore WordPress state even on error
            $this->restore_wordpress_state();
            $this->import_running = false;

            $this->log_error( 'Import AJAX error: ' . $e->getMessage() );

            wp_send_json_error(
                [
                    'message'  => $e->getMessage(),
                    'can_retry' => true,
                ]
            );
        }
    }

    /**
     * Optimize WordPress for bulk import operations
     *
     * @return void
     */
    private function optimize_for_bulk_import() {
        // Store original states
        $this->original_cache_state  = wp_suspend_cache_invalidation( false );
        $this->original_term_state   = wp_defer_term_counting( false );
        $this->original_comment_state = wp_defer_comment_counting( false );

        // Suspend cache invalidation
        wp_suspend_cache_invalidation( true );

        // Defer term and comment counting
        wp_defer_term_counting( true );
        wp_defer_comment_counting( true );

        // Increase memory limit for heavy themes
        if ( $this->is_heavy_theme() && function_exists( 'wp_raise_memory_limit' ) ) {
            wp_raise_memory_limit( 'admin' );
        }
    }

    /**
     * Restore WordPress to normal state after import
     *
     * @return void
     */
    private function restore_wordpress_state() {
        // Restore original states
        wp_suspend_cache_invalidation( $this->original_cache_state );
        wp_defer_term_counting( $this->original_term_state );
        wp_defer_comment_counting( $this->original_comment_state );
    }

    /**
     * AJAX handler for cancelling import
     *
     * @return void
     */
    public function ajax_cancel_import() {
        try {
            // Prevent recursive processing
            if ( $this->import_running ) {
                $this->restore_wordpress_state();
                $this->import_running = false;
            }

            if ( ! check_ajax_referer( 'hvnly_import_nonce', 'nonce', false ) ) {
                wp_send_json_error( esc_html__( 'Security check failed.', 'havenlytics' ) );
                return;
            }

            if ( ! isset( $_POST['csrf_token'] ) ) {
                wp_send_json_error( esc_html__( 'CSRF token missing.', 'havenlytics' ) );
                return;
            }

            $csrf_token = sanitize_text_field( wp_unslash( $_POST['csrf_token'] ) );
            if ( ! wp_verify_nonce( $csrf_token, 'hvnly_import_csrf' ) ) {
                wp_send_json_error( esc_html__( 'CSRF validation failed.', 'havenlytics' ) );
                return;
            }

            if ( ! current_user_can( 'manage_options' ) ) {
                wp_send_json_error( esc_html__( 'Insufficient permissions.', 'havenlytics' ) );
                return;
            }

            $this->log_error( 'Import cancelled by user at ' . current_time( 'mysql' ) );

            wp_send_json_success(
                [
                    'message' => esc_html__( 'Import cancelled successfully.', 'havenlytics' ),
                ]
            );

        } catch ( \Exception $e ) {
            $this->log_error( 'Cancel import error: ' . $e->getMessage() );

            wp_send_json_error( $e->getMessage() );
        }
    }

    /**
     * Sanitize import options recursively
     *
     * @param array $options Raw options.
     * @return array Sanitized options
     */
    private function sanitize_import_options( $options ) {
        $sanitized = [];

        foreach ( $options as $key => $value ) {
            $key = sanitize_key( $key );

            if ( is_array( $value ) ) {
                $sanitized[ $key ] = $this->sanitize_import_options( $value );
            } elseif ( is_numeric( $value ) ) {
                $sanitized[ $key ] = floatval( $value );
            } elseif ( is_bool( $value ) || 'true' === $value || 'false' === $value ) {
                $sanitized[ $key ] = rest_sanitize_boolean( $value );
            } elseif ( filter_var( $value, FILTER_VALIDATE_URL ) ) {
                $sanitized[ $key ] = esc_url_raw( $value );
            } elseif ( is_string( $value ) ) {
                $sanitized[ $key ] = sanitize_text_field( $value );
            } else {
                $sanitized[ $key ] = $value;
            }
        }

        return $sanitized;
    }

    /**
     * Validate numeric field
     *
     * @param mixed $value Value to validate.
     * @param int   $min   Minimum value.
     * @param int   $max   Maximum value.
     * @return int|float Validated value
     */
    private function validate_numeric( $value, $min = 0, $max = PHP_INT_MAX ) {
        $value = floatval( $value );
        return max( $min, min( $max, $value ) );
    }

    /**
     * Process import in batches with memory safety
     *
     * @param int   $batch           Current batch number.
     * @param int   $imported        Number already imported.
     * @param int   $total_to_import Total to import.
     * @param array $options         Import options.
     * @return array
     * @throws \Exception If too many errors occur.
     */
    private function process_import_batch( $batch = 0, $imported = 0, $total_to_import = 25, $options = [] ) {
        try {
            $this->ensure_taxonomies_exist();
            $this->check_rate_limit();

            // Use smaller batch size for heavy themes
            $batch_size = $this->is_heavy_theme() ? 3 : 5;

            // Use DemoData class for demo properties
            $demo_properties            = DemoData::get_demo_properties_data();
            $total_properties_available = count( $demo_properties );

            // Calculate remaining properties to import
            $remaining = $total_to_import - $imported;

            // If no more properties to import, return completion
            if ( $remaining <= 0 ) {
                $completion_message = sprintf(
                    /* translators: %d: number of imported properties */
                    __( 'Import complete! Imported %d properties.', 'havenlytics' ),
                    $total_to_import
                );
                
                return [
                    'batch'          => $batch,
                    'next_batch'     => $batch,
                    'imported'       => $total_to_import,
                    'total'          => $total_to_import,
                    'complete'       => true,
                    'percent'        => 100,
                    'message'        => $completion_message,
                    'errors'         => null,
                ];
            }

            // Calculate batch range - ensure we don't exceed remaining
            $start = $batch * $batch_size;
            $end   = min( $start + $batch_size, $start + $remaining );

            $departments     = isset( $options['departments'] ) && is_array( $options['departments'] ) ? $options['departments'] : [];
            $department_keys = ! empty( $departments ) ? array_keys( $departments ) : [ 'sale' ];

            $imported_count = 0;
            $errors         = [];

            // Force garbage collection if available
            if ( function_exists( 'gc_collect_cycles' ) ) {
                gc_collect_cycles();
            }

            // Process only up to remaining properties
            for ( $i = $start; $i < $end && $imported_count < $remaining; $i++ ) {
                try {
                    $property_index = $i % $total_properties_available;
                    $dept_key       = $department_keys[ $i % count( $department_keys ) ];
                    $dept_data      = isset( $departments[ $dept_key ] ) && is_array( $departments[ $dept_key ] ) ? $departments[ $dept_key ] : [];

                    $property_data = $demo_properties[ $property_index ];
                    if ( $i >= $total_properties_available ) {
                        $copy_number = floor( $i / $total_properties_available ) + 1;
                        /* translators: %d: copy number */
                        $property_data['title'] = $property_data['title'] . ' ' . sprintf( __( '(Copy %d)', 'havenlytics' ), $copy_number );
                    }

                    $property_data['department'] = sanitize_key( $dept_key );

                    $property_data = $this->merge_taxonomy_data( $property_data, $dept_data, $demo_properties, $property_index );
                    $property_data = $this->merge_common_options( $property_data, $options );

                    // Check memory before creating property
                    $this->check_memory_usage();

                    $post_id = $this->create_demo_property( $property_data );

                    if ( is_wp_error( $post_id ) ) {
                        throw new \Exception( $post_id->get_error_message() );
                    }

                    $imported_count++;

                } catch ( \Exception $e ) {
                    $errors[] = sprintf(
                        /* translators: 1: property number, 2: error message */
                        __( 'Property %1$d failed: %2$s', 'havenlytics' ),
                        $i + 1,
                        $e->getMessage()
                    );
                    $this->log_error( 'Failed to import property: ' . $e->getMessage() );

                    if ( count( $errors ) >= 3 ) {
                        throw new \Exception(
                            sprintf(
                                /* translators: 1: number of errors, 2: last error message */
                                __( 'Too many errors (%1$d). Last error: %2$s', 'havenlytics' ),
                                count( $errors ),
                                end( $errors )
                            )
                        );
                    }

                    continue;
                }
            }

            $new_total_imported = $imported + $imported_count;
            $complete           = ( $new_total_imported >= $total_to_import );

            if ( $complete ) {
                // Ensure we don't exceed the total
                if ( $new_total_imported > $total_to_import ) {
                    $new_total_imported = $total_to_import;
                }

                update_option( $this->import_option, true );
                update_option( $this->count_option, $new_total_imported );
                $this->update_rate_limit();
                
                $completion_message = sprintf(
                    /* translators: 1: number of imported properties, 2: total properties */
                    __( 'Imported %1$d of %2$d properties...', 'havenlytics' ),
                    $new_total_imported,
                    $total_to_import
                );
                
                return [
                    'batch'          => $batch,
                    'next_batch'     => $batch + 1,
                    'imported'       => $new_total_imported,
                    'total'          => $total_to_import,
                    'complete'       => true,
                    'percent'        => round( ( $new_total_imported / $total_to_import ) * 100 ),
                    'message'        => $completion_message,
                    'errors'         => ! empty( $errors ) ? $errors : null,
                ];
            }

            $result = [
                'batch'      => $batch,
                'next_batch' => $batch + 1,
                'imported'   => $new_total_imported,
                'total'      => $total_to_import,
                'complete'   => $complete,
                'percent'    => round( ( $new_total_imported / $total_to_import ) * 100 ),
                /* translators: 1: number of imported properties, 2: total properties */
                'message'    => sprintf( __( 'Imported %1$d of %2$d properties...', 'havenlytics' ), $new_total_imported, $total_to_import ),
                'errors'     => ! empty( $errors ) ? $errors : null,
            ];

            return $result;

        } catch ( \Exception $e ) {
            $this->log_error( 'Batch processing error: ' . $e->getMessage() );
            throw $e;
        }
    }

    /**
     * Check memory usage and throw warning if low
     *
     * @return void
     */
    private function check_memory_usage() {
        $memory_limit = $this->get_memory_limit_bytes();
        $current_usage = memory_get_usage( true );
        $available     = $memory_limit - $current_usage;

        // If less than 10MB available, force garbage collection
        if ( $available < 10 * 1024 * 1024 ) {
            if ( function_exists( 'gc_collect_cycles' ) ) {
                gc_collect_cycles();
            }
        }
    }

    /**
     * Get memory limit in bytes
     *
     * @return int
     */
    private function get_memory_limit_bytes(): int {
        $memory_limit = ini_get( 'memory_limit' );
        if ( preg_match( '/^(\d+)(.)$/', $memory_limit, $matches ) ) {
            if ( 'G' === $matches[2] ) {
                return (int) $matches[1] * 1024 * 1024 * 1024;
            } elseif ( 'M' === $matches[2] ) {
                return (int) $matches[1] * 1024 * 1024;
            } elseif ( 'K' === $matches[2] ) {
                return (int) $matches[1] * 1024;
            }
        }
        return (int) $memory_limit;
    }

    /**
     * Merge taxonomy data with validation
     *
     * @param array $property_data   Property data.
     * @param array $dept_data       Department data.
     * @param array $demo_properties Demo properties.
     * @param int   $property_index  Property index.
     * @return array Merged data
     */
    private function merge_taxonomy_data( $property_data, $dept_data, $demo_properties, $property_index ) {
        // Map frontend taxonomy keys to backend keys
        $taxonomy_map = [
            'property_types'   => [ 'types', 'property_types' ],
            'property_status'  => [ 'status', 'property_status' ],
            'badges'           => [ 'badges' ],
            'tags'             => [ 'tags' ],
            'locations'        => [ 'locations' ],
            'features'         => [ 'features' ],
        ];

        foreach ( $taxonomy_map as $target => $sources ) {
            $found = false;
            foreach ( $sources as $source ) {
                // Check if data exists in dept_data
                if ( ! empty( $dept_data[ $source ] ) ) {
                    $values = is_array( $dept_data[ $source ] ) ? $dept_data[ $source ] : [ $dept_data[ $source ] ];
                    // Filter out empty values
                    $values = array_filter( $values );
                    if ( ! empty( $values ) ) {
                        $property_data[ $target ] = array_map( 'sanitize_text_field', $values );
                        $found = true;
                        break;
                    }
                }
            }

            // If no data found in dept_data, try demo properties
            if ( ! $found && isset( $demo_properties[ $property_index ][ $target ] ) ) {
                $values = $demo_properties[ $property_index ][ $target ];
                $property_data[ $target ] = is_array( $values ) ? array_map( 'sanitize_text_field', $values ) : [ $values ];
            }

            // Ensure we always have an array, even if empty
            if ( ! isset( $property_data[ $target ] ) ) {
                $property_data[ $target ] = [];
            }
        }

        return $property_data;
    }

    /**
     * Merge common options with validation
     * FIXED: Properly handles 0 values
     *
     * @param array $property_data Property data.
     * @param array $options       Import options.
     * @return array Merged data
     */
    private function merge_common_options( $property_data, $options ) {
        // These fields should ALWAYS use the imported option values (override demo data)
        $always_override_fields = [
            'reference_number',
            'building_number',
            'street',
            'address_line_1',
            'address_line_2',
            'town_city',
            'country_state',
            'zip_code',
            'youtube_title',
            'youtube_url',
            'youtube_thumbnail',
            'gallery_title',
            'map_address',
            'map_latitude',
            'map_longitude',
            'include_images',
            'full_address',
            'latitude',
            'longitude',
            'heating',
            'cooling',
            'water',
            'location',
            'country_location',
            'half_bathrooms',  
            'garage_sqft',      
            'bedrooms',
            'bathrooms',
            'reception_rooms',
            'sqft',
            'price',
            'year_built',
            'floors',
            'total_rooms',
            'kitchens',
        ];
        
        foreach ( $always_override_fields as $field ) {
            // ALWAYS use the imported option value if provided (even if empty)
            if ( isset( $options[ $field ] ) ) {
                // Check if value is numeric (0 is valid)
                if ( is_numeric( $options[ $field ] ) ) {
                    $property_data[ $field ] = floatval( $options[ $field ] );
                } elseif ( 'include_images' === $field ) {
                    $property_data[ $field ] = rest_sanitize_boolean( $options[ $field ] );
                } elseif ( strpos( $field, 'url' ) !== false ) {
                    $property_data[ $field ] = esc_url_raw( $options[ $field ] );
                } else {
                    $property_data[ $field ] = sanitize_text_field( $options[ $field ] );
                }
            }
            // Only apply default if option not provided AND property doesn't have value
            elseif ( ! isset( $property_data[ $field ] ) || $property_data[ $field ] === '' || $property_data[ $field ] === null ) {
                $defaults = [
                    'reference_number'  => 'REF-2024-001',
                    'building_number'   => '123',
                    'street'            => 'Main Street',
                    'address_line_1'    => '123 Main Street',
                    'address_line_2'    => '',
                    'town_city'         => 'Austin',
                    'country_state'     => 'TX',
                    'zip_code'          => '78701',
                    'youtube_title'     => __( 'Property Tour', 'havenlytics' ),
                    'youtube_url'       => '',
                    'youtube_thumbnail' => '',
                    'gallery_title'     => __( 'Property Gallery', 'havenlytics' ),
                    'map_address'       => 'Austin, TX',
                    'map_latitude'      => '30.2672',
                    'map_longitude'     => '-97.7431',
                    'include_images'    => true,
                    'full_address'      => '',
                    'latitude'          => '',
                    'longitude'         => '',
                    'heating'           => '',
                    'cooling'           => '',
                    'water'             => '',
                    'location'          => '',
                    'country_location'  => '',
                    'half_bathrooms'    => 0,
                    'garage_sqft'       => 0,
                    'bedrooms'          => 0,
                    'bathrooms'         => 0,
                    'reception_rooms'   => 0,
                    'sqft'              => 0,
                    'price'             => 0,
                    'year_built'        => 0,
                    'floors'            => 1,
                    'total_rooms'       => 0,
                    'kitchens'          => 0,
                ];
                $property_data[ $field ] = $defaults[ $field ] ?? '';
            }
            // Keep existing numeric value (including 0)
            elseif ( isset( $property_data[ $field ] ) && is_numeric( $property_data[ $field ] ) ) {
                // Already has a value (including 0), keep it
            }
        }

        // If full_address not set, build it from address components
        if ( empty( $property_data['full_address'] ) && ! empty( $property_data['address_line_1'] ) ) {
            $address_parts = [ $property_data['address_line_1'] ];
            if ( ! empty( $property_data['town_city'] ) ) {
                $address_parts[] = $property_data['town_city'];
            }
            if ( ! empty( $property_data['country_state'] ) ) {
                $address_parts[] = $property_data['country_state'];
            }
            if ( ! empty( $property_data['zip_code'] ) ) {
                $address_parts[] = $property_data['zip_code'];
            }
            $property_data['full_address'] = implode( ', ', $address_parts );
        }

        // If latitude/longitude not set, use map_latitude/map_longitude
        if ( empty( $property_data['latitude'] ) && ! empty( $property_data['map_latitude'] ) ) {
            $property_data['latitude'] = $property_data['map_latitude'];
        }
        if ( empty( $property_data['longitude'] ) && ! empty( $property_data['map_longitude'] ) ) {
            $property_data['longitude'] = $property_data['map_longitude'];
        }

        return $property_data;
    }

    /**
     * Check rate limiting
     *
     * @throws \Exception If rate limit exceeded.
     * @return void
     */
    private function check_rate_limit() {
        $rate_key = 'hvnly_import_rate_' . get_current_user_id();
        $attempts = get_transient( $rate_key );

        if ( $attempts && $attempts >= 5 ) {
            throw new \Exception( esc_html__( 'Rate limit exceeded. Please wait before trying again.', 'havenlytics' ) );
        }
    }

    /**
     * Update rate limit
     *
     * @return void
     */
    private function update_rate_limit() {
        $rate_key = 'hvnly_import_rate_' . get_current_user_id();
        $attempts = get_transient( $rate_key );

        if ( $attempts ) {
            set_transient( $rate_key, $attempts + 1, HOUR_IN_SECONDS );
        } else {
            set_transient( $rate_key, 1, HOUR_IN_SECONDS );
        }
    }

    /**
     * Log error - store in options for admin review
     *
     * @param string $message Error message.
     * @return void
     */
    private function log_error( $message ) {
        $log_entry = [
            'time'    => current_time( 'mysql' ),
            'user'    => get_current_user_id(),
            'message' => $message,
        ];

        $logs = get_option( 'hvnly_import_logs', [] );
        array_unshift( $logs, $log_entry );
        $logs = array_slice( $logs, 0, 100 );
        update_option( 'hvnly_import_logs', $logs );
    }

    /**
     * Ensure all taxonomies exist and have the necessary terms
     *
     * @return void
     */
    private function ensure_taxonomies_exist() {
        $taxonomies = [
            'hvnly_prop_depts' => [
                'sale'       => __( 'Sale', 'havenlytics' ),
                'rent'       => __( 'Rent', 'havenlytics' ),
                'commercial' => __( 'Commercial', 'havenlytics' ),
                'let'        => __( 'Let', 'havenlytics' ),
            ],
            'hvnly_prop_types' => [
                'cottage'  => __( 'Cottage', 'havenlytics' ),
                'duplex'   => __( 'Duplex', 'havenlytics' ),
                'flat'     => __( 'Flat', 'havenlytics' ),
                'land'     => __( 'Land', 'havenlytics' ),
                'garage'   => __( 'Garage', 'havenlytics' ),
                'mews'     => __( 'Mews', 'havenlytics' ),
                'triplex'  => __( 'Triplex', 'havenlytics' ),
            ],
            'hvnly_prop_features' => [
                'studio'             => __( 'Studio', 'havenlytics' ),
                'premium'            => __( 'Premium', 'havenlytics' ),
                'privacy'            => __( 'Privacy', 'havenlytics' ),
                'rooftop-terrace'    => __( 'Rooftop Terrace', 'havenlytics' ),
                'hardwood-floors'    => __( 'Hardwood Floors', 'havenlytics' ),
                'central-air'        => __( 'Central Air', 'havenlytics' ),
                'fireplace'          => __( 'Fireplace', 'havenlytics' ),
                'pool'               => __( 'Pool', 'havenlytics' ),
                'gym'                => __( 'Gym', 'havenlytics' ),
                'parking'            => __( 'Parking', 'havenlytics' ),
                'elevator'           => __( 'Elevator', 'havenlytics' ),
                'balcony'            => __( 'Balcony', 'havenlytics' ),
                'garden'             => __( 'Garden', 'havenlytics' ),
                'security'           => __( 'Security', 'havenlytics' ),
            ],
            'hvnly_prop_locations' => [
                'abu-dhabi'    => __( 'Abu Dhabi', 'havenlytics' ),
                'berlin'       => __( 'Berlin', 'havenlytics' ),
                'boston'       => __( 'Boston', 'havenlytics' ),
                'chicago'      => __( 'Chicago', 'havenlytics' ),
                'coastal'      => __( 'Coastal', 'havenlytics' ),
                'dallas'       => __( 'Dallas', 'havenlytics' ),
                'dubai'        => __( 'Dubai', 'havenlytics' ),
                'hong-kong'    => __( 'Hong Kong', 'havenlytics' ),
                'london'       => __( 'London', 'havenlytics' ),
                'los-angeles'  => __( 'Los Angeles', 'havenlytics' ),
                'miami'        => __( 'Miami', 'havenlytics' ),
                'new-york'     => __( 'New York', 'havenlytics' ),
                'paris'        => __( 'Paris', 'havenlytics' ),
                'san-francisco' => __( 'San Francisco', 'havenlytics' ),
                'seattle'      => __( 'Seattle', 'havenlytics' ),
                'singapore'    => __( 'Singapore', 'havenlytics' ),
                'sydney'       => __( 'Sydney', 'havenlytics' ),
                'tokyo'        => __( 'Tokyo', 'havenlytics' ),
                'toronto'      => __( 'Toronto', 'havenlytics' ),
                'vancouver'    => __( 'Vancouver', 'havenlytics' ),
            ],
            'hvnly_prop_status' => [
                'for-sale'    => __( 'For Sale', 'havenlytics' ),
                'for-rent'    => __( 'For Rent', 'havenlytics' ),
                'pending'     => __( 'Pending', 'havenlytics' ),
                'sold'        => __( 'Sold', 'havenlytics' ),
                'under-offer' => __( 'Under Offer', 'havenlytics' ),
                'exchanged'   => __( 'Exchanged', 'havenlytics' ),
            ],
            'hvnly_prop_badges' => [
                'featured' => __( 'Featured', 'havenlytics' ),
                'new'      => __( 'New', 'havenlytics' ),
                'popular'  => __( 'Popular', 'havenlytics' ),
            ],
            'hvnly_prop_tags' => [
                'apartment'  => __( 'Apartment', 'havenlytics' ),
                'bungalow'   => __( 'Bungalow', 'havenlytics' ),
                'commercial' => __( 'Commercial', 'havenlytics' ),
                'cottage'    => __( 'Cottage', 'havenlytics' ),
                'duplex'     => __( 'Duplex', 'havenlytics' ),
                'flat'       => __( 'Flat', 'havenlytics' ),
                'house'      => __( 'House', 'havenlytics' ),
                'land'       => __( 'Land', 'havenlytics' ),
                'office'     => __( 'Office', 'havenlytics' ),
                'retail'     => __( 'Retail', 'havenlytics' ),
                'studio'     => __( 'Studio', 'havenlytics' ),
                'townhouse'  => __( 'Townhouse', 'havenlytics' ),
                'warehouse'  => __( 'Warehouse', 'havenlytics' ),
            ],
        ];

        foreach ( $taxonomies as $taxonomy => $terms ) {
            if ( ! taxonomy_exists( $taxonomy ) ) {
                $this->log_error( sprintf( 'Taxonomy %s does not exist!', $taxonomy ) );
                continue;
            }

            foreach ( $terms as $term_slug => $term_name ) {
                $term = term_exists( $term_slug, $taxonomy );
                if ( ! $term ) {
                    $result = wp_insert_term(
                        $term_name,
                        $taxonomy,
                        [
                            'slug' => $term_slug,
                        ]
                    );

                    if ( is_wp_error( $result ) ) {
                        $this->log_error(
                            sprintf(
                                /* translators: 1: term slug, 2: taxonomy name, 3: error message */
                                __( 'Failed to create term %1$s in taxonomy %2$s: %3$s', 'havenlytics' ),
                                $term_slug,
                                $taxonomy,
                                $result->get_error_message()
                            )
                        );
                    }
                }
            }
        }
    }

    /**
     * Create demo property safely with full field support
     *
     * @param array $data Property data.
     * @return int|\WP_Error Post ID or WP_Error on failure
     * @throws \Exception If post creation fails.
     */
    private function create_demo_property( $data ) {

        // Sanitize title and content
        $title   = isset( $data['title'] ) ? sanitize_text_field( wp_strip_all_tags( $data['title'] ) ) : '';
        $content = isset( $data['content'] ) ? wp_kses_post( $data['content'] ) : __( 'Beautiful property with great features.', 'havenlytics' );
        $excerpt = isset( $data['excerpt'] ) ? sanitize_textarea_field( $data['excerpt'] ) : __( 'Amazing property with all amenities.', 'havenlytics' );

        // Avoid duplicate titles 
        $existing_query = new \WP_Query(
            [
                'post_type'              => $this->post_type,
                'title'                  => $title,
                'posts_per_page'          => 1,
                'post_status'             => 'any',
                'fields'                  => 'ids',
                'no_found_rows'           => true,
                'update_post_meta_cache'  => false,
                'update_post_term_cache'  => false,
            ]
        );

        if ( $existing_query->have_posts() ) {
            $title .= ' ' . uniqid();
        }

        // Build basic meta input
        $meta_input = $this->build_basic_meta_fields( $data );
        $meta_input['_hvnly_property_views']    = $this->validate_numeric( wp_rand( 50, 500 ), 0, 10000 );
        $meta_input['_hvnly_property_featured'] = ! empty( $data['featured'] ) ? '1' : '0';
        $meta_input['_hvnly_importing']         = '1'; // Flag to prevent theme hooks

        // Prepare post array
        $post_data = [
            'post_title'     => $title,
            'post_content'   => $content,
            'post_excerpt'   => $excerpt,
            'post_status'    => 'publish',
            'post_type'      => $this->post_type,
            'post_author'    => get_current_user_id(),
            'meta_input'     => $meta_input,
            'ping_status'    => 'closed',
            'comment_status' => 'closed',
        ];

        // Temporarily suspend theme hooks for wp_insert_post
        remove_all_actions( 'save_post' );
        remove_all_actions( 'save_post_' . $this->post_type );
        remove_all_actions( 'wp_insert_post' );

        // Insert post safely
        $post_id = wp_insert_post( wp_slash( $post_data ), true );

        // Handle insert error
        if ( is_wp_error( $post_id ) ) {
            throw new \Exception( esc_html( $post_id->get_error_message() ) );
        }

        // Remove temporary meta flag
        delete_post_meta( $post_id, '_hvnly_importing' );

        // Set featured image if requested
        if ( ! empty( $data['include_images'] ) ) {
            $this->set_featured_image( $post_id, $data );
            $this->add_gallery_images( $post_id );
        }

        // ========== SAVE GROUP FIELDS USING ACTUAL BUILDER CONFIGURATION ==========
        // Get the current property builder configuration
        $builder_config = get_option( 'hvnly_property_builder.sections', [] );
        
        if ( ! empty( $builder_config ) ) {
            // Flatten all fields from the builder config
            $all_fields = [];
            foreach ( $builder_config as $section ) {
                if ( isset( $section['fields'] ) && is_array( $section['fields'] ) ) {
                    foreach ( $section['fields'] as $field ) {
                        $all_fields[] = $field;
                    }
                }
            }
            
            // Save data for each field based on its type
            foreach ( $all_fields as $field ) {
                $field_type = $field['type'] ?? '';
                $field_name = $field['name'] ?? '';
                
                if ( empty( $field_name ) ) {
                    continue;
                }
                
                switch ( $field_type ) {
                    case 'video':
                        $this->save_video_field_data( $post_id, $field_name, $data );
                        break;
                        
                    case 'gallery':
                        $this->save_gallery_field_data( $post_id, $field_name, $data );
                        break;
                        
                    case 'map':
                        $this->save_map_field_data( $post_id, $field_name, $data );
                        break;
                        
                    case 'property_docs':
                        $this->save_property_docs_field_data( $post_id, $field_name, $data );
                        break;
                }
            }
        } else {
            // Fallback: Try to find fields from the database directly
            $this->save_group_fields_by_pattern( $post_id, $data );
        }

        // Assign all taxonomies
        $this->assign_property_taxonomies( $post_id, $data );

        // Generate property ID using helper if available
        if (
            function_exists( 'hvnlyMain' ) &&
            method_exists( hvnlyMain(), 'Helper' ) &&
            method_exists( hvnlyMain()->Helper, 'generate_property_id' )
        ) {
            hvnlyMain()->Helper->generate_property_id( $post_id );
        }

        return $post_id;
    }

    /**
     * Build basic meta fields (non-group fields)
     * Includes all standard meta fields including YouTube video fields (legacy format)
     * FIXED: Properly handles 0 values as valid numbers
     *
     * @param array $data Property data.
     * @return array Sanitized meta fields
     */
    private function build_basic_meta_fields( $data ) {
        $meta_input = [];
        
        // Numeric fields - 0 is a valid value, only skip if truly empty
        $numeric_fields = [
            '_hvnly_property_price'              => [ 0, 999999999 ],
            '_hvnly_property_reception_rooms'    => [ 0, 20 ],
            '_hvnly_property_bedrooms'           => [ 0, 50 ],
            '_hvnly_property_bathrooms'          => [ 0, 30 ],
            '_hvnly_property_half_bathrooms'     => [ 0, 10 ],
            '_hvnly_property_kitchens'           => [ 0, 10 ],
            '_hvnly_property_total_rooms'        => [ 0, 100 ],
            '_hvnly_property_floors'             => [ 1, 10 ],
            '_hvnly_property_year_built'         => [ 1800, (int) gmdate( 'Y' ) + 1 ],
            '_hvnly_property_garage_sqft'        => [ 0, 10000 ],
            '_hvnly_property_sqft'               => [ 0, 100000 ],
            '_hvnly_property_hoa_fee'            => [ 0, 100000 ],
            '_hvnly_property_annual_tax_amount'  => [ 0, 1000000 ],
        ];

        foreach ( $numeric_fields as $field => $range ) {
            $key = str_replace( '_hvnly_property_', '', $field );
            
            // Check if value exists in data
            if ( isset( $data[ $key ] ) ) {
                // Check if value is numeric (0 is valid)
                if ( is_numeric( $data[ $key ] ) ) {
                    $meta_input[ $field ] = $this->validate_numeric( $data[ $key ], $range[0], $range[1] );
                } else {
                    // For string values like "10 acres", keep as is
                    $meta_input[ $field ] = sanitize_text_field( $data[ $key ] );
                }
            } else {
                // Default to 0 for numeric fields instead of empty
                $meta_input[ $field ] = 0;
            }
        }

        $meta_input['_hvnly_property_mls_number'] = isset( $data['mls_number'] ) && !empty( $data['mls_number'] ) ?
            sanitize_text_field( $data['mls_number'] ) : 'MLS' . absint( wp_rand( 10000, 99999 ) );

        $meta_input['_hvnly_property_lot_size'] = isset( $data['lot_size'] ) && !empty( $data['lot_size'] ) ?
            sanitize_text_field( $data['lot_size'] ) : __( '5000 sq ft', 'havenlytics' );

        // Address fields
        $address_fields = [
            '_hvnly_property_reference_number' => 'reference_number',
            '_hvnly_property_building_number'  => 'building_number',
            '_hvnly_property_street'           => 'street',
            '_hvnly_property_address_line_1'   => 'address_line_1',
            '_hvnly_property_address_line_2'   => 'address_line_2',
            '_hvnly_property_town_city'        => 'town_city',
            '_hvnly_property_country_state'    => 'country_state',
            '_hvnly_property_zip_code'         => 'zip_code',
        ];

        foreach ( $address_fields as $meta_key => $data_key ) {
            if ( isset( $data[ $data_key ] ) && !empty( $data[ $data_key ] ) ) {
                $meta_input[ $meta_key ] = sanitize_text_field( $data[ $data_key ] );
            } elseif ( isset( $data[ $data_key ] ) ) {
                $meta_input[ $meta_key ] = sanitize_text_field( $data[ $data_key ] );
            } else {
                $meta_input[ $meta_key ] = '';
            }
        }

        // Select fields
        $select_fields = [
            '_hvnly_property_heating' => 'heating',
            '_hvnly_property_cooling' => 'cooling',
            '_hvnly_property_water'   => 'water',
            '_hvnly_property_location' => 'location',
            '_hvnly_property_country_location' => 'country_location',
        ];

        foreach ( $select_fields as $meta_key => $data_key ) {
            if ( isset( $data[ $data_key ] ) && !empty( $data[ $data_key ] ) ) {
                $meta_input[ $meta_key ] = sanitize_text_field( $data[ $data_key ] );
            } elseif ( isset( $data[ $data_key ] ) ) {
                $meta_input[ $meta_key ] = sanitize_text_field( $data[ $data_key ] );
            }
        }

        // YouTube video fields - ALWAYS use custom values if provided
        $meta_input['_hvnly_property_youtube_video_title'] = isset( $data['youtube_title'] ) && !empty( $data['youtube_title'] ) ? 
            sanitize_text_field( $data['youtube_title'] ) : __( 'Property Tour', 'havenlytics' );
        
        $meta_input['_hvnly_property_youtube_video_url'] = isset( $data['youtube_url'] ) && !empty( $data['youtube_url'] ) ? 
            esc_url_raw( $data['youtube_url'] ) : '';
        
        $meta_input['_hvnly_property_youtube_video_thumbnail'] = isset( $data['youtube_thumbnail'] ) && !empty( $data['youtube_thumbnail'] ) ? 
            esc_url_raw( $data['youtube_thumbnail'] ) : '';

        return $meta_input;
    }

    /**
     * Save video field data using the actual field name from builder
     * CRITICAL: Stores reference to the active video field IDs for later retrieval
     *
     * @param int    $post_id    Post ID
     * @param string $field_name The field name (e.g., video_xxx_title, video_xxx_url, etc.)
     * @param array  $data       Property data
     * @return void
     */
    private function save_video_field_data( $post_id, $field_name, $data ) {
        // Extract the base ID by removing '_title', '_url', or '_thumbnail'
        $base_name = preg_replace( '/_(title|url|thumbnail)$/', '', $field_name );
        
        if ( ! empty( $base_name ) ) {
            // Determine which part of the video field this is
            if ( strpos( $field_name, '_title' ) !== false ) {
                $title_value = isset( $data['youtube_title'] ) ? sanitize_text_field( $data['youtube_title'] ) : __( 'Property Tour', 'havenlytics' );
                update_post_meta( $post_id, $base_name . '_title', $title_value );
            } elseif ( strpos( $field_name, '_url' ) !== false ) {
                $url_value = isset( $data['youtube_url'] ) ? esc_url_raw( $data['youtube_url'] ) : '';
                update_post_meta( $post_id, $base_name . '_url', $url_value );
            } elseif ( strpos( $field_name, '_thumbnail' ) !== false ) {
                $thumbnail_value = isset( $data['youtube_thumbnail'] ) ? esc_url_raw( $data['youtube_thumbnail'] ) : '';
                update_post_meta( $post_id, $base_name . '_thumbnail', $thumbnail_value );
            }
            
            // ========== CRITICAL: Store reference to the active video field base ID ==========
            // This allows any component to find the correct video fields for this property
            update_post_meta( $post_id, '_hvnly_active_video_field_base', $base_name );
            update_post_meta( $post_id, '_hvnly_active_video_title_key', $base_name . '_title' );
            update_post_meta( $post_id, '_hvnly_active_video_url_key', $base_name . '_url' );
            update_post_meta( $post_id, '_hvnly_active_video_thumbnail_key', $base_name . '_thumbnail' );
        }
    }

    /**
     * Save gallery field data using the actual field name from builder
     * CRITICAL: Stores reference to the active gallery field IDs for later retrieval
     *
     * @param int    $post_id    Post ID
     * @param string $field_name The field name (e.g., gallery_xxx_title or gallery_xxx_images)
     * @param array  $data       Property data
     * @return void
     */
    private function save_gallery_field_data( $post_id, $field_name, $data ) {
        $base_name = preg_replace( '/_(title|images)$/', '', $field_name );
        
        if ( ! empty( $base_name ) ) {
            // Save gallery title
            if ( strpos( $field_name, '_title' ) !== false ) {
                $title_value = isset( $data['gallery_title'] ) ? sanitize_text_field( $data['gallery_title'] ) : __( 'Property Gallery', 'havenlytics' );
                update_post_meta( $post_id, $base_name . '_title', $title_value );
            }
            
            // Save gallery images (already handled by add_gallery_images)
            if ( strpos( $field_name, '_images' ) !== false ) {
                $gallery_ids = get_post_meta( $post_id, '_hvnly_property_gallery_images', true );
                if ( ! empty( $gallery_ids ) ) {
                    update_post_meta( $post_id, $base_name . '_images', $gallery_ids );
                }
            }
            
            // ========== CRITICAL: Store reference to the active gallery field base ID ==========
            // This allows any component to find the correct gallery fields for this property
            update_post_meta( $post_id, '_hvnly_active_gallery_field_base', $base_name );
            update_post_meta( $post_id, '_hvnly_active_gallery_title_key', $base_name . '_title' );
            update_post_meta( $post_id, '_hvnly_active_gallery_images_key', $base_name . '_images' );
        }
    }

    /**
     * Save map field data using the actual field name from builder
     * CRITICAL: Stores reference to the active map field IDs for later retrieval
     *
     * @param int    $post_id    Post ID
     * @param string $field_name The field name (e.g., map_xxx_address, map_xxx_latitude, etc.)
     * @param array  $data       Property data
     * @return void
     */
    private function save_map_field_data( $post_id, $field_name, $data ) {
        // Map fields: address, latitude, longitude, preview
        $base_name = preg_replace( '/_(address|latitude|longitude|preview)$/', '', $field_name );
        
        if ( ! empty( $base_name ) ) {
            // Save map address
            $address_value = isset( $data['full_address'] ) ? sanitize_text_field( $data['full_address'] ) : 
                        ( isset( $data['map_address'] ) ? sanitize_text_field( $data['map_address'] ) : __( 'Austin, TX', 'havenlytics' ) );
            update_post_meta( $post_id, $base_name . '_address', $address_value );
            
            // Save latitude
            $lat_value = isset( $data['latitude'] ) ? sanitize_text_field( $data['latitude'] ) : 
                        ( isset( $data['map_latitude'] ) ? sanitize_text_field( $data['map_latitude'] ) : '30.2672' );
            update_post_meta( $post_id, $base_name . '_latitude', $lat_value );
            
            // Save longitude
            $lng_value = isset( $data['longitude'] ) ? sanitize_text_field( $data['longitude'] ) : 
                        ( isset( $data['map_longitude'] ) ? sanitize_text_field( $data['map_longitude'] ) : '-97.7431' );
            update_post_meta( $post_id, $base_name . '_longitude', $lng_value );
            
            // ========== CRITICAL: Store reference to the active map field ID ==========
            // This allows any component to find the correct map fields for this property
            update_post_meta( $post_id, '_hvnly_active_map_field_base', $base_name );
            update_post_meta( $post_id, '_hvnly_active_map_address_key', $base_name . '_address' );
            update_post_meta( $post_id, '_hvnly_active_map_latitude_key', $base_name . '_latitude' );
            update_post_meta( $post_id, '_hvnly_active_map_longitude_key', $base_name . '_longitude' );
            
            // Also save to legacy fields for backward compatibility (optional, can be removed)
            update_post_meta( $post_id, '_hvnly_property_map_location_address', $address_value );
            update_post_meta( $post_id, '_hvnly_property_location_Latitude', $lat_value );
            update_post_meta( $post_id, '_hvnly_property_location_Longitude', $lng_value );
        }
    }

    /**
     * Save property documents field data using the actual field name from builder
     * CRITICAL: Stores reference to the active document field IDs for later retrieval
     * This handles the document repeater fields with array inputs
     *
     * @param int    $post_id    Post ID
     * @param string $field_name The field name (e.g., property_docs_xxx_documents)
     * @param array  $data       Property data
     * @return void
     */
    private function save_property_docs_field_data( $post_id, $field_name, $data ) {
        // Extract the base ID for documents
        $base_name = preg_replace( '/_documents$/', '', $field_name );
        
        if ( ! empty( $base_name ) ) {
            // Create sample documents with realistic data
            $sample_documents = [
                [
                    'icon' => 'file-pdf',
                    'label' => __( 'Floor Plan', 'havenlytics' ),
                    'url' => 'https://demo.havenlytics.com/sample/floor-plan.pdf',
                ],
                [
                    'icon' => 'file-image',
                    'label' => __( 'Brochure', 'havenlytics' ),
                    'url' => 'https://demo.havenlytics.com/sample/brochure.pdf',
                ],
                [
                    'icon' => 'file-alt',
                    'label' => __( 'Energy Certificate', 'havenlytics' ),
                    'url' => 'https://demo.havenlytics.com/sample/epc.pdf',
                ],
            ];
            
            // Save documents as JSON
            $documents_json = wp_json_encode( $sample_documents );
            update_post_meta( $post_id, $field_name, $documents_json );
            
            // Also save as individual arrays for the repeater field
            $icons = [];
            $labels = [];
            $urls = [];
            
            foreach ( $sample_documents as $doc ) {
                $icons[] = $doc['icon'];
                $labels[] = $doc['label'];
                $urls[] = $doc['url'];
            }
            
            // Save individual arrays for the repeater fields
            update_post_meta( $post_id, $base_name . '_documents_icons', $icons );
            update_post_meta( $post_id, $base_name . '_documents_labels', $labels );
            update_post_meta( $post_id, $base_name . '_documents_urls', $urls );
            
            // Save show_in_sidebar setting
            update_post_meta( $post_id, $base_name . '_show_in_sidebar', '1' );
            
            // ========== CRITICAL: Store reference to the active document field base ID ==========
            // This allows any component to find the correct document fields for this property
            update_post_meta( $post_id, '_hvnly_active_documents_field_base', $base_name );
            update_post_meta( $post_id, '_hvnly_active_documents_key', $field_name );
            update_post_meta( $post_id, '_hvnly_active_documents_icons_key', $base_name . '_documents_icons' );
            update_post_meta( $post_id, '_hvnly_active_documents_labels_key', $base_name . '_documents_labels' );
            update_post_meta( $post_id, '_hvnly_active_documents_urls_key', $base_name . '_documents_urls' );
            
            // Also save to legacy meta for backward compatibility
            update_post_meta( $post_id, '_hvnly_property_documents', $documents_json );
        }
    }

    /**
     * Fallback: Save group fields by searching for pattern in existing post meta
     * This is used when builder config is not available
     *
     * @param int   $post_id Post ID
     * @param array $data    Property data
     * @return void
     */
    private function save_group_fields_by_pattern( $post_id, $data ) {
        global $wpdb;
        
        // Find all meta keys that match our patterns
        $patterns = [ 'video_%_title', 'video_%_url', 'video_%_thumbnail', 'gallery_%_title', 'gallery_%_images', 'map_%_address', 'map_%_latitude', 'map_%_longitude', 'property_docs_%_documents' ];
        
        foreach ( $patterns as $pattern ) {
            $like = $wpdb->esc_like( $pattern );
            $like = str_replace( '%', '%%', $like );
            
            $results = $wpdb->get_col(
                $wpdb->prepare(
                    "SELECT meta_key FROM {$wpdb->postmeta} WHERE post_id = %d AND meta_key LIKE %s LIMIT 1",
                    $post_id,
                    $like
                )
            );
            
            if ( ! empty( $results ) ) {
                $field_name = $results[0];
                
                if ( strpos( $field_name, 'video_' ) !== false ) {
                    $this->save_video_field_data( $post_id, $field_name, $data );
                } elseif ( strpos( $field_name, 'gallery_' ) !== false ) {
                    $this->save_gallery_field_data( $post_id, $field_name, $data );
                } elseif ( strpos( $field_name, 'map_' ) !== false ) {
                    $this->save_map_field_data( $post_id, $field_name, $data );
                } elseif ( strpos( $field_name, 'property_docs_' ) !== false ) {
                    $this->save_property_docs_field_data( $post_id, $field_name, $data );
                }
            }
        }
    }

    /**
     * Set featured image with security checks and error handling
     *
     * @param int   $post_id Post ID.
     * @param array $data    Property data.
     * @return void
     */
    private function set_featured_image( $post_id, $data ) {
        // Use DemoData class for property images
        $property_images = DemoData::get_property_images();

        $image_index = $post_id % count( $property_images );
        $image_url   = esc_url_raw( $property_images[ $image_index ] );

        if ( ! $this->validate_image_url( $image_url ) ) {
            return;
        }

        $attachment_id = $this->download_and_attach_image_secure( $image_url, $post_id, 'featured' );
        if ( $attachment_id && ! is_wp_error( $attachment_id ) ) {
            set_post_thumbnail( $post_id, $attachment_id );
        }
    }

    /**
     * Add gallery images with security checks and error handling
     * Adds 3 gallery images (different from featured image)
     *
     * @param int $post_id Post ID.
     * @return void
     */
    private function add_gallery_images( $post_id ) {
        $gallery_ids = [];

        // Use DemoData class for gallery images
        $gallery_images = DemoData::get_property_images();
        $total_images = count( $gallery_images );

        // Add 3 gallery images
        for ( $i = 1; $i <= 3; $i++ ) {
            $image_index = ( $post_id + $i * 7 ) % $total_images;
            $image_url   = esc_url_raw( $gallery_images[ $image_index ] );

            if ( ! $this->validate_image_url( $image_url ) ) {
                continue;
            }

            $attachment_id = $this->download_and_attach_image_secure( $image_url, $post_id, 'gallery-' . $i );
            if ( $attachment_id && ! is_wp_error( $attachment_id ) ) {
                $gallery_ids[] = $attachment_id;
            }
        }

        if ( ! empty( $gallery_ids ) ) {
            update_post_meta( $post_id, '_hvnly_property_gallery_images', implode( ',', $gallery_ids ) );
        }
    }

    /**
     * Validate image URL for security
     *
     * @param string $url Image URL.
     * @return bool True if valid
     */
    private function validate_image_url( $url ) {
        $host = wp_parse_url( $url, PHP_URL_HOST );

        if ( ! in_array( $host, $this->allowed_image_domains, true ) ) {
            $this->log_error( "Blocked image download from unauthorized domain: $host" );
            return false;
        }

        return true;
    }

    /**
     * Securely download and attach image with enhanced error handling
     *
     * @param string $image_url Image URL.
     * @param int    $post_id   Post ID.
     * @param string $suffix    File suffix.
     * @return int|false Attachment ID or false
     */
    private function download_and_attach_image_secure( $image_url, $post_id, $suffix = '' ) {
        require_once ABSPATH . 'wp-admin/includes/media.php';
        require_once ABSPATH . 'wp-admin/includes/file.php';
        require_once ABSPATH . 'wp-admin/includes/image.php';

        // Check if URL is accessible first
        $head_response = wp_remote_head( $image_url, [ 'timeout' => 10 ] );
        if ( is_wp_error( $head_response ) ) {
            $this->log_error( 'Image URL not accessible: ' . $head_response->get_error_message() );
            return false;
        }

        $status_code = wp_remote_retrieve_response_code( $head_response );
        if ( 200 !== $status_code ) {
            $this->log_error( "Image URL returned HTTP {$status_code}: {$image_url}" );
            return false;
        }

        $temp_file = download_url( $image_url, 300, true );

        if ( is_wp_error( $temp_file ) ) {
            $this->log_error( 'Failed to download image: ' . $temp_file->get_error_message() );
            return false;
        }

        if ( ! file_exists( $temp_file ) ) {
            $this->log_error( 'Downloaded file does not exist: ' . $temp_file );
            return false;
        }

        $filesize = filesize( $temp_file );
        if ( $filesize > $this->max_file_size ) {
            wp_delete_file( $temp_file );
            $this->log_error( 'Image file too large: ' . size_format( $filesize ) );
            return false;
        }

        $file_info = wp_check_filetype_and_ext( $temp_file, basename( $image_url ) );
        $mime_type = $file_info['type'] ?? '';

        if ( empty( $mime_type ) || ! in_array( $mime_type, $this->allowed_mime_types, true ) ) {
            wp_delete_file( $temp_file );
            $this->log_error( "Invalid image mime type: $mime_type" );
            return false;
        }

        // Additional MIME type verification
        if ( function_exists( 'finfo_open' ) ) {
            $finfo       = finfo_open( FILEINFO_MIME_TYPE );
            $actual_mime = finfo_file( $finfo, $temp_file );
            finfo_close( $finfo );

            if ( ! in_array( $actual_mime, $this->allowed_mime_types, true ) ) {
                wp_delete_file( $temp_file );
                $this->log_error( "MIME type mismatch: $actual_mime" );
                return false;
            }
        }

        $file_array = [
            'name'     => sanitize_file_name( 'property-' . $post_id . ( $suffix ? '-' . $suffix : '' ) . '-' . uniqid() . '.jpg' ),
            'tmp_name' => $temp_file,
        ];

        $attachment_id = media_handle_sideload( $file_array, $post_id );

        // Clean up temp file
        if ( file_exists( $temp_file ) ) {
            wp_delete_file( $temp_file );
        }

        if ( is_wp_error( $attachment_id ) ) {
            $this->log_error( 'Failed to attach image: ' . $attachment_id->get_error_message() );
            return false;
        }

        return $attachment_id;
    }

    /**
     * Assign taxonomies to property
     *
     * @param int   $post_id Post ID.
     * @param array $data    Property data.
     * @return void
     */
    private function assign_property_taxonomies( $post_id, $data ) {
        $taxonomy_map = [
            'department'       => 'hvnly_prop_depts',
            'property_types'   => 'hvnly_prop_types',
            'property_status'  => 'hvnly_prop_status',
            'badges'           => 'hvnly_prop_badges',
            'tags'             => 'hvnly_prop_tags',
            'locations'        => 'hvnly_prop_locations',
            'features'         => 'hvnly_prop_features',
        ];

        foreach ( $taxonomy_map as $data_key => $taxonomy ) {
            if ( ! empty( $data[ $data_key ] ) ) {
                $terms = is_array( $data[ $data_key ] ) ? $data[ $data_key ] : [ $data[ $data_key ] ];
                $valid_terms = [];

                foreach ( $terms as $term ) {
                    $term = sanitize_text_field( trim( $term ) );
                    if ( ! empty( $term ) ) {
                        // Check if term exists, if not, create it
                        if ( ! term_exists( $term, $taxonomy ) ) {
                            // Try to get term name from the term slug
                            $term_name = ucwords( str_replace( [ '-', '_' ], ' ', $term ) );
                            $insert_result = wp_insert_term(
                                $term_name,
                                $taxonomy,
                                [ 'slug' => $term ]
                            );
                        }

                        // Verify term exists before adding
                        if ( term_exists( $term, $taxonomy ) ) {
                            $valid_terms[] = $term;
                        }
                    }
                }

                if ( ! empty( $valid_terms ) ) {
                    // Use wp_set_object_terms with append=false for efficiency
                    $result = wp_set_object_terms( $post_id, $valid_terms, $taxonomy, false );
                }
            }
        }
    }
}