<?php
/**
 * Havenlytics Property Sections Metabox - Enhanced with Property Builder Integration
 *
 * @package HvnlyNab\Database\Custom_Metabox
 * @since 2.0.0
 */

namespace HvnlyNab\Database\Custom_Metabox;

use HvnlyNab\Database\Base\Custom_Metabox;
use HvnlyNab\Database\Database;
use HvnlyNab\Admin\Data\TabData;

// Exit if accessed directly.
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Class Havenlytics_Type
 *
 * Handles custom metabox for property sections with full property builder integration.
 */
class Havenlytics_Type extends Custom_Metabox {

    /**
     * Storage key for sections data.
     *
     * @var string
     */
    private $storage_key = 'hvnly_property_builder.sections';

    /**
     * Field registry instance
     *
     * @var object
     */
    private $field_registry;

    /**
     * Current post ID
     *
     * @var int
     */
    private $post_id;

    /**
     * Constructor.
     *
     * Initializes the metabox functionality.
     */
    public function __construct() {
        parent::__construct();
        $this->field_registry = Database::get_field_registry();
        
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_assets' ) );
        add_action( 'add_meta_boxes', array( $this, 'hvnly_register_dynamic_tabs_metabox' ) );
        add_action( 'add_meta_boxes', array( $this, 'hvnly_register_featured_property_metabox' ) );
        add_action( 'save_post', array( $this, 'hvnly_save_dynamic_tabs_data' ) );
        add_action( 'save_post', array( $this, 'hvnly_save_featured_property_data' ) );
        
        // Add admin notice for validation errors
        add_action( 'admin_notices', array( $this, 'display_validation_errors' ) );
    }

    /**
     * Register the dynamic tabs metabox.
     *
     * @return void
     */
    public function hvnly_register_dynamic_tabs_metabox() {
        add_meta_box(
            'hvnly_dynamic_metabox_tabs__main__wrapper',
            __( 'Havenlytics Property Sections', 'havenlytics' ),
            array( $this, 'hvnly_render_dynamic_tabs_metabox' ),
            'hvnly_property',
            'normal',
            'low'
        );
    }

    /**
     * Register featured property metabox.
     *
     * Adds a toggle switch to mark properties as featured in the sidebar.
     *
     * @return void
     */
    public function hvnly_register_featured_property_metabox() {
        add_meta_box(
            'hvnly_featured_property_metabox',
            __( 'Featured Property', 'havenlytics' ),
            array( $this, 'hvnly_render_featured_property_metabox' ),
            'hvnly_property',
            'side',
            'high'
        );
    }

    /**
     * Render the featured property metabox with modern toggle switch.
     *
     * @param WP_Post $post Current post object.
     * @return void
     */
    public function hvnly_render_featured_property_metabox( $post ) {
        wp_nonce_field( 'hvnly_featured_property_save', 'hvnly_featured_property_nonce' );

        $is_featured = get_post_meta( $post->ID, '_hvnly_property_featured', true );
        ?>
<div class="hvnly-featured-toggle-container">
    <label class="hvnly-toggle-label">
        <input type="checkbox" name="_hvnly_property_featured" value="1" <?php checked( $is_featured, '1' ); ?> />
        <span class="hvnly-toggle-slider"></span>
        <span class="hvnly-toggle-text"><?php esc_html_e( 'Featured Property', 'havenlytics' ); ?></span>
    </label>
</div>
<?php
    }

    /**
     * Save featured property data.
     *
     * @param int $post_id Post ID.
     * @return void
     */
    public function hvnly_save_featured_property_data( $post_id ) {
        $nonce = filter_input( INPUT_POST, 'hvnly_featured_property_nonce', FILTER_UNSAFE_RAW );
        $nonce = is_string( $nonce ) ? sanitize_text_field( $nonce ) : '';
        
        if ( ! $nonce || ! wp_verify_nonce( $nonce, 'hvnly_featured_property_save' ) ) {
            return;
        }

        if ( ! current_user_can( 'edit_post', $post_id ) ) {
            return;
        }

        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return;
        }

