/**
 * Schema Builder App - Core JavaScript
 * 
 * Main application logic for the schema builder
 * 
 * @package CustomSchemaSchemafy
 * @since 2.0.0
 */

(function($) {
    'use strict';
    
    // Builder App namespace
    window.SchemafyBuilder = window.SchemafyBuilder || {};
    
    /**
     * Main Builder Application
     */
    SchemafyBuilder.App = {
        
        /**
         * Current schema ID being edited
         */
        currentSchemaId: 0,
        
        /**
         * Current schema type
         */
        currentSchemaType: '',
        
        /**
         * Current mode ('visual' or 'json')
         */
        currentMode: 'visual',
        
        /**
         * Field configuration for current schema type
         */
        fieldConfig: null,
        
        /**
         * Current field values
         */
        fieldValues: {},

        /**
         * Original complete schema data (preserved for unknown-field round-trip)
         */
        _originalData: {},

        /**
         * Raw @type value from loaded schema (may be array for multi-type schemas)
         */
        _rawSchemaType: null,

        /**
         * Initialize the builder
         */
        init: function() {
            
            this.bindEvents();
            this.initSchemaTypeSelector();
            this.initNavigation();
            
            // Load existing schema if ID provided (support both schema_id and edit_id)
            const urlParams = new URLSearchParams(window.location.search);
            const schemaId = urlParams.get('schema_id') || urlParams.get('edit_id');
            const prefillUrl = urlParams.get('url');

            if (schemaId) {
                this.loadSchema(schemaId);
            } else if (prefillUrl) {
                // Pre-fill URL for new schema
                this.setUrl(prefillUrl);
            }

            // Check for pending schema from admin redirect
            if (window.pendingSchemaEdit) {
                this.loadSchemaData(window.pendingSchemaEdit);
                window.pendingSchemaEdit = null;
            } else if (window.pendingBuilderUrl) {
                this.setUrl(window.pendingBuilderUrl);
                window.pendingBuilderUrl = null;
            }
            
        },
        
        /**
         * Bind global events
         */
        bindEvents: function() {
            // Schema type change
            $(document).on('change', '#schemafy-schema-type', this.onSchemaTypeChange.bind(this));
            
            // Mode toggle
            $(document).on('click', '.schemafy-mode-toggle', this.toggleMode.bind(this));
            
            // Save button
            $(document).on('click', '#schemafy-save-schema', this.saveSchema.bind(this));
            
            // Field changes (for real-time validation and scoring)
            $(document).on('input change', '.schemafy-field-input, .schemafy-field-textarea, .schemafy-field-select', 
                this.onFieldChange.bind(this));
            
            // Template loading
            $(document).on('click', '.schemafy-load-template', this.loadTemplate.bind(this));
        },
        
        /**
         * Initialize schema type selector
         */
        initSchemaTypeSelector: function() {
            const $selector = $('#schemafy-schema-type');
            
            if ($selector.length && schemafyBuilder.schema_types) {
                schemafyBuilder.schema_types.forEach(function(type) {
                    $selector.append(
                        $('<option>').val(type).text(type)
                    );
                });
            }
        },
        
        /**
         * Initialize sidebar navigation
         */
        initNavigation: function() {
            const self = this;

            $('.schemafy-builder-nav-link').on('click', function(e) {
                e.preventDefault();

                const target = $(this).data('target');

                // Update active state
                $('.schemafy-builder-nav-link').removeClass('active');
                $(this).addClass('active');

                // Show corresponding panel
                $('.schemafy-builder-panel').hide();
                $('#' + target).show();

                // Initialize JSON editor when that panel is shown
                if (target === 'schemafy-json-panel' && typeof SchemafyBuilder.JSON !== 'undefined') {
                    const jsonData = self.fieldValuesToJSON();
                    SchemafyBuilder.JSON.show(jsonData);
                }
            });
        },
        
        /**
         * Handle schema type change
         */
        onSchemaTypeChange: function(e) {
            const schemaType = $(e.target).val();
            
            if (!schemaType) {
                return;
            }
            
            this.currentSchemaType = schemaType;
            this.loadFieldConfig(schemaType);
        },
        
        /**
         * Schema types that fall back to a parent type's field config when no specific config exists
         */
        _typeConfigFallback: {
            'NewsArticle': 'Article', 'BlogPosting': 'Article', 'TechArticle': 'Article',
            'SatiricalArticle': 'Article', 'ScholarlyArticle': 'Article',
            'AdvertiserContentArticle': 'Article', 'AnalysisNewsArticle': 'Article',
            'AskPublicNewsArticle': 'Article', 'BackgroundNewsArticle': 'Article',
            'MedicalScholarlyArticle': 'Article', 'ReportageNewsArticle': 'Article',
            'SocialMediaPosting': 'Article',
            'EventVenue': 'LocalBusiness', 'Restaurant': 'LocalBusiness',
            'CafeOrCoffeeShop': 'LocalBusiness', 'Dentist': 'LocalBusiness',
            'Physician': 'LocalBusiness', 'Physiotherapist': 'LocalBusiness',
            'Pharmacy': 'LocalBusiness', 'BeautySalon': 'LocalBusiness',
            'HealthAndBeautyBusiness': 'LocalBusiness', 'Optician': 'LocalBusiness',
            'VeterinaryCare': 'LocalBusiness', 'ChildCare': 'LocalBusiness',
            'ExerciseGym': 'LocalBusiness', 'LegalService': 'LocalBusiness',
            'AccountingService': 'LocalBusiness', 'FinancialService': 'LocalBusiness',
            'InsuranceAgency': 'LocalBusiness', 'ProfessionalService': 'LocalBusiness',
            'RealEstateAgent': 'LocalBusiness', 'LodgingBusiness': 'LocalBusiness',
            'AutoDealer': 'LocalBusiness', 'AutoRepair': 'LocalBusiness',
            'AutoWash': 'LocalBusiness', 'AutoRental': 'LocalBusiness',
            'AutomotiveBusiness': 'LocalBusiness', 'TaxiService': 'LocalBusiness',
            'GovernmentOffice': 'LocalBusiness', 'NailSalon': 'LocalBusiness',
            'TravelAgency': 'LocalBusiness', 'Florist': 'LocalBusiness',
            'MovingCompany': 'LocalBusiness', 'Plumber': 'LocalBusiness',
            'Electrician': 'LocalBusiness', 'HVACBusiness': 'LocalBusiness',
            'GeneralContractor': 'LocalBusiness', 'RoofingContractor': 'LocalBusiness',
            'HousePainter': 'LocalBusiness', 'HomeAndConstructionBusiness': 'LocalBusiness',
            'Locksmith': 'LocalBusiness', 'FoodEstablishment': 'LocalBusiness',
            'Bakery': 'LocalBusiness', 'EntertainmentBusiness': 'LocalBusiness',
            'SportsActivityLocation': 'LocalBusiness', 'MedicalBusiness': 'LocalBusiness',
            'Airline': 'Organization', 'Consortium': 'Organization',
            'Corporation': 'Organization', 'EducationalOrganization': 'Organization',
            'GovernmentOrganization': 'Organization', 'LibrarySystem': 'Organization',
            'NGO': 'Organization', 'NewsMediaOrganization': 'Organization',
            'OnlineBusiness': 'Organization', 'PerformingGroup': 'Organization',
            'Project': 'Organization', 'ResearchOrganization': 'Organization',
            'SearchRescueOrganization': 'Organization', 'SportsOrganization': 'Organization',
            'WorkersUnion': 'Organization',
            'AboutPage': 'WebPage', 'ContactPage': 'WebPage',
            'CheckoutPage': 'WebPage', 'WebSite': 'WebPage',
            'ItemPage': 'WebPage', 'ProfilePage': 'WebPage',
            'MedicalWebPage': 'WebPage', 'QAPage': 'WebPage',
            'RealEstateListing': 'WebPage', 'SearchResultsPage': 'WebPage',
            'CollectionPage': 'WebPage', 'ImageGallery': 'WebPage'
        },

        getTypeConfigFallback: function(schemaType) {
            const registry = (typeof schemafyBuilder !== 'undefined' && schemafyBuilder.schema_type_registry)
                ? schemafyBuilder.schema_type_registry
                : {};
            const fallbackMap = registry.configFallbackMap || registry.typeMap || this._typeConfigFallback;

            return fallbackMap[schemaType];
        },

        /**
         * Load field configuration for schema type — with automatic parent-type fallback
         */
        loadFieldConfig: function(schemaType) {
            const self = this;

            const tryLoad = function(type, originalType) {
                $.ajax({
                    url: schemafyBuilder.ajax_url,
                    method: 'POST',
                    data: {
                        action: 'schemafy_builder_get_field_config',
                        nonce: schemafyBuilder.nonce,
                        schema_type: type
                    },
                    success: function(response) {
                        if (response.success) {
                            self.fieldConfig = response.data;
                            self.renderVisualForm();
                            self.updateTypeIndicator(originalType || type);
                        } else {
                            const fallback = self.getTypeConfigFallback(type);
                            if (fallback && fallback !== type) {
                                tryLoad(fallback, originalType || type);
                            } else {
                                self.fieldConfig = { fields: [] };
                                self.renderVisualForm();
                                self.updateTypeIndicator(originalType || type);
                            }
                        }
                    },
                    error: function() {
                        self.fieldConfig = { fields: [] };
                        self.renderVisualForm();
                    }
                });
            };

            tryLoad(schemaType);
        },

        /**
         * Show @type indicator badge (for multi-type or fallback-config schemas)
         */
        updateTypeIndicator: function(displayType) {
            const rawType = this._rawSchemaType;
            let $indicator = $('#schemafy-type-indicator');
            if (!$indicator.length) {
                $indicator = $('<div id="schemafy-type-indicator" class="schemafy-type-indicator" style="display:none;">');
                $('#schemafy-schema-type').closest('.schemafy-field-group, .schemafy-selector-wrap').after($indicator);
                if (!$indicator.parent().length) {
                    $('#schemafy-schema-type').after($indicator);
                }
            }

            if (Array.isArray(rawType) && rawType.length > 1) {
                $indicator.html(
                    '<span class="schemafy-type-badge schemafy-type-primary">' + rawType[0] + '</span>' +
                    ' + ' +
                    '<span class="schemafy-type-badge schemafy-type-secondary">' + rawType[rawType.length - 1] + '</span>' +
                    ' <span class="schemafy-type-note">Multi-type schema — all fields preserved on save</span>'
                );
                $indicator.show();
            } else if (displayType && displayType !== (Array.isArray(rawType) ? rawType[0] : rawType)) {
                $indicator.html(
                    '<span class="schemafy-type-note">Using <strong>' +
                    (Array.isArray(rawType) ? rawType[0] : (rawType || displayType)) +
                    '</strong> field config</span>'
                );
                $indicator.show();
            } else {
                $indicator.hide();
            }
        },
        
        /**
         * Render visual form based on field config
         */
        renderVisualForm: function() {
            // This will be implemented in builder-visual.js
            if (typeof SchemafyBuilder.Visual !== 'undefined') {
                SchemafyBuilder.Visual.render(this.fieldConfig, this.fieldValues);
            }
        },
        
        /**
         * Toggle between visual and JSON mode
         */
        toggleMode: function(e) {
            e.preventDefault();
            
            const newMode = $(e.currentTarget).data('mode');
            
            if (newMode === this.currentMode) {
                return;
            }
            
            if (newMode === 'json') {
                // Switch to JSON
                this.switchToJsonMode();
            } else {
                // Switch to visual
                this.switchToVisualMode();
            }
            
            this.currentMode = newMode;
        },
        
        /**
         * Switch to JSON editor mode
         */
        switchToJsonMode: function() {
            if (typeof SchemafyBuilder.JSON !== 'undefined') {
                // Convert current form values to JSON
                const jsonData = this.fieldValuesToJSON();
                SchemafyBuilder.JSON.show(jsonData);
            }
        },
        
        /**
         * Switch to visual editor mode
         */
        switchToVisualMode: function() {
            if (typeof SchemafyBuilder.JSON !== 'undefined') {
                // Get JSON data and convert to form values
                const jsonData = SchemafyBuilder.JSON.getValue();
                this.JSONToFieldValues(jsonData);
            }
            
            this.renderVisualForm();
        },
        
        /**
         * Convert field values to JSON-LD.
         * Starts from _originalData so ALL unknown fields are preserved,
         * then overlays what the user has edited in the visual form.
         */
        fieldValuesToJSON: function() {
            const rawType = this._rawSchemaType || this.currentSchemaType;

            // Known nested @type annotations
            const knownNestedTypes = {
                brand: 'Brand', offers: 'Offer', aggregateRating: 'AggregateRating',
                author: 'Person', publisher: 'Organization', location: 'Place',
                address: 'PostalAddress', geo: 'GeoCoordinates',
                performer: 'Person', organizer: 'Organization', contactPoint: 'ContactPoint',
                potentialAction: 'SearchAction', mainEntity: 'ItemList'
            };

            // Start with original data — this preserves @id, sameAs, amenityFeature, etc.
            const schema = Object.assign({}, this._originalData || {});
            schema['@context'] = 'https://schema.org';
            schema['@type'] = rawType;

            // Separate plain keys (nested objects) from dot-notation keys (edited sub-fields)
            // Process plain keys first so dot-notation edits can surgically override sub-fields
            const plainEntries = [];
            const dotEntries = [];

            Object.entries(this.fieldValues || {}).forEach(([key, value]) => {
                if (key.startsWith('@')) return;
                if (value === '' || value === null || value === undefined) return;
                if (key.includes('.')) {
                    dotEntries.push([key, value]);
                } else {
                    plainEntries.push([key, value]);
                }
            });

            plainEntries.forEach(([key, value]) => { schema[key] = value; });

            dotEntries.forEach(([key, value]) => {
                const parts = key.split('.');
                let obj = schema;
                for (let i = 0; i < parts.length - 1; i++) {
                    const part = parts[i];
                    if (!obj[part] || typeof obj[part] !== 'object' || Array.isArray(obj[part])) {
                        obj[part] = {};
                        if (knownNestedTypes[part]) obj[part]['@type'] = knownNestedTypes[part];
                    }
                    obj = obj[part];
                }
                obj[parts[parts.length - 1]] = value;
            });

            // Merge the "Additional Fields" JSON textarea (power-user escape hatch)
            const $extra = $('#schemafy-extra-fields-json');
            if ($extra.length && $extra.val().trim()) {
                try {
                    const extra = JSON.parse($extra.val());
                    Object.assign(schema, extra);
                    // Re-assert context and type after merge
                    schema['@context'] = 'https://schema.org';
                    schema['@type'] = rawType;
                } catch (e) {
                    console.warn('[SCHEMAFY Builder] Extra fields JSON invalid — skipped:', e.message);
                }
            }

            return schema;
        },

        /**
         * Convert JSON-LD to field values.
         * Preserves the complete original data and handles @type arrays.
         */
        JSONToFieldValues: function(jsonData) {
            if (!jsonData || typeof jsonData !== 'object') return;

            // Preserve raw @type — may be array like ["LocalBusiness","EventVenue"]
            this._rawSchemaType = jsonData['@type'] || null;

            // Deep-clone original (minus @context) for lossless round-trip
            const original = JSON.parse(JSON.stringify(jsonData));
            delete original['@context'];
            this._originalData = original;

            // Resolve primary type for field config loading
            if (Array.isArray(this._rawSchemaType)) {
                this.currentSchemaType = this._rawSchemaType[this._rawSchemaType.length - 1];
            } else {
                this.currentSchemaType = this._rawSchemaType || '';
            }

            // fieldValues keeps nested objects so group fields can read sub-values
            const fv = Object.assign({}, jsonData);
            delete fv['@context'];
            delete fv['@type'];
            this.fieldValues = fv;
        },
        
        /**
         * Handle field value change
         */
        onFieldChange: function(e) {
            const $field = $(e.target);
            const fieldName = $field.attr('name');
            const fieldValue = $field.val();

            // Store dot-notation keys as-is (e.g., "address.streetAddress")
            // and keep top-level keys for plain fields
            this.fieldValues[fieldName] = fieldValue;
            
            // Real-time validation
            this.validateField($field);
            
            // Update SEO score
            this.updateSEOScore();
            
            // Update preview
            if (typeof SchemafyBuilder.Preview !== 'undefined') {
                SchemafyBuilder.Preview.update(this.fieldValues);
            }
        },
        
        /**
         * Validate single field
         */
        validateField: function($field) {
            const fieldName = $field.attr('name');
            const fieldValue = $field.val();
            
            // Get field config
            const fieldConfig = this.getFieldConfigByName(fieldName);
            
            if (!fieldConfig) {
                return;
            }
            
            const self = this;
            
            $.ajax({
                url: schemafyBuilder.ajax_url,
                method: 'POST',
                data: {
                    action: 'schemafy_builder_validate_field',
                    nonce: schemafyBuilder.nonce,
                    field_name: fieldName,
                    field_value: fieldValue,
                    field_config: JSON.stringify(fieldConfig)
                },
                success: function(response) {
                    if (response.success) {
                        self.showFieldValidation($field, response.data);
                    }
                }
            });
        },
        
        /**
         * Show field validation result
         */
        showFieldValidation: function($field, validation) {
            const $group = $field.closest('.schemafy-field-group');
            const $validation = $group.find('.schemafy-field-validation');
            
            if (validation.valid) {
                $field.removeClass('invalid').addClass('valid');
                $validation.removeClass('error').addClass('success').text('✓');
            } else {
                $field.removeClass('valid').addClass('invalid');
                $validation.removeClass('success').addClass('error')
                    .text(validation.errors.join(', '));
            }
        },
        
        /**
         * Get field config by field name
         */
        getFieldConfigByName: function(fieldName) {
            if (!this.fieldConfig || !this.fieldConfig.fields) {
                return null;
            }
            
            for (let i = 0; i < this.fieldConfig.fields.length; i++) {
                if (this.fieldConfig.fields[i].name === fieldName) {
                    return this.fieldConfig.fields[i];
                }
            }
            
            return null;
        },
        
        /**
         * Update SEO score
         */
        updateSEOScore: function() {
            if (typeof SchemafyBuilder.Scoring !== 'undefined') {
                SchemafyBuilder.Scoring.calculate(this.fieldConfig, this.fieldValues);
            }
        },
        
        /**
         * Load existing schema
         */
        loadSchema: function(schemaId) {
            const self = this;

            $.ajax({
                url: schemafyBuilder.ajax_url,
                method: 'POST',
                data: {
                    action: 'schemafy_builder_load_schema',
                    nonce: schemafyBuilder.nonce,
                    schema_id: schemaId
                },
                success: function(response) {
                    if (response.success) {
                        self.currentSchemaId = schemaId;

                        const schema = response.data;

                        // Load field values — also sets _rawSchemaType, _originalData, currentSchemaType
                        self.JSONToFieldValues(JSON.parse(schema.schema_data));

                        // Set selector to primary type (array types use last/most-specific)
                        const selectorType = Array.isArray(self._rawSchemaType)
                            ? self._rawSchemaType[self._rawSchemaType.length - 1]
                            : (self.currentSchemaType || schema.schema_type);
                        $('#schemafy-schema-type').val(selectorType).trigger('change');

                        if (schema.url) self.setUrl(schema.url);
                    }
                }
            });
        },

        /**
         * Set URL field value
         */
        setUrl: function(url) {
            // Try multiple possible URL field selectors
            const urlSelectors = [
                '#schemafy-schema-url',
                '#builder-url',
                '#schemafy-builder-url',
                '[name="schema_url"]',
                '[name="url"]',
                '.schemafy-url-field input'
            ];

            urlSelectors.forEach(selector => {
                const $field = $(selector);
                if ($field.length) {
                    $field.val(url);
                }
            });

            // Store URL in field values
            this.fieldValues = this.fieldValues || {};
            this.fieldValues.url = url;

        },

        /**
         * Load schema data directly (from object, not from server)
         */
        loadSchemaData: function(schema) {
            this.currentSchemaId = schema.id;
            this.currentSchemaType = schema.schema_type;

            // Parse schema_data if it's a string
            let schemaData = schema.schema_data;
            if (typeof schemaData === 'string') {
                try {
                    schemaData = JSON.parse(schemaData);
                } catch (e) {
                    console.error('[SCHEMAFY Builder] Error parsing schema data:', e);
                    return;
                }
            }

            this.JSONToFieldValues(schemaData);

            const selectorType = Array.isArray(this._rawSchemaType)
                ? this._rawSchemaType[this._rawSchemaType.length - 1]
                : (this.currentSchemaType || schema.schema_type);
            $('#schemafy-schema-type').val(selectorType).trigger('change');

            // Set URL if available
            if (schema.url) {
                this.setUrl(schema.url);
            }

        },
        
        /**
         * Load template
         */
        loadTemplate: function(e) {
            e.preventDefault();
            
            const templateName = $(e.currentTarget).data('template');
            const self = this;
            
            $.ajax({
                url: schemafyBuilder.ajax_url,
                method: 'POST',
                data: {
                    action: 'schemafy_builder_get_template',
                    nonce: schemafyBuilder.nonce,
                    schema_type: this.currentSchemaType,
                    template_name: templateName
                },
                success: function(response) {
                    if (response.success) {
                        // Apply template default values
                        self.fieldValues = { ...self.fieldValues, ...response.data.defaultValues };
                        self.renderVisualForm();
                    }
                }
            });
        },
        
        /**
         * Save schema
         */
        saveSchema: function(e) {
            e.preventDefault();
            
            const $btn = $(e.currentTarget);
            const originalText = $btn.text();
            
            $btn.prop('disabled', true).text(schemafyBuilder.i18n.saving);
            
            // Convert to JSON
            const schemaJSON = JSON.stringify(this.fieldValuesToJSON());
            
            const self = this;
            
            $.ajax({
                url: schemafyBuilder.ajax_url,
                method: 'POST',
                data: {
                    action: 'schemafy_builder_save_schema',
                    nonce: schemafyBuilder.nonce,
                    schema_id: this.currentSchemaId,
                    schema_data: schemaJSON
                },
                success: function(response) {
                    if (response.success) {
                        $btn.text(schemafyBuilder.i18n.saved);
                        
                        if (response.data.id && !self.currentSchemaId) {
                            self.currentSchemaId = response.data.id;
                        }
                        
                        setTimeout(function() {
                            $btn.prop('disabled', false).text(originalText);
                        }, 2000);
                    } else {
                        alert(schemafyBuilder.i18n.error + ': ' + response.data);
                        $btn.prop('disabled', false).text(originalText);
                    }
                },
                error: function() {
                    alert(schemafyBuilder.i18n.error);
                    $btn.prop('disabled', false).text(originalText);
                }
            });
        }
    };
    
    // Initialize on document ready
    $(document).ready(function() {
        if (typeof schemafyBuilder !== 'undefined') {
            SchemafyBuilder.App.init();
        }
    });
    
})(jQuery);