        $is_featured = filter_input( INPUT_POST, '_hvnly_property_featured', FILTER_VALIDATE_BOOLEAN ) ? '1' : '0';
        update_post_meta( $post_id, '_hvnly_property_featured', $is_featured );
    }

    /**
     * Render the dynamic tabs metabox.
     *
     * @param WP_Post $post Current post object.
     * @return void
     */
    public function hvnly_render_dynamic_tabs_metabox( $post ) {
        wp_nonce_field( 'hvnly_dynamic_metabox_tabs_save', 'hvnly_dynamic_metabox_tabs_nonce' );
        $this->post_id = $post->ID;
        $tabs = $this->get_tabs_data();
        
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
        echo $this->generate_dynamic_tabs_html( $tabs );
    }

    /**
     * Display validation errors from transient as admin notice
     */
    public function display_validation_errors() {
        $screen = get_current_screen();
        if ( ! $screen || $screen->post_type !== 'hvnly_property' ) {
            return;
        }
        
        $post_id = get_the_ID();
        if ( ! $post_id ) {
            return;
        }
        
        $errors = get_transient( 'hvnly_validation_errors_' . $post_id );
        if ( ! empty( $errors ) && is_array( $errors ) ) {
            delete_transient( 'hvnly_validation_errors_' . $post_id );
            ?>
<div class="notice notice-error is-dismissible">
    <p><strong><?php esc_html_e( 'Validation Error:', 'havenlytics' ); ?></strong></p>
    <ul>
        <?php foreach ( $errors as $error ) : ?>
        <li><?php echo esc_html( $error ); ?></li>
        <?php endforeach; ?>
    </ul>
    <p><?php esc_html_e( 'Please fill in all required fields before saving.', 'havenlytics' ); ?></p>
</div>
<?php
        }
    }

    /**
     * Get tabs data from storage with fallback to default
     */
    private function get_tabs_data() {
        $stored_tabs = get_option( $this->storage_key, [] );
        
        if ( empty( $stored_tabs ) || ! is_array( $stored_tabs ) ) {
            return $this->get_default_tabs();
        }
        
        return $this->normalize_tabs_data( $stored_tabs );
    }

    /**
     * Normalize and validate tabs data from the property builder
     */
    private function normalize_tabs_data( $stored_tabs ) {
        $tabs = [];
        
        foreach ( $stored_tabs as $tab_id => $tab ) {
            if ( ! is_array( $tab ) ) {
                continue;
            }
            
            $tabs[] = [
                'id'        => $tab['id'] ?? $tab_id,
                'title'     => $tab['title'] ?? 'Untitled Section',
                'icon'      => $this->normalize_icon( $tab['icon'] ?? 'fas fa-cog' ),
                'fields'    => $this->normalize_fields( $tab['fields'] ?? [] ),
                'order'     => $tab['order'] ?? 0,
                'collapsed' => $tab['collapsed'] ?? false,
                'required'  => $tab['required'] ?? false,
            ];
        }
        
        // Sort by order
        usort( $tabs, function( $a, $b ) {
            return $a['order'] <=> $b['order'];
        } );
        
        return $tabs;
    }

    /**
     * Normalize icon format for consistency
     */
    private function normalize_icon( $icon ) {
        if ( empty( $icon ) ) {
            return 'fas fa-cog';
        }
        
        if ( strpos( $icon, 'fas ' ) === 0 || strpos( $icon, 'far ' ) === 0 || strpos( $icon, 'fab ' ) === 0 ) {
            return $icon;
        }
        
        if ( strpos( $icon, 'fa-' ) === 0 ) {
            return 'fas ' . $icon;
        }
        
        if ( strpos( $icon, 'fa-' ) === false && strpos( $icon, ' ' ) === false ) {
            return 'fas fa-' . $icon;
        }
        
        return 'fas fa-cog';
    }

    /**
     * Normalize field data with proper type handling
     *
     * @param array $fields Raw fields data.
     * @return array Normalized fields.
     */
    private function normalize_fields( $fields ) {
        $normalized = [];
        
        // First pass: collect all fields and group them by group_id
        $groups = [];
        $processed_groups = [];
        
        foreach ( $fields as $index => $field ) {
            if ( ! is_array( $field ) ) {
                continue;
            }
            
            $field_id = $field['id'] ?? 'fld_' . uniqid();
            $group_id = $field['group_id'] ?? null;
            
            if ( $group_id ) {
                if ( ! isset( $groups[ $group_id ] ) ) {
                    $groups[ $group_id ] = [
                        'type'      => $field['group_type'] ?? '',
                        'timestamp' => $field['group_timestamp'] ?? null,
                        'unique_id' => $field['group_unique_id'] ?? null,
                        'base_id'   => $field['group_base_id'] ?? null,
                        'fields'    => [],
                        'show_in_sidebar' => isset( $field['show_in_sidebar'] ) ? (bool) $field['show_in_sidebar'] : true,
                    ];
                }
                $groups[ $group_id ]['fields'][ $field_id ] = $field;
            }
        }
        
        // Second pass: process each field with proper relationships
        foreach ( $fields as $index => $field ) {
            if ( ! is_array( $field ) ) {
                continue;
            }
            
            $type     = $this->map_field_type( $field['type'] ?? 'text' );
            $field_id = $field['id'] ?? 'fld_' . uniqid();
            $group_id = $field['group_id'] ?? null;
            
            // Handle property_docs groups as SINGLE repeater field
            if ( $group_id && isset( $groups[ $group_id ] ) && $groups[ $group_id ]['type'] === 'property_docs' ) {
                if ( in_array( $group_id, $processed_groups, true ) ) {
                    continue;
                }
                
                $processed_groups[] = $group_id;
                
                $group           = $groups[ $group_id ];
                $group_base_id   = $group['base_id'] ?? $group_id;
                $show_in_sidebar = $group['show_in_sidebar'];
                
                $repeater_field = [
                    'id'            => $group_base_id . '_documents',
                    'fieldid'       => $group_base_id . '_documents',
                    'name'          => $group_base_id . '_documents',
                    'type'          => 'property_docs',
                    'label'         => __( 'Property Documents', 'havenlytics' ),
                    'placeholder'   => '',
                    'value'         => '',
                    'is_required'   => false,
                    'admin_only'    => false,
                    'enabled'       => true,
                    'order'         => $field['order'] ?? $index,
                    'options'       => [],
                    'description'   => __( 'Add multiple documents with icons, labels, and URLs', 'havenlytics' ),
                    'userguide'     => '',
                    'autocomplete'  => '',
                    'file_type'     => 'file',
                    'original_type' => 'property_docs',
                    'group_id'       => $group_id,
                    'group_type'     => 'property_docs',
                    'group_name'     => __( 'Property Documents', 'havenlytics' ),
                    'group_position' => 0,
                    'group_total'    => 1,
                    'group_base_id'  => $group_base_id,
                    'group_timestamp' => $group['timestamp'],
                    'group_unique_id' => $group['unique_id'],
                    'show_in_sidebar' => $show_in_sidebar,
                ];
                
                $normalized[] = $repeater_field;
                continue;
            }
            
            $name = $this->get_field_name( $field, $type, $field_id );
            
            $normalized_field = [
                'id'           => $field_id,
                'fieldid'      => $field_id,
                'name'         => $name,
                'type'         => $type,
                'label'        => $field['label'] ?? '',
                'placeholder'  => $field['placeholder'] ?? '',
                'value'        => '',
                'is_required'  => isset( $field['required'] ) ? (bool) $field['required'] : false,
                'admin_only'   => isset( $field['adminOnly'] ) ? (bool) $field['adminOnly'] : false,
                'enabled'      => isset( $field['enabled'] ) ? (bool) $field['enabled'] : true,
                'order'        => $field['order'] ?? $index,
                'options'      => $this->get_field_options( $field, $type, $name ),
                'description'  => $field['description'] ?? '',
                'userguide'    => $field['userguide'] ?? '',
                'autocomplete' => $field['autocomplete'] ?? '',
                'file_type'    => $field['file_type'] ?? 'file',
                'original_type' => $field['type'] ?? $type,
            ];
            
            // Add group information if present
            if ( $group_id && ( ! isset( $groups[ $group_id ] ) || $groups[ $group_id ]['type'] !== 'property_docs' ) ) {
                $normalized_field['group_id']       = $group_id;
                $normalized_field['group_type']     = $field['group_type'] ?? '';
                $normalized_field['group_name']     = $field['group_name'] ?? '';
                $normalized_field['group_position'] = $field['group_position'] ?? 0;
                $normalized_field['group_total']    = $field['group_total'] ?? 0;
                $normalized_field['group_base_id']  = $field['group_base_id'] ?? null;
                $normalized_field['group_timestamp'] = $field['group_timestamp'] ?? null;
                $normalized_field['group_unique_id'] = $field['group_unique_id'] ?? null;
            }
            
            // Map field relationship handling
            if ($type === 'map' && $group_id && isset($groups[$group_id])) {
                $group         = $groups[$group_id];
                $group_base_id = $group['base_id'];
                
                foreach ($group['fields'] as $gfield_id => $gfield) {
                    $gfield_metakey = $gfield['metaKey'] ?? '';
                    $gfield_name    = $gfield['name'] ?? $gfield_id;
                    
                    if ($gfield_metakey === 'address' || strpos($gfield_id, '_address') !== false) {
                        $normalized_field['address_field_name'] = $gfield_name;
                    } elseif ($gfield_metakey === 'latitude' || strpos($gfield_id, '_latitude') !== false) {
                        $normalized_field['lat_field_name'] = $gfield_name;
                    } elseif ($gfield_metakey === 'longitude' || strpos($gfield_id, '_longitude') !== false) {
                        $normalized_field['lng_field_name'] = $gfield_name;
                    }
                }
                
                if (empty($normalized_field['address_field_name']) && $group_base_id) {
                    $normalized_field['address_field_name'] = $group_base_id . '_address';
                }
                if (empty($normalized_field['lat_field_name']) && $group_base_id) {
                    $normalized_field['lat_field_name'] = $group_base_id . '_latitude';
                }
                if (empty($normalized_field['lng_field_name']) && $group_base_id) {
                    $normalized_field['lng_field_name'] = $group_base_id . '_longitude';
                }
                
                $normalized_field['is_map_preview'] = true;
            }
            
            $normalized[] = $normalized_field;
        }
        
        // Sort by order
        usort( $normalized, function( $a, $b ) {
            return ( $a['order'] ?? 0 ) <=> ( $b['order'] ?? 0 );
        } );
        
        return $normalized;
    }

    /**
     * Get field name with conflict resolution
     *
     * @param array  $field    Field data.
     * @param string $type     Field type.
     * @param string $field_id Field ID.
     * @return string Field name.
     */
    private function get_field_name( $field, $type, $field_id ) {
        $is_gallery_field = ( $type === 'gallery' ) || 
                            ( strpos( $field_id, 'gallery_' ) === 0 ) || 
                            ( isset( $field['group_type'] ) && $field['group_type'] === 'gallery' );
        
        if ( $is_gallery_field ) {
            return $field_id;
        }
        
        $is_docs_field = ( $type === 'property_docs' ) || 
                        ( strpos( $field_id, 'property_docs_' ) === 0 ) ||
                        ( isset( $field['group_type'] ) && $field['group_type'] === 'property_docs' );
        
        if ( $is_docs_field ) {
            return $field_id;
        }
        
        if ( $type === 'video' && ! empty( $field['group_base_id'] ) ) {
            $group_base_id = $field['group_base_id'];
            $meta_key      = $field['metaKey'] ?? '';
            
            if ( $meta_key ) {
                return $group_base_id . '_' . $meta_key;
            }
        }
        
        if ( $type === 'map' && ! empty( $field['group_base_id'] ) ) {
            $group_base_id = $field['group_base_id'];
            $meta_key      = $field['metaKey'] ?? '';
            
            if ( $meta_key === 'address' ) {
                return $group_base_id . '_address';
            }
            if ( $meta_key === 'latitude' ) {
                return $group_base_id . '_latitude';
            }
            if ( $meta_key === 'longitude' ) {
                return $group_base_id . '_longitude';
            }
            if ( $meta_key === 'preview' ) {
                return $group_base_id . '_preview';
            }
            
            if ( strpos( $field_id, '_preview' ) !== false ) {
                return $group_base_id . '_preview';
            }
            
            return $group_base_id . '_' . ( $field['id'] ?? 'location' );
        }
        
        return $field_id;
    }

    /**
     * Map stored field type to handler type
     *
     * @param string $stored_type Stored field type.
     * @return string Mapped field type.
     */
    private function map_field_type( $stored_type ) {
        $mapping = [
            'text'          => 'text',
            'textarea'      => 'textarea',
            'select'        => 'select',
            'checkbox'      => 'checkbox',
            'number'        => 'number',
            'email'         => 'text',
            'url'           => 'text',
            'file'          => 'file',
            'image'         => 'file',
            'gallery'       => 'gallery',
            'map'           => 'map',
            'video'         => 'video',
            'property_docs' => 'property_docs',
            'price_label'   => 'price_label',
        ];
        
        return $mapping[ $stored_type ] ?? 'text';
    }

    /**
     * Get field options based on field type and name
     *
     * @param array  $field Field data.
     * @param string $type  Field type.
     * @param string $name  Field name.
     * @return array Field options.
     */
    private function get_field_options( $field, $type, $name ) {
        if ( $type !== 'select' ) {
            return $field['options'] ?? [];
        }
        
        switch ( $name ) {
            case '_hvnly_property_location':
                return $this->get_taxonomy_options( 'hvnly_prop_locations' );
                
            case '_hvnly_property_country_location':
                return TabData::hvnly_get_property_countries();
                
            case '_hvnly_property_heating':
                return [
                    'forced_air' => __( 'Forced Air', 'havenlytics' ),
                    'radiator'   => __( 'Radiator', 'havenlytics' ),
                    'heat_pump'  => __( 'Heat Pump', 'havenlytics' ),
                    'baseboard'  => __( 'Baseboard', 'havenlytics' ),
                    'none'       => __( 'None', 'havenlytics' ),
                ];
                
            case '_hvnly_property_cooling':
                return [
                    'central'    => __( 'Central Air', 'havenlytics' ),
                    'window'     => __( 'Window Units', 'havenlytics' ),
                    'heat_pump'  => __( 'Heat Pump', 'havenlytics' ),
                    'baseboard'  => __( 'Baseboard', 'havenlytics' ),
                    'none'       => __( 'None', 'havenlytics' ),
                ];
                
            case '_hvnly_property_water':
                return [
                    'city'        => __( 'City', 'havenlytics' ),
                    'well'        => __( 'Well', 'havenlytics' ),
                    'shared_well' => __( 'Shared Well', 'havenlytics' ),
                    'none'        => __( 'None', 'havenlytics' ),
                ];
                
            default:
                return $field['options'] ?? [];
        }
    }

    /**
     * Get taxonomy terms as options
     *
     * @param string $taxonomy Taxonomy slug.
     * @return array Taxonomy options.
     */
    private function get_taxonomy_options( $taxonomy ) {
        $terms = get_terms( [
            'taxonomy'   => $taxonomy,
            'hide_empty' => false,
            'orderby'    => 'name',
            'order'      => 'ASC',
        ] );
        
        if ( is_wp_error( $terms ) || empty( $terms ) ) {
            return [];
        }
        
        $options = [];
        foreach ( $terms as $term ) {
            $options[ $term->slug ] = $term->name;
        }
        
        return $options;
    }

    /**
     * Get default tabs structure
     */
    private function get_default_tabs() {
        $default_tabs = TabData::hvnly_metabox_tabs_builder();
        $tabs = [];
        
        foreach ( $default_tabs as $index => $tab ) {
            $tabs[] = [
                'id'        => $tab['id'] ?? 'tab_' . $index,
                'title'     => $tab['hvnly__sectiontitle'] ?? 'Untitled Section',
                'icon'      => $this->normalize_icon( $tab['icon'] ?? 'fas fa-cog' ),
                'fields'    => $this->normalize_default_fields( $tab['fields'] ?? [] ),
                'order'     => $index,
                'collapsed' => false,
                'required'  => false,
            ];
        }
        
        return $tabs;
    }

    /**
     * Normalize default fields from TabData
     *
     * @param array $fields Raw fields data.
     * @return array Normalized fields.
     */
    private function normalize_default_fields( $fields ) {
        $normalized = [];
        
        foreach ( $fields as $index => $field ) {
            $normalized[] = [
                'id'           => $field['fieldid'] ?? 'fld_' . $index,
                'fieldid'      => $field['fieldid'] ?? 'fld_' . $index,
                'name'         => $field['name'] ?? $field['fieldid'] ?? 'fld_' . $index,
                'type'         => $field['input_type'] ?? 'text',
                'label'        => $field['label'] ?? '',
                'placeholder'  => $field['placeholder'] ?? '',
                'value'        => $field['value'] ?? '',
                'is_required'  => isset( $field['is_required'] ) ? (bool) $field['is_required'] : false,
                'admin_only'   => $field['adminOnly'] ?? false,
                'enabled'      => true,
                'order'        => $index,
                'options'      => $field['options'] ?? [],
                'description'  => $field['description'] ?? '',
                'userguide'    => $field['userguide'] ?? '',
                'autocomplete' => $field['autocomplete'] ?? '',
            ];
        }
        
        return $normalized;
    }

    /**
     * Generate dynamic tabs HTML
     *
     * @param array $tabs Tabs data.
     * @return string HTML output.
     */
    private function generate_dynamic_tabs_html( $tabs ) {
        ob_start();
        ?>
<!-- Havenlytics Tabs Container -->
<div class="hvnly__dyamic_metabox_tab__wrapper">
    <!-- Left Side Tab Navigation -->
    <div class="hvnly__dyamic_metabox_tab__nav">
        <ul>
            <?php foreach ( $tabs as $index => $tab ) : ?>
            <?php 
                        $nav_active_class = ( 0 === $index ) ? 'hvnly__dyamic_metabox_tab__active' : ''; 
                        ?>
            <li class="<?php echo esc_attr( $nav_active_class ); ?>">
                <a href="javascript:void(0)" data-target=".hvnly-tab-<?php echo esc_attr( $tab['id'] ); ?>"
                    class="<?php echo esc_attr( $nav_active_class ); ?>">
                    <i class="<?php echo esc_attr( $tab['icon'] ); ?>"></i>
                    <?php echo esc_html( $tab['title'] ); ?>
                </a>
            </li>
            <?php endforeach; ?>
        </ul>
    </div>

    <!-- Tab Content Areas -->
    <div class="hvnly__dyamic_metabox_tab__content">
        <?php foreach ( $tabs as $index => $tab ) : ?>
        <?php 
                    $panel_active_class = ( 0 === $index ) ? 'hvnly__dyamic_metabox_tab__active' : ''; 
                    ?>
        <div
            class="hvnly__dyamic_metabox_tab__tab-content hvnly-tab-<?php echo esc_attr( $tab['id'] ); ?> <?php echo esc_attr( $panel_active_class ); ?>">
            <h3><?php echo esc_html( $tab['title'] ); ?></h3>

            <?php if ( ! empty( $tab['fields'] ) ) : ?>
            <div class="hvnly__dyamic_metabox_tab__fields">
                <?php foreach ( $tab['fields'] as $field ) : ?>
                <?php if ( ! $this->should_display_field( $field ) ) continue; ?>
                <?php 
                                    // Field handlers escape their own output
                                    // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
                                    echo $this->render_field( $field ); 
                                    ?>
                <?php endforeach; ?>
            </div>
            <?php endif; ?>
        </div>
        <?php endforeach; ?>
    </div>
</div>
<!-- Havenlytics Tabs Container -->
<?php
        return ob_get_clean();
    }

    /**
     * Check if field should be displayed
     *
     * @param array $field Field data.
     * @return bool True if field should be displayed.
     */
    private function should_display_field( $field ) {
        if ( isset( $field['enabled'] ) && ! $field['enabled'] ) {
            return false;
        }
        
        if ( isset( $field['admin_only'] ) && $field['admin_only'] && ! current_user_can( 'manage_options' ) ) {
            return false;
        }
        
        return true;
    }

    /**
     * Render field using field type handler
     *
     * @param array $field Field data.
     * @return string Rendered field HTML.
     */
    private function render_field( $field ) {
        $value   = get_post_meta( $this->post_id, $field['name'], true );
        $handler = Database::get_field_handler( $field['type'] );
        
        if ( ! $handler ) {
            $handler = $this->get_fallback_handler( $field['type'] );
        }
        
        if ( ! $handler ) {
            /* translators: %s: Field type name */
            $message = sprintf( __( 'Error: Field type "%s" not found.', 'havenlytics' ), $field['type'] );
            return '<p class="hvnly-field-error-message">' . esc_html( $message ) . '</p>';
        }
        
        $field_content = $handler->render( $field, $value, $this->post_id );
        $is_required = isset( $field['is_required'] ) && $field['is_required'];
        
        if ( $field['type'] === 'property_docs' ) {
            $field_id = $field['id'] ?? $field['name'] ?? '';
            ob_start();
            ?>
<div class="hvnly__dyamic_metabox_tab__field <?php echo $is_required ? 'hvnly-field-required' : ''; ?>"
    data-field-id="<?php echo esc_attr( $field_id ); ?>" data-field-type="property_docs"
    data-is-required="<?php echo $is_required ? 'true' : 'false'; ?>"
    <?php echo $is_required ? 'data-required="true"' : ''; ?>>
    <div class="hvnly__dyamic_metabox_tab__field-input">
        <?php 
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            echo $field_content; 
            ?>
    </div>
</div>
<?php
            return ob_get_clean();
        }
        
        if ( $field['type'] === 'map' ) {
            ob_start();
            ?>
<div class="hvnly__dyamic_metabox_tab__field <?php echo $is_required ? 'hvnly-field-required' : ''; ?>"
    data-field-id="<?php echo esc_attr( $field['id'] ); ?>" data-field-type="map"
    data-is-required="<?php echo $is_required ? 'true' : 'false'; ?>"
    <?php echo $is_required ? 'data-required="true"' : ''; ?>>
    <div class="hvnly__dyamic_metabox_tab__field-input">
        <?php 
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            echo $field_content; 
            ?>
    </div>
</div>
<?php
            return ob_get_clean();
        }
        
        ob_start();
        ?>
<div class="hvnly__dyamic_metabox_tab__field <?php echo esc_attr( $this->get_wrapper_class( $field['type'] ) ); ?> <?php echo $is_required ? 'hvnly-field-required' : ''; ?>"
    data-field-id="<?php echo esc_attr( $field['id'] ); ?>" data-field-type="<?php echo esc_attr( $field['type'] ); ?>"
    data-is-required="<?php echo $is_required ? 'true' : 'false'; ?>"
    <?php echo $is_required ? 'data-required="true"' : ''; ?>>
    <div class="hvnly__dyamic_metabox_tab__field-input">
        <?php 
            // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
            echo $field_content; 
            ?>
    </div>
</div>
<?php
        return ob_get_clean();
    }
    
    /**
     * Get fallback handler if registry fails
     *
     * @param string $type Field type
     * @return object|null
     */
    private function get_fallback_handler( $type ) {
        $handlers = [
            'text' => '\HvnlyNab\Database\FieldTypes\TextField',
            'textarea' => '\HvnlyNab\Database\FieldTypes\TextareaField',
            'number' => '\HvnlyNab\Database\FieldTypes\NumberField',
            'select' => '\HvnlyNab\Database\FieldTypes\SelectField',
            'checkbox' => '\HvnlyNab\Database\FieldTypes\CheckboxField',
            'file' => '\HvnlyNab\Database\FieldTypes\FileField',
            'gallery' => '\HvnlyNab\Database\FieldTypes\GalleryField',
            'map' => '\HvnlyNab\Database\FieldTypes\MapField',
            'video' => '\HvnlyNab\Database\FieldTypes\VideoField',
            'property_docs' => '\HvnlyNab\Database\FieldTypes\DocumentField',
            'price_label' => '\HvnlyNab\Database\FieldTypes\PriceLabelField',
        ];
        
        if ( isset( $handlers[ $type ] ) && class_exists( $handlers[ $type ] ) ) {
            return new $handlers[ $type ]();
        }
        
        return null;
    }

    /**
     * Get wrapper class for field
     *
     * @param string $field_type Field type.
     * @return string CSS class.
     */
    private function get_wrapper_class( $field_type ) {
        return 'checkbox' === $field_type ? 'hvnly__dyamic_metabox_tab__checkbox' : '';
    }

    /**
     * Save dynamic tabs data
     *
     * @param int $post_id Post ID.
     * @return void
     */
    public function hvnly_save_dynamic_tabs_data( $post_id ) {
        $nonce = filter_input( INPUT_POST, 'hvnly_dynamic_metabox_tabs_nonce', FILTER_UNSAFE_RAW );
        $nonce = is_string( $nonce ) ? sanitize_text_field( $nonce ) : '';
        
        if ( ! $nonce || ! wp_verify_nonce( $nonce, 'hvnly_dynamic_metabox_tabs_save' ) ) {
            return;
        }
        
        if ( ! current_user_can( 'edit_post', $post_id ) ) {
            return;
        }
        
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return;
        }
        
        $tabs = $this->get_tabs_data();
        
        // Validate required fields
        $validation_errors = [];
        
        foreach ( $tabs as $tab ) {
            if ( ! empty( $tab['fields'] ) ) {
                foreach ( $tab['fields'] as $field ) {
                    if ( ! $this->should_display_field( $field ) ) {
                        continue;
                    }
                    
                    $is_required = isset( $field['is_required'] ) && $field['is_required'];
                    $field_name  = $field['name'] ?? $field['id'] ?? '';
                    $field_label = $field['label'] ?? $field_name;
                    $field_type  = $field['type'] ?? 'text';
                    
                    if ( $is_required && ! empty( $field_name ) ) {
                        if ( $field_type === 'property_docs' ) {
                            $labels_raw = filter_input( INPUT_POST, $field_name . '_labels', FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY ) ?: [];
                            $urls_raw   = filter_input( INPUT_POST, $field_name . '_urls', FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY ) ?: [];
                            
                            $labels = array_map( 'sanitize_text_field', (array) $labels_raw );
                            $urls   = array_map( 'esc_url_raw', (array) $urls_raw );
                            
                            $has_data = false;
                            foreach ( $labels as $index => $label ) {
                                if ( ! empty( $label ) && ! empty( $urls[ $index ] ) ) {
                                    $has_data = true;
                                    break;
                                }
                            }
                            
                            if ( ! $has_data ) {
                                $validation_errors[] = sprintf(
                                    /* translators: %s: Field label name */
                                    __( 'At least one document is required for "%s".', 'havenlytics' ),
                                    $field_label
                                );
                            }
                        } else {
                            $raw_value = filter_input( INPUT_POST, $field_name, FILTER_UNSAFE_RAW );
                            $value = is_string( $raw_value ) ? sanitize_text_field( $raw_value ) : '';
                            
                            if ( empty( trim( $value ) ) ) {
                                $validation_errors[] = sprintf(
                                    /* translators: %s: Field label name */
                                    __( 'The field "%s" is required.', 'havenlytics' ),
                                    esc_html( $field_label )
                                );
                            }
                        }
                    }
                }
            }
        }
        
        if ( ! empty( $validation_errors ) ) {
            set_transient( 'hvnly_validation_errors_' . $post_id, $validation_errors, 60 );
            
            $edit_link = get_edit_post_link( $post_id, 'raw' );
            if ( $edit_link ) {
                wp_safe_redirect( add_query_arg( 'hvnly_validation_error', '1', $edit_link ) );
                exit;
            }
            return;
        }
        
        // Save fields
        foreach ( $tabs as $tab ) {
            if ( ! empty( $tab['fields'] ) ) {
                foreach ( $tab['fields'] as $field ) {
                    if ( ! $this->should_display_field( $field ) ) {
                        continue;
                    }
                    
                    $field_name = $field['name'] ?? $field['id'] ?? '';
                    $field_type = $field['type'] ?? 'text';
                    $handler    = Database::get_field_handler( $field_type );
                    
                    if ( ! $handler ) {
                        $handler = $this->get_fallback_handler( $field_type );
                    }
                    
                    if ( empty( $field_name ) || ! $handler ) {
                        continue;
                    }
                    
                    // Skip map preview fields
                    if ( $field_type === 'map' ) {
                        continue;
                    }
                    
                    // Handle document fields
                    if ( $field_type === 'property_docs' ) {
                        $icons_raw  = filter_input( INPUT_POST, $field_name . '_icons', FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY ) ?: [];
                        $labels_raw = filter_input( INPUT_POST, $field_name . '_labels', FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY ) ?: [];
                        $urls_raw   = filter_input( INPUT_POST, $field_name . '_urls', FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY ) ?: [];
                        
                        $icons  = array_map( 'sanitize_text_field', (array) $icons_raw );
                        $labels = array_map( 'sanitize_text_field', (array) $labels_raw );
                        $urls   = array_map( 'esc_url_raw', (array) $urls_raw );
                        
                        $documents = [];
                        $count     = max( count( $icons ), count( $labels ), count( $urls ) );
                        
                        for ( $i = 0; $i < $count; $i++ ) {
                            $icon  = isset( $icons[ $i ] ) ? $icons[ $i ] : '';
                            $label = isset( $labels[ $i ] ) ? $labels[ $i ] : '';
                            $url   = isset( $urls[ $i ] ) ? $urls[ $i ] : '';
                            
                            if ( ! empty( $label ) && ! empty( $url ) ) {
                                $documents[] = [
                                    'icon'  => $icon,
                                    'label' => $label,
                                    'url'   => $url,
                                ];
                            }
                        }
                        
                        if ( ! empty( $documents ) ) {
                            update_post_meta( $post_id, $field_name, wp_json_encode( $documents ) );
                        } else {
                            delete_post_meta( $post_id, $field_name );
                        }
                        
                        $sidebar_field = str_replace( '_documents', '_show_in_sidebar', $field_name );
                        $sidebar_raw = filter_input( INPUT_POST, $sidebar_field, FILTER_UNSAFE_RAW );
                        $sidebar_value = ! empty( $sidebar_raw ) ? '1' : '0';
                        update_post_meta( $post_id, $sidebar_field, $sidebar_value );
                        
                        continue;
                    }
                    
                    $raw_value = filter_input( INPUT_POST, $field_name, FILTER_UNSAFE_RAW );
                    
                    if ( $raw_value !== null && $raw_value !== false ) {
                        $sanitized_value = $handler->sanitize( $raw_value );
                        $handler->save( $post_id, $field_name, $sanitized_value );
                    }
                }
            }
        }
        
        $this->save_gallery_metadata( $post_id );
    }

    /**
     * Save gallery metadata for multiple groups
     *
     * @param int $post_id Post ID.
     * @return void
     */
    private function save_gallery_metadata( $post_id ) {
        $post_data = filter_input_array( INPUT_POST );
        
        if ( empty( $post_data ) || ! is_array( $post_data ) ) {
            return;
        }
        
        foreach ( $post_data as $key => $value ) {
            if ( strpos( $key, 'hvnly_gallery_title_' ) === 0 ) {
                $gallery_id    = str_replace( 'hvnly_gallery_title_', '', $key );
                $ids_key       = 'hvnly_gallery_ids_' . $gallery_id;
                $captions_key  = 'hvnly_gallery_caption_' . $gallery_id;
                
                $ids_raw     = filter_input( INPUT_POST, $ids_key, FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY ) ?: [];
                $titles_raw  = filter_input( INPUT_POST, $key, FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY ) ?: [];
                $captions_raw = filter_input( INPUT_POST, $captions_key, FILTER_UNSAFE_RAW, FILTER_REQUIRE_ARRAY ) ?: [];
                
                $attachment_ids = array_map( 'intval', (array) $ids_raw );
                $titles = array_map( 'sanitize_text_field', (array) $titles_raw );
                $captions = array_map( 'sanitize_textarea_field', (array) $captions_raw );
                
                foreach ( $attachment_ids as $index => $attachment_id ) {
                    if ( ! empty( $attachment_id ) ) {
                        $title   = isset( $titles[ $index ] ) ? $titles[ $index ] : '';
                        $caption = isset( $captions[ $index ] ) ? $captions[ $index ] : '';
                        
                        wp_update_post([
                            'ID'           => intval( $attachment_id ),
                            'post_title'   => $title,
                            'post_excerpt' => $caption,
                        ]);
                    }
                }
            }
        }
    }

    /**
     * Enqueue admin assets
     *
     * @return void
     */
    public static function enqueue_assets() {
        if ( ! is_admin() ) {
            return;
        }
        
        $screen = get_current_screen();
        if ( ! $screen ) {
            return;
        }
        
        $allowed_post_types = array( 'hvnly_property' );
        $default_version = defined( 'HVNLYNAB_VERSION' ) ? HVNLYNAB_VERSION : '1.0.0';
        
        if ( in_array( $screen->post_type ?? '', $allowed_post_types, true ) ) {
            $styles = [
                'hvnly-admin-fontawesome-all' => HVNLYNAB_ASSETS_URL . '/admin/css/fontawesome-all.min.css',
                'hvnly-admin-leaflet'         => HVNLYNAB_ASSETS_URL . '/admin/css/hvnly-admin-leaflet.css',
                'hvnly-admin-metabox'         => HVNLYNAB_ASSETS_URL . '/admin/css/hvnly-admin-metabox.css',
            ];

            foreach ( $styles as $handle => $src ) {
                $file_path = HVNLYNAB_PATH . str_replace( HVNLYNAB_ASSETS_URL, '', $src );
                $version   = file_exists( $file_path ) ? filemtime( $file_path ) : $default_version;
                wp_enqueue_style( $handle, $src, array(), $version );
            }
        }
        
        if ( in_array( $screen->base, array( 'post', 'post-new' ), true ) &&
             in_array( $screen->post_type ?? '', $allowed_post_types, true ) ) {
            
            wp_enqueue_script(
                'leaflet',
                HVNLYNAB_ASSETS_URL . '/admin/js/leaflet/core-leaflet.js',
                array(),
                '1.9.4',
                true
            );
        }
    }
}