<?php
/**
 * 247ChatMate — Remote Verticals Loader
 * Canonical source of vertical definitions
 * Version-safe, network-safe, fail-closed
 * Catalog authority comes from remote JSON
 * No legacy category injection
 */

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

/**
 * Detect narrow admin settings contexts where the vertical catalogue must stay local-only.
 *
 * This intentionally avoids remote JSON and diagnostics writes while the settings
 * screen is saving or reloading. Cached/local catalogue data can still be used
 * so valid saved vertical selections are not clamped back to the fallback.
 *
 * @return bool
 */
if ( ! function_exists( 'matewa_is_admin_settings_vertical_guard_context' ) ) {
	function matewa_is_admin_settings_vertical_guard_context() {
		if ( ! is_admin() ) {
			return false;
		}

		$page = '';
		if ( isset( $_GET['page'] ) ) {
			$page = sanitize_key( wp_unslash( $_GET['page'] ) );
		}

		if ( '247chatmate' === $page && ( ! function_exists( 'wp_doing_ajax' ) || ! wp_doing_ajax() ) && empty( $_POST ) ) {
			return false;
		}

		return true;
	}
}

/**
 * Persist narrow diagnostics for vertical loading.
 *
 * @param array $data
 * @return void
 */
if ( ! function_exists( 'matewa_store_verticals_diagnostic' ) ) {
	function matewa_store_verticals_diagnostic( $data ) {
		if ( ! is_array( $data ) ) {
			return;
		}

		// Recovery pass: never write vertical diagnostics during admin requests.
		// Settings saves/renders must not trigger extra update_option() calls.
		if ( is_admin() ) {
			return;
		}

		if (
			function_exists( 'matewa_is_admin_settings_vertical_guard_context' ) &&
			matewa_is_admin_settings_vertical_guard_context()
		) {
			return;
		}

		$defaults = array(
			'timestamp'       => gmdate( 'c' ),
			'resolver_mode'   => '',
			'cache_key'       => '',
			'url'             => '',
			'result'          => '',
			'reason'          => '',
			'response_code'   => '',
			'payload_version' => '',
			'vertical_count'  => 0,
		);

		update_option(
			'matewa_verticals_last_diagnostic',
			array_merge( $defaults, $data ),
			false
		);
	}
}

/**
 * Helper: sanitize a key-like value safely.
 *
 * @param mixed  $value
 * @param string $fallback
 * @return string
 */
if ( ! function_exists( 'matewa_catalog_safe_key' ) ) {
	function matewa_catalog_safe_key( $value, $fallback = '' ) {
		$value = is_string( $value ) || is_numeric( $value ) ? trim( (string) $value ) : '';
		$value = sanitize_key( $value );

		return '' !== $value ? $value : sanitize_key( (string) $fallback );
	}
}

/**
 * Helper: sanitize visible text safely.
 *
 * @param mixed  $value
 * @param string $fallback
 * @return string
 */
if ( ! function_exists( 'matewa_catalog_safe_text' ) ) {
	function matewa_catalog_safe_text( $value, $fallback = '' ) {
		if ( is_string( $value ) || is_numeric( $value ) ) {
			$value = trim( wp_strip_all_tags( (string) $value ) );
			$value = preg_replace( '/\s+/u', ' ', $value );

			if ( '' !== $value ) {
				return (string) $value;
			}
		}

		return (string) $fallback;
	}
}

/**
 * Helper: format machine keys into visible labels while preserving common acronyms.
 *
 * @param string $value
 * @param string $fallback
 * @return string
 */
if ( ! function_exists( 'matewa_catalog_format_key_label' ) ) {
	function matewa_catalog_format_key_label( $value, $fallback = 'General' ) {
		$value = is_string( $value ) ? trim( $value ) : '';

		if ( '' === $value ) {
			return $fallback;
		}

		$value = str_replace( array( 'intent.', 'vertical.' ), '', $value );
		$value = str_replace( array( '_', '-' ), ' ', $value );
		$value = preg_replace( '/\s+/u', ' ', $value );
		$value = trim( (string) $value );

		if ( '' === $value ) {
			return $fallback;
		}

		$words       = preg_split( '/\s+/u', strtolower( $value ) );
		$upper_words = array(
			'hgv',
			'mot',
			'cbt',
			'das',
			'cpc',
			'seo',
			'ppc',
			'vat',
			'ev',
			'gp',
			'it',
			'ai',
			'av',
			'tv',
			'cctv',
			'wifi',
			'voip',
			'epos',
		);

		$out = array();

		if ( is_array( $words ) ) {
			foreach ( $words as $word ) {
				$word = trim( (string) $word );

				if ( '' === $word ) {
					continue;
				}

				if ( in_array( strtolower( $word ), $upper_words, true ) ) {
					$out[] = strtoupper( $word );
					continue;
				}

				$out[] = ucfirst( $word );
			}
		}

		$label = trim( implode( ' ', $out ) );

		return '' !== $label ? $label : $fallback;
	}
}

/**
 * Central visible chip label authority.
 * Keys remain machine-safe. Values are user-facing.
 *
 * @return array
 */
if ( ! function_exists( 'matewa_catalog_intent_label_authority' ) ) {
	function matewa_catalog_intent_label_authority() {
		return array(

			// Existing explicit normalization fixes
			'intent.driveway_cleaning'      => 'Driveway cleaning',
			'intent.patio_cleaning'         => 'Patio cleaning',
			'intent.render_cleaning'        => 'Render cleaning',
			'intent.room_info'              => 'Room info',
			'intent.special_request'        => 'Special request',
			'intent.urgent_help'            => 'Urgent help',

			// Stable common wording
			'intent.quote'                  => 'Get a quote',
			'intent.quote_request'          => 'Get a quote',
			'intent.pricing'                => 'Pricing',
			'intent.availability'           => 'Availability',
			'intent.location'               => 'Location',
			'intent.site_visit'             => 'Site visit',
			'intent.same_day_service'       => 'Same-day service',
			'intent.same_day_quote'         => 'Same-day quote',
			'intent.book_job'               => 'Book a job',
			'intent.ask_question'           => 'Ask a question',
			'intent.recovery'               => 'Recovery',
			'intent.breakdown'              => 'Breakdown',
			'intent.vehicle_fault'          => 'Vehicle fault',
			'intent.battery_help'           => 'Battery help',
			'intent.roadside_help'          => 'Roadside help',

			// Driving / training
			'intent.manual_lessons'         => 'Manual lessons',
			'intent.automatic_lessons'      => 'Automatic lessons',
			'intent.intensive_course'       => 'Intensive course',
			'intent.test_preparation'       => 'Test preparation',
			'intent.refresher_lessons'      => 'Refresher lessons',
			'intent.cbt_training'           => 'CBT training',
			'intent.das_training'           => 'DAS training',
			'intent.bike_test_prep'         => 'Bike test prep',
			'intent.gear_advice'            => 'Gear advice',
			'intent.class_1_training'       => 'Class 1 training',
			'intent.class_2_training'       => 'Class 2 training',
			'intent.cpc_training'           => 'CPC training',
			'intent.theory_support'         => 'Theory support',
			'intent.refresher_training'     => 'Refresher training',

			// Tree services
			'intent.tree_pruning'           => 'Tree pruning',
			'intent.tree_removal'           => 'Tree removal',
			'intent.stump_grinding'         => 'Stump grinding',
			'intent.hedge_cutting'          => 'Hedge cutting',
			'intent.emergency_tree_work'    => 'Emergency tree work',

			// Minimal fit fixes for long installation chips
			'intent.floor_installation'     => 'New flooring',
			'intent.kitchen_installation'   => 'New kitchen',
			'intent.bathroom_installation'  => 'New bathroom',
			'intent.driveway_installation'  => 'New driveway',
			'intent.patio_installation'     => 'New patio',
			'intent.window_installation'    => 'New windows',
			'intent.door_installation'      => 'New doors',

			// A few key acronym / UX fixes from current catalog
			'intent.mot_booking'            => 'MOT booking',
			'intent.ev_charger'             => 'EV charger',
			'intent.ev_charging'            => 'EV charging',
			'intent.cctv_survey'            => 'CCTV survey',
			'intent.lasting_power_of_attorney' => 'Lasting power of attorney',
			'intent.vat_support'            => 'VAT support',
			'intent.one_to_one_training'    => '1-to-1 training',
			'intent.in_person_session'      => 'In-person session',
			'intent.online_session'         => 'Online session',
			'intent.online_lessons'         => 'Online lessons',
			'intent.online_coaching'        => 'Online coaching',

			// Agency, technical trade and creative verticals — Phase 5-A-14K
			'intent.add_client_sites' => 'Add client sites',
			'intent.agency_pricing' => 'Agency pricing',
			'intent.book_agency_demo' => 'Book agency demo',
			'intent.client_lead_examples' => 'Client lead examples',
			'intent.white_label_options' => 'White-label options',
			'intent.fix_poor_tv_signal' => 'Fix poor TV signal',
			'intent.install_new_aerial' => 'Install new aerial',
			'intent.fix_satellite_dish' => 'Fix satellite dish',
			'intent.add_extra_tv_points' => 'Add extra TV points',
			'intent.book_visit' => 'Book a visit',
			'intent.fix_wifi_connection' => 'Fix Wi-Fi connection',
			'intent.improve_coverage' => 'Improve coverage',
			'intent.garden_room_wifi' => 'Garden room Wi-Fi',
			'intent.add_network_points' => 'Add network points',
			'intent.book_survey' => 'Book a survey',
			'intent.mount_my_tv' => 'Mount my TV',
			'intent.home_cinema_setup' => 'Home cinema setup',
			'intent.smart_home_setup' => 'Set up smart home',
			'intent.audio_installation' => 'Audio installation',
			'intent.book_quote' => 'Book a quote',
			'intent.install_cctv' => 'Install CCTV',
			'intent.install_alarm' => 'Install alarm',
			'intent.repair_security_system' => 'Repair security system',
			'intent.upgrade_system' => 'Upgrade system',
			'intent.urgent_it_support' => 'Urgent IT support',
			'intent.set_up_device' => 'Set up device',
			'intent.business_it_support' => 'Business IT support',
			'intent.managed_it_plan' => 'Managed IT plan',
			'intent.book_support_session' => 'Book support session',
			'intent.new_website_design' => 'New website design',
			'intent.logo_or_branding' => 'Logo or branding',
			'intent.design_project' => 'Design project',
			'intent.website_updates' => 'Website updates',
			'intent.request_quote' => 'Request a quote',
			'intent.shop_signage' => 'Shop signage',
			'intent.vehicle_graphics' => 'Vehicle graphics',
			'intent.window_graphics' => 'Window graphics',
			'intent.design_print' => 'Design & print',

			// Childcare & early years
			'intent.after_school_places' => 'After-school places',
			'intent.age_groups' => 'Age groups',
			'intent.assessment_call' => 'Assessment call',
			'intent.before_after_school' => 'Before/after school',
			'intent.book_call' => 'Book a call',
			'intent.book_session' => 'Book a session',
			'intent.childcare_places' => 'Childcare places',
			'intent.class_times' => 'Class times',
			'intent.consultation' => 'Consultation',
			'intent.dates_times' => 'Dates & times',
			'intent.fees' => 'Fees',
			'intent.fees_funding' => 'Fees & funding',
			'intent.holiday_club_places' => 'Holiday club places',
			'intent.nanny_enquiry' => 'Nanny enquiry',
			'intent.preschool_places' => 'Preschool places',
			'intent.requirements' => 'Requirements',
			'intent.school_pickup' => 'School pickup',
			'intent.support_needs' => 'Support needs',
			'intent.term_times' => 'Term times',
			'intent.opening_hours' => 'Opening hours',

			// Final chip
			'intent.other'                  => 'Something else',
		);
	}
}

/**
 * Central visible vertical label authority.
 *
 * @return array
 */
if ( ! function_exists( 'matewa_catalog_vertical_label_authority' ) ) {
	function matewa_catalog_vertical_label_authority() {
		return array(
			'vertical.tree_surgeon'               => 'Tree Surgeon',
			'vertical.hvac'                       => 'HVAC',
			'vertical.ev_charging_installation'   => 'EV Charging Installation',
			'vertical.solar_pv'                   => 'Solar PV',
			'vertical.mot_garage'                 => 'MOT Garage',
			'vertical.it_services'                => 'IT Services',
			'vertical.private_gp'                 => 'Private GP',
			'vertical.driving_instructor_hgv'     => 'Driving Instructor HGV',

			// Agency, technical trade and creative verticals — Phase 5-A-14K
			'vertical.agency' => 'Agency',
			'vertical.web_design_agency' => 'Web Design Agency',
			'vertical.wordpress_agency' => 'WordPress Agency',
			'vertical.seo_agency' => 'SEO Agency',
			'vertical.ppc_agency' => 'PPC Agency',
			'vertical.local_marketing_agency' => 'Local Marketing Agency',
			'vertical.trades_marketing_agency' => 'Trades Marketing Agency',
			'vertical.website_maintenance_agency' => 'Website Maintenance Agency',
			'vertical.ai_automation_agency' => 'AI Automation Agency',
			'vertical.branding_agency' => 'Branding Agency',
			'vertical.graphic_design_agency' => 'Graphic Design Agency',
			'vertical.signage_agency' => 'Signage Agency',
			'vertical.aerial_installer' => 'Aerial Installer',
			'vertical.satellite_installer' => 'Satellite Installer',
			'vertical.tv_aerial_repairs' => 'TV Aerial Repairs',
			'vertical.tv_wall_mounting' => 'TV Wall Mounting',
			'vertical.extra_tv_points' => 'Extra TV Points',
			'vertical.home_networking' => 'Home Networking',
			'vertical.wifi_installation' => 'WiFi Installation',
			'vertical.wifi_repair' => 'WiFi Repair',
			'vertical.garden_room_wifi' => 'Garden Room WiFi',
			'vertical.network_cabling' => 'Network Cabling',
			'vertical.data_cabling_contractor' => 'Data Cabling Contractor',
			'vertical.office_cabling' => 'Office Cabling',
			'vertical.home_av_installer' => 'Home AV Installer',
			'vertical.commercial_av_installer' => 'Commercial AV Installer',
			'vertical.smart_home_installer' => 'Smart Home Installer',
			'vertical.home_cinema_installer' => 'Home Cinema Installer',
			'vertical.media_wall_installer' => 'Media Wall Installer',
			'vertical.audio_installer' => 'Audio Installer',
			'vertical.cctv_installer' => 'CCTV Installer',
			'vertical.alarm_installer' => 'Alarm Installer',
			'vertical.access_control' => 'Access Control',
			'vertical.door_entry_systems' => 'Door Entry Systems',
			'vertical.electric_gates' => 'Electric Gates',
			'vertical.security_system_repairs' => 'Security System Repairs',
			'vertical.it_support' => 'IT Support',
			'vertical.managed_it_services' => 'Managed IT Services',
			'vertical.computer_repair' => 'Computer Repair',
			'vertical.laptop_repair' => 'Laptop Repair',
			'vertical.business_it_support' => 'Business IT Support',
			'vertical.voip_installer' => 'VoIP Installer',
			'vertical.cybersecurity_consultant' => 'Cybersecurity Consultant',
			'vertical.epos_installer' => 'EPOS Installer',
			'vertical.web_design' => 'Web Design',
			'vertical.graphic_design' => 'Graphic Design',
			'vertical.branding_design' => 'Branding Design',
			'vertical.logo_design' => 'Logo Design',
			'vertical.website_maintenance' => 'Website Maintenance',
			'vertical.seo_services' => 'SEO Services',
			'vertical.content_design' => 'Content Design',
			'vertical.marketing_design' => 'Marketing Design',
			'vertical.signage' => 'Signage',
			'vertical.vehicle_graphics' => 'Vehicle Graphics',
			'vertical.vehicle_wraps' => 'Vehicle Wraps',
			'vertical.shop_signage' => 'Shop Signage',
			'vertical.window_graphics' => 'Window Graphics',
			'vertical.exhibition_graphics' => 'Exhibition Graphics',
			'vertical.print_design' => 'Print Design',
			'vertical.workwear_printing' => 'Workwear Printing',

			// Childcare & early years verticals
			'vertical.after_school_club' => 'After-School Club',
			'vertical.baby_toddler_classes' => 'Baby & Toddler Classes',
			'vertical.childcare_provider' => 'Childcare Provider',
			'vertical.childminder' => 'Childminder',
			'vertical.day_nursery' => 'Day Nursery',
			'vertical.holiday_club' => 'Holiday Club',
			'vertical.nanny_agency' => 'Nanny Agency',
			'vertical.preschool' => 'Preschool',
			'vertical.send_support_provider' => 'SEND Support Provider',
			'vertical.wraparound_care' => 'Wraparound Care',
		);
	}
}

/**
 * Resolve a visible label for a chip intent key.
 *
 * @param string $intent_key
 * @return string
 */
if ( ! function_exists( 'matewa_catalog_resolve_intent_label' ) ) {
	function matewa_catalog_resolve_intent_label( $intent_key ) {
		$intent_key = is_string( $intent_key ) ? trim( $intent_key ) : '';
		$labels     = matewa_catalog_intent_label_authority();

		if ( '' !== $intent_key && isset( $labels[ $intent_key ] ) && '' !== $labels[ $intent_key ] ) {
			return (string) $labels[ $intent_key ];
		}

		return matewa_catalog_format_key_label( $intent_key, 'Something else' );
	}
}

/**
 * Resolve a visible label for a vertical key.
 *
 * @param string $vertical_key
 * @param string $label_key
 * @return string
 */
if ( ! function_exists( 'matewa_catalog_resolve_vertical_label' ) ) {
	function matewa_catalog_resolve_vertical_label( $vertical_key, $label_key = '' ) {
		$vertical_key = is_string( $vertical_key ) ? trim( $vertical_key ) : '';
		$label_key    = is_string( $label_key ) ? trim( $label_key ) : '';
		$labels       = matewa_catalog_vertical_label_authority();

		if ( '' !== $label_key && isset( $labels[ $label_key ] ) && '' !== $labels[ $label_key ] ) {
			return (string) $labels[ $label_key ];
		}

		return matewa_catalog_format_key_label( $vertical_key, 'General' );
	}
}

/**
 * Return generic fill intents for malformed catalogs.
 *
 * @return array
 */
if ( ! function_exists( 'matewa_catalog_generic_fill_intents' ) ) {
	function matewa_catalog_generic_fill_intents() {
		return array(
			'intent.quote',
			'intent.pricing',
			'intent.availability',
			'intent.ask_question',
			'intent.book_job',
		);
	}
}

/**
 * Normalize a chip list:
 * - max 6 total
 * - final chip always intent.other
 * - chips 1-5 always populated
 *
 * @param array $chips
 * @return array
 */
if ( ! function_exists( 'matewa_catalog_normalize_chip_list' ) ) {
	function matewa_catalog_normalize_chip_list( $chips ) {
		$normalized = array();

		if ( is_array( $chips ) ) {
			foreach ( $chips as $chip ) {
				if ( is_string( $chip ) ) {
					$chip = trim( $chip );

					if ( '' !== $chip ) {
						$normalized[] = $chip;
					}
				}
			}
		}

		$normalized = array_values(
			array_filter(
				$normalized,
				static function( $chip ) {
					return 'intent.other' !== $chip;
				}
			)
		);

		$normalized = array_slice( $normalized, 0, 5 );

		$fills = matewa_catalog_generic_fill_intents();

		foreach ( $fills as $fill ) {
			if ( count( $normalized ) >= 5 ) {
				break;
			}

			if ( ! in_array( $fill, $normalized, true ) ) {
				$normalized[] = $fill;
			}
		}

		while ( count( $normalized ) < 5 ) {
			$normalized[] = 'intent.quote';
		}

		$normalized[] = 'intent.other';

		return array_values( $normalized );
	}
}

/**
 * Normalize categories:
 * - category labels cleaned
 * - category vertical keys cleaned
 * - only keep vertical references that exist
 * - preserve payload authority; do not inject legacy branches
 *
 * @param array $categories
 * @param array $verticals
 * @return array
 */
if ( ! function_exists( 'matewa_catalog_normalize_categories' ) ) {
	function matewa_catalog_normalize_categories( $categories, $verticals ) {
		$categories = is_array( $categories ) ? $categories : array();
		$verticals  = is_array( $verticals ) ? $verticals : array();

		$out = array();

		foreach ( $categories as $category_key => $category_config ) {
			$category_key = matewa_catalog_safe_key( $category_key );

			if ( '' === $category_key ) {
				continue;
			}

			$category_config = is_array( $category_config ) ? $category_config : array();

			$label = matewa_catalog_safe_text(
				isset( $category_config['label'] ) ? $category_config['label'] : '',
				matewa_catalog_format_key_label( $category_key, 'General' )
			);

			$refs = isset( $category_config['verticals'] ) && is_array( $category_config['verticals'] )
				? $category_config['verticals']
				: array();

			$valid_refs = array();

			foreach ( $refs as $vertical_key ) {
				$vertical_key = matewa_catalog_safe_key( $vertical_key );

				if ( '' === $vertical_key ) {
					continue;
				}

				if ( ! isset( $verticals[ $vertical_key ] ) ) {
					continue;
				}

				$valid_refs[ $vertical_key ] = $vertical_key;
			}

			$out[ $category_key ] = array(
				'label'     => $label,
				'verticals' => array_values( $valid_refs ),
			);
		}

		if ( empty( $out ) ) {
			$out['general'] = array(
				'label'     => 'General',
				'verticals' => isset( $verticals['general'] ) ? array( 'general' ) : array(),
			);
		}

		return $out;
	}
}

/**
 * Apply controlled catalog normalization.
 * Trust the remote payload as authority.
 * Do not inject legacy categories or legacy vertical aliases.
 *
 * @param array $data
 * @return array
 */
if ( ! function_exists( 'matewa_catalog_apply_controlled_normalisation' ) ) {
	function matewa_catalog_apply_controlled_normalisation( $data ) {
		if ( ! is_array( $data ) ) {
			$data = array();
		}

		if ( empty( $data['version'] ) ) {
			$data['version'] = '1.2-main';
		}

		$default_vertical = matewa_catalog_safe_key(
			isset( $data['default_vertical'] ) ? $data['default_vertical'] : 'general',
			'general'
		);

		$data['default_vertical'] = '' !== $default_vertical ? $default_vertical : 'general';

		if ( empty( $data['rules'] ) || ! is_array( $data['rules'] ) ) {
			$data['rules'] = array();
		}

		$data['rules']['max_chips']             = 6;
		$data['rules']['ensure_other_last']     = true;
		$data['rules']['other_intent_key']      = 'intent.other';
		$data['rules']['other_type']            = isset( $data['rules']['other_type'] ) ? $data['rules']['other_type'] : 'service';
		$data['rules']['other_encourage_notes'] = array_key_exists( 'other_encourage_notes', $data['rules'] ) ? (bool) $data['rules']['other_encourage_notes'] : true;

		$input_verticals = isset( $data['verticals'] ) && is_array( $data['verticals'] )
			? $data['verticals']
			: array();

		$normalized_verticals = array();

		foreach ( $input_verticals as $vertical_key => $vertical_config ) {
			$vertical_key = matewa_catalog_safe_key( $vertical_key );

			if ( '' === $vertical_key ) {
				continue;
			}

			$vertical_config = is_array( $vertical_config ) ? $vertical_config : array();

			$label_key = matewa_catalog_safe_text(
				isset( $vertical_config['label_key'] ) ? $vertical_config['label_key'] : '',
				'vertical.' . $vertical_key
			);

			$chips = isset( $vertical_config['chips'] ) && is_array( $vertical_config['chips'] )
				? $vertical_config['chips']
				: array();

			$dropdown = isset( $vertical_config['dropdown'] ) && is_array( $vertical_config['dropdown'] )
				? $vertical_config['dropdown']
				: array();

			$rules = isset( $vertical_config['rules'] ) && is_array( $vertical_config['rules'] )
				? $vertical_config['rules']
				: array();

			$search_terms = isset( $vertical_config['search_terms'] ) && is_array( $vertical_config['search_terms'] )
				? array_values( array_filter( array_map( 'matewa_catalog_safe_text', $vertical_config['search_terms'] ) ) )
				: array();

			$normalized_verticals[ $vertical_key ] = array(
				'label_key'    => $label_key,
				'chips'        => matewa_catalog_normalize_chip_list( $chips ),
				'dropdown'     => $dropdown,
				'rules'        => $rules,
				'search_terms' => $search_terms,
			);
		}

		if ( ! isset( $normalized_verticals['general'] ) ) {
			$normalized_verticals['general'] = array(
				'label_key' => 'vertical.general',
				'chips'     => array(
					'intent.quote',
					'intent.pricing',
					'intent.availability',
					'intent.ask_question',
					'intent.book_job',
					'intent.other',
				),
				'dropdown'  => array(),
				'rules'     => array(),
			);
		}

		$data['verticals'] = $normalized_verticals;

		$data['categories'] = matewa_catalog_normalize_categories(
			isset( $data['categories'] ) ? $data['categories'] : array(),
			$data['verticals']
		);

		if ( ! isset( $data['verticals'][ $data['default_vertical'] ] ) ) {
			if ( isset( $data['verticals']['general'] ) ) {
				$data['default_vertical'] = 'general';
			} else {
				$keys = array_keys( $data['verticals'] );
				$data['default_vertical'] = ! empty( $keys ) ? (string) $keys[0] : 'general';
			}
		}

		return $data;
	}
}

/**
 * Resolve which remote payload should be used.
 *
 * Routing model:
 * - free           => free payload
 * - trial_expired  => free payload
 * - trial_active   => main payload
 * - pro            => main payload
 * - master         => main payload
 *
 * @return array
 */
function matewa_resolve_vertical_source() {
	static $resolved_source = null;

	if ( is_array( $resolved_source ) ) {
		return $resolved_source;
	}

	// Use the effective runtime mode so Founder QA and downgrade states
	// resolve the same catalogue as the live widget.
	$mode = function_exists( 'matewa_get_mode' )
		? matewa_get_mode()
		: ( function_exists( 'matewa_license_status' ) ? matewa_license_status() : MATEWA_MODE_FREE );

	$is_free_like = in_array(
		$mode,
		array(
			MATEWA_MODE_FREE,
			MATEWA_MODE_TRIAL_EXPIRED,
		),
		true
	);

	$full_catalogue_url = 'https://247trademate.pro/247chatmate/vertical-packs/full-catalogue.json';

	$resolved_source = array(
		'mode'      => $is_free_like ? 'free' : 'main',
		// Catalogue data is identical for Free, Trial and Pro. Use a URL-specific
		// namespace so legacy 289-vertical transients can never shadow this source.
		'cache_key' => 'matewa_remote_verticals_full_' . substr( md5( $full_catalogue_url ), 0, 12 ),
		'url'       => $full_catalogue_url,
		'fallback_url' => 'https://247trademate.pro/247chatmate/verticals.json',
	);

	return $resolved_source;
}

/**
 * Clear remote vertical transients.
 * Useful after changing remote catalog files.
 *
 * @return void
 */
if ( ! function_exists( 'matewa_clear_verticals_cache' ) ) {
	function matewa_clear_verticals_cache() {
		$full_catalogue_url = 'https://247trademate.pro/247chatmate/vertical-packs/full-catalogue.json';
		$modes = array(
			'matewa_remote_verticals_free',
			'matewa_remote_verticals_main',
			'matewa_remote_verticals_full_' . substr( md5( $full_catalogue_url ), 0, 12 ),
		);

		foreach ( $modes as $base_cache_key ) {
			$version_key    = $base_cache_key . '_version';
			$cached_version = get_transient( $version_key );

			if ( $cached_version ) {
				delete_transient( $base_cache_key . '_' . $cached_version );
			}

			delete_transient( $version_key );
		}
	}
}

/**
 * Merge optional remote vertical packs onto the canonical catalogue.
 *
 * Remote packs live beside the main catalogue under /247chatmate/vertical-packs/.
 * They are additive data only: product entitlement/locking remains local.
 *
 * @param array $data Canonical catalogue.
 * @return array
 */

/**
 * Fetch one remote vertical pack robustly.
 *
 * Tries the clean static URL first (best for Hostinger/static files), then a
 * cache-busted WordPress request, cURL and allow_url_fopen as fallbacks.
 * A validated last-known-good copy is retained locally.
 *
 * @param string $pack_url
 * @return array
 */
if ( ! function_exists( 'matewa_fetch_remote_vertical_pack_json' ) ) {
	function matewa_fetch_remote_vertical_pack_json( $pack_url ) {
		$pack_url = esc_url_raw( (string) $pack_url );

		if ( '' === $pack_url || 0 !== strpos( $pack_url, 'https://' ) ) {
			return array();
		}

		$cache_key = 'matewa_remote_vertical_pack_' . md5( $pack_url );
		$cached    = get_transient( $cache_key );
		$attempts  = array();

		$validate = static function ( $raw ) {
			if ( ! is_string( $raw ) || '' === trim( $raw ) ) {
				return array();
			}

			$decoded = json_decode( $raw, true );

			if (
				! is_array( $decoded ) ||
				empty( $decoded['verticals'] ) ||
				! is_array( $decoded['verticals'] )
			) {
				return array();
			}

			return $decoded;
		};

		$wp_args = array(
			'timeout'     => 10,
			'redirection' => 5,
			'sslverify'   => true,
			'user-agent'  => '247ChatMate/' . ( defined( 'MATEWA_VERSION' ) ? MATEWA_VERSION : 'unknown' ),
			'headers'     => array(
				'Accept' => 'application/json',
			),
		);

		// 1. Clean static URL first.
		$response = wp_remote_get( $pack_url, $wp_args );
		if ( ! is_wp_error( $response ) ) {
			$code = (int) wp_remote_retrieve_response_code( $response );
			$attempts[] = 'wp_clean:' . $code;

			if ( 200 === $code ) {
				$fresh = $validate( (string) wp_remote_retrieve_body( $response ) );
				if ( ! empty( $fresh ) ) {
					set_transient( $cache_key, $fresh, 6 * HOUR_IN_SECONDS );
					set_transient( $cache_key . '_diag', array(
						'status' => 'ok',
						'source' => 'wp_clean',
						'count'  => count( $fresh['verticals'] ),
						'time'   => time(),
					), DAY_IN_SECONDS );
					return $fresh;
				}
				$attempts[] = 'wp_clean:invalid_json';
			}
		} else {
			$attempts[] = 'wp_clean:error';
		}

		// 2. Cache-busted WP request.
		$busted_url = add_query_arg( array( '_matewa' => time() ), $pack_url );
		$response = wp_remote_get(
			$busted_url,
			array_merge(
				$wp_args,
				array(
					'headers' => array(
						'Accept'        => 'application/json',
						'Cache-Control' => 'no-cache',
						'Pragma'        => 'no-cache',
					),
				)
			)
		);

		if ( ! is_wp_error( $response ) ) {
			$code = (int) wp_remote_retrieve_response_code( $response );
			$attempts[] = 'wp_busted:' . $code;

			if ( 200 === $code ) {
				$fresh = $validate( (string) wp_remote_retrieve_body( $response ) );
				if ( ! empty( $fresh ) ) {
					set_transient( $cache_key, $fresh, 6 * HOUR_IN_SECONDS );
					set_transient( $cache_key . '_diag', array(
						'status' => 'ok',
						'source' => 'wp_busted',
						'count'  => count( $fresh['verticals'] ),
						'time'   => time(),
					), DAY_IN_SECONDS );
					return $fresh;
				}
				$attempts[] = 'wp_busted:invalid_json';
			}
		} else {
			$attempts[] = 'wp_busted:error';
		}

		// 3. Continue to the stream fallback below if both WordPress HTTP requests fail.

		// 4. allow_url_fopen fallback.
		if ( filter_var( ini_get( 'allow_url_fopen' ), FILTER_VALIDATE_BOOLEAN ) ) {
			$context = stream_context_create(
				array(
					'http' => array(
						'timeout' => 10,
						'header'  => "Accept: application/json\r\nUser-Agent: 247ChatMate/" . ( defined( 'MATEWA_VERSION' ) ? MATEWA_VERSION : 'unknown' ) . "\r\n",
					),
					'ssl' => array(
						'verify_peer'      => true,
						'verify_peer_name' => true,
					),
				)
			);

			$raw = @file_get_contents( $pack_url, false, $context );
			$attempts[] = is_string( $raw ) ? 'fopen:response' : 'fopen:error';

			$fresh = $validate( is_string( $raw ) ? $raw : '' );
			if ( ! empty( $fresh ) ) {
				set_transient( $cache_key, $fresh, 6 * HOUR_IN_SECONDS );
				set_transient( $cache_key . '_diag', array(
					'status' => 'ok',
					'source' => 'fopen',
					'count'  => count( $fresh['verticals'] ),
					'time'   => time(),
				), DAY_IN_SECONDS );
				return $fresh;
			}
		}

		if ( is_array( $cached ) && ! empty( $cached['verticals'] ) && is_array( $cached['verticals'] ) ) {
			set_transient( $cache_key . '_diag', array(
				'status'   => 'cached',
				'source'   => 'last_known_good',
				'count'    => count( $cached['verticals'] ),
				'attempts' => $attempts,
				'time'     => time(),
			), DAY_IN_SECONDS );
			return $cached;
		}

		set_transient( $cache_key . '_diag', array(
			'status'   => 'failed',
			'source'   => '',
			'count'    => 0,
			'attempts' => $attempts,
			'time'     => time(),
		), DAY_IN_SECONDS );

		return array();
	}
}

if ( ! function_exists( 'matewa_catalog_apply_remote_vertical_packs' ) ) {
	function matewa_catalog_apply_remote_vertical_packs( $data ) {
		$data = is_array( $data ) ? $data : array();

		$pack_urls = array(
			'https://247trademate.pro/247chatmate/vertical-packs/high-value.json',
		);

		foreach ( $pack_urls as $pack_url ) {
			$pack_url = esc_url_raw( (string) $pack_url );

			if ( '' === $pack_url || 0 !== strpos( $pack_url, 'https://' ) ) {
				continue;
			}

			$pack = matewa_fetch_remote_vertical_pack_json( $pack_url );

			if ( empty( $pack ) ) {
				continue;
			}

			foreach ( array( 'intent_labels', 'vertical_labels' ) as $label_group ) {
				if ( ! isset( $data[ $label_group ] ) || ! is_array( $data[ $label_group ] ) ) {
					$data[ $label_group ] = array();
				}

				if ( isset( $pack[ $label_group ] ) && is_array( $pack[ $label_group ] ) ) {
					$data[ $label_group ] = array_replace( $data[ $label_group ], $pack[ $label_group ] );
				}
			}

			if ( ! isset( $data['verticals'] ) || ! is_array( $data['verticals'] ) ) {
				$data['verticals'] = array();
			}
			$data['verticals'] = array_replace( $data['verticals'], $pack['verticals'] );

			if ( ! isset( $data['categories'] ) || ! is_array( $data['categories'] ) ) {
				$data['categories'] = array();
			}

			$pack_categories = isset( $pack['categories'] ) && is_array( $pack['categories'] ) ? $pack['categories'] : array();

			foreach ( $pack_categories as $category_key => $category_config ) {
				$category_key = matewa_catalog_safe_key( $category_key );

				if ( '' === $category_key || ! is_array( $category_config ) ) {
					continue;
				}

				$incoming_verticals = isset( $category_config['verticals'] ) && is_array( $category_config['verticals'] )
					? array_values( array_filter( array_map( 'sanitize_key', $category_config['verticals'] ) ) )
					: array();

				if ( isset( $data['categories'][ $category_key ] ) && is_array( $data['categories'][ $category_key ] ) ) {
					$existing_verticals = isset( $data['categories'][ $category_key ]['verticals'] ) && is_array( $data['categories'][ $category_key ]['verticals'] )
						? $data['categories'][ $category_key ]['verticals']
						: array();

					$data['categories'][ $category_key ] = array_merge(
						$data['categories'][ $category_key ],
						$category_config
					);
					$data['categories'][ $category_key ]['verticals'] = array_values(
						array_unique( array_merge( $existing_verticals, $incoming_verticals ) )
					);
				} else {
					$category_config['verticals'] = $incoming_verticals;
					$data['categories'][ $category_key ] = $category_config;
				}
			}
		}

		return matewa_catalog_apply_controlled_normalisation( $data );
	}
}

/**
 * Get vertical definitions (remote → cached → safe fallback).
 *
 * @return array
 */
function matewa_get_verticals() {
	static $request_cache = array();

	$source = matewa_resolve_vertical_source();

	$base_cache_key = $source['cache_key'];
	$version_key    = $base_cache_key . '_version';
	$request_key    = (string) $base_cache_key;

	if ( isset( $request_cache[ $request_key ] ) && is_array( $request_cache[ $request_key ] ) ) {
		return $request_cache[ $request_key ];
	}

	$cached_version = get_transient( $version_key );
	if ( $cached_version ) {
		$cached = get_transient( $base_cache_key . '_' . $cached_version );

		if ( $cached && is_array( $cached ) ) {
			$cached = matewa_catalog_apply_controlled_normalisation( $cached );

			matewa_store_verticals_diagnostic(
				array(
					'resolver_mode'   => (string) $source['mode'],
					'cache_key'       => (string) $base_cache_key,
					'url'             => (string) $source['url'],
					'result'          => 'cache_hit',
					'reason'          => 'cached_payload_returned',
					'payload_version' => (string) $cached_version,
					'vertical_count'  => isset( $cached['verticals'] ) && is_array( $cached['verticals'] ) ? count( $cached['verticals'] ) : 0,
				)
			);

			$cached = matewa_catalog_apply_controlled_normalisation( $cached );
			$request_cache[ $request_key ] = $cached;

			return $cached;
		}

		matewa_store_verticals_diagnostic(
			array(
				'resolver_mode'   => (string) $source['mode'],
				'cache_key'       => (string) $base_cache_key,
				'url'             => (string) $source['url'],
				'result'          => 'cache_miss_after_version_hit',
				'reason'          => 'version_transient_found_but_payload_missing',
				'payload_version' => (string) $cached_version,
			)
		);
	}

	if (
		function_exists( 'matewa_is_admin_settings_vertical_guard_context' ) &&
		matewa_is_admin_settings_vertical_guard_context()
	) {
		$fallback = matewa_catalog_apply_controlled_normalisation( matewa_verticals_fallback() );
		$request_cache[ $request_key ] = $fallback;

		return $fallback;
	}

	$source_request_url = add_query_arg(
		array(
			'plugin' => defined( 'MATEWA_VERSION' ) ? MATEWA_VERSION : 'unknown',
			'_matewa_verticals' => time(),
		),
		$source['url']
	);

	$request_args = array(
		'timeout'     => 10,
		'redirection' => 5,
		'sslverify'   => true,
		'user-agent'  => '247ChatMate/' . ( defined( 'MATEWA_VERSION' ) ? MATEWA_VERSION : 'unknown' ),
		'headers'     => array(
			'Accept'        => 'application/json',
			'Cache-Control' => 'no-cache',
			'Pragma'        => 'no-cache',
		),
	);

	$response = wp_remote_get( $source_request_url, $request_args );

	// Compatibility fallback only. The complete catalogue above remains canonical.
	if (
		is_wp_error( $response ) ||
		200 !== (int) wp_remote_retrieve_response_code( $response )
	) {
		$fallback_url = isset( $source['fallback_url'] ) ? esc_url_raw( (string) $source['fallback_url'] ) : '';
		if ( '' !== $fallback_url ) {
			$response = wp_remote_get(
				add_query_arg( array( '_matewa_verticals' => time() ), $fallback_url ),
				$request_args
			);
		}
	}

	if ( is_wp_error( $response ) ) {
		matewa_store_verticals_diagnostic(
			array(
				'resolver_mode' => (string) $source['mode'],
				'cache_key'     => (string) $base_cache_key,
				'url'           => (string) $source['url'],
				'result'        => 'fallback',
				'reason'        => 'wp_remote_get_error',
				'response_code' => '',
			)
		);

		$fallback = matewa_catalog_apply_controlled_normalisation( matewa_verticals_fallback() );
		$request_cache[ $request_key ] = $fallback;

		return $fallback;
	}

	$code = wp_remote_retrieve_response_code( $response );
	if ( 200 !== (int) $code ) {
		matewa_store_verticals_diagnostic(
			array(
				'resolver_mode' => (string) $source['mode'],
				'cache_key'     => (string) $base_cache_key,
				'url'           => (string) $source['url'],
				'result'        => 'fallback',
				'reason'        => 'non_200_response',
				'response_code' => (string) $code,
			)
		);

		$fallback = matewa_catalog_apply_controlled_normalisation( matewa_verticals_fallback() );
		$request_cache[ $request_key ] = $fallback;

		return $fallback;
	}

	$body = wp_remote_retrieve_body( $response );
	$data = json_decode( $body, true );

	if (
		! is_array( $data ) ||
		empty( $data['version'] ) ||
		empty( $data['verticals'] ) ||
		! is_array( $data['verticals'] )
	) {
		matewa_store_verticals_diagnostic(
			array(
				'resolver_mode' => (string) $source['mode'],
				'cache_key'     => (string) $base_cache_key,
				'url'           => (string) $source['url'],
				'result'        => 'fallback',
				'reason'        => 'invalid_json_payload',
				'response_code' => (string) $code,
			)
		);

		$fallback = matewa_catalog_apply_controlled_normalisation( matewa_verticals_fallback() );
		$request_cache[ $request_key ] = $fallback;

		return $fallback;
	}

	$data = matewa_catalog_apply_controlled_normalisation( $data );

	$default = isset( $data['default_vertical'] ) ? $data['default_vertical'] : 'general';

	if ( ! isset( $data['verticals'][ $default ] ) ) {
		$default                  = 'general';
		$data['default_vertical'] = $default;
	}

	$version = (string) $data['version'];

	set_transient( $base_cache_key . '_' . $version, $data, 15 * MINUTE_IN_SECONDS );
	set_transient( $version_key, $version, 15 * MINUTE_IN_SECONDS );

	matewa_store_verticals_diagnostic(
		array(
			'resolver_mode'   => (string) $source['mode'],
			'cache_key'       => (string) $base_cache_key,
			'url'             => (string) $source['url'],
			'result'          => 'remote_success',
			'reason'          => 'remote_payload_loaded',
			'response_code'   => (string) $code,
			'payload_version' => $version,
			'vertical_count'  => count( $data['verticals'] ),
		)
	);

	$request_cache[ $request_key ] = $data;

	return $data;
}

/**
 * Get one vertical config by key, safely.
 *
 * @param string $vertical_key
 * @return array
 */
if ( ! function_exists( 'matewa_get_vertical_config' ) ) {
	function matewa_get_vertical_config( $vertical_key ) {
		$data         = matewa_get_verticals();
		$verticals    = isset( $data['verticals'] ) && is_array( $data['verticals'] ) ? $data['verticals'] : array();
		$vertical_key = is_string( $vertical_key ) ? trim( $vertical_key ) : '';

		if ( '' !== $vertical_key && isset( $verticals[ $vertical_key ] ) && is_array( $verticals[ $vertical_key ] ) ) {
			return $verticals[ $vertical_key ];
		}

		$default = isset( $data['default_vertical'] ) && is_string( $data['default_vertical'] )
			? $data['default_vertical']
			: 'general';

		if ( isset( $verticals[ $default ] ) && is_array( $verticals[ $default ] ) ) {
			return $verticals[ $default ];
		}

		if ( isset( $verticals['general'] ) && is_array( $verticals['general'] ) ) {
			return $verticals['general'];
		}

		return array(
			'label_key' => 'vertical.general',
			'chips'     => array(
				'intent.quote',
				'intent.pricing',
				'intent.availability',
				'intent.ask_question',
				'intent.book_job',
				'intent.other',
			),
			'dropdown'  => array(),
			'rules'     => array(),
		);
	}
}

/**
 * Resolve the active vertical safely.
 *
 * @return array
 */
function matewa_get_active_vertical() {
	$data      = matewa_get_verticals();
	$verticals = isset( $data['verticals'] ) && is_array( $data['verticals'] ) ? $data['verticals'] : array();
	$default   = isset( $data['default_vertical'] ) ? $data['default_vertical'] : 'general';

	$selected = get_option( 'matewa_vertical_selected', '' );
	$selected = is_string( $selected ) ? trim( $selected ) : '';

	if ( '' !== $selected && isset( $verticals[ $selected ] ) ) {
		return $verticals[ $selected ];
	}

	if ( isset( $verticals[ $default ] ) ) {
		return $verticals[ $default ];
	}

	return isset( $verticals['general'] )
		? $verticals['general']
		: array(
			'label_key' => 'vertical.general',
			'chips'     => array(
				'intent.quote',
				'intent.pricing',
				'intent.availability',
				'intent.ask_question',
				'intent.book_job',
				'intent.other',
			),
			'dropdown'  => array(),
			'rules'     => array(),
		);
}

/**
 * Resolve the active vertical key safely.
 *
 * @return string
 */
if ( ! function_exists( 'matewa_get_active_vertical_key' ) ) {
	function matewa_get_active_vertical_key() {
		$data      = matewa_get_verticals();
		$verticals = isset( $data['verticals'] ) && is_array( $data['verticals'] ) ? $data['verticals'] : array();
		$default   = isset( $data['default_vertical'] ) ? $data['default_vertical'] : 'general';

		$selected = get_option( 'matewa_vertical_selected', '' );
		$selected = is_string( $selected ) ? trim( $selected ) : '';

		if ( '' !== $selected && isset( $verticals[ $selected ] ) ) {
			return $selected;
		}

		if ( isset( $verticals[ $default ] ) ) {
			return (string) $default;
		}

		if ( isset( $verticals['general'] ) ) {
			return 'general';
		}

		$keys = array_keys( $verticals );

		if ( ! empty( $keys ) ) {
			return (string) $keys[0];
		}

		return 'general';
	}
}

/**
 * Get visible default chip labels for a vertical.
 * This is what the widget/admin preview/editor defaults should use.
 *
 * @param string $vertical_key
 * @return array
 */
if ( ! function_exists( 'matewa_get_vertical_chip_labels' ) ) {
	function matewa_get_vertical_chip_labels( $vertical_key ) {
		$config = matewa_get_vertical_config( $vertical_key );
		$chips  = isset( $config['chips'] ) && is_array( $config['chips'] ) ? $config['chips'] : array();

		$labels = array();

		foreach ( $chips as $intent_key ) {
			$labels[] = matewa_catalog_resolve_intent_label( (string) $intent_key );
		}

		return $labels;
	}
}

if ( ! function_exists( 'matewa_get_effective_vertical_chip_labels' ) ) {
	function matewa_get_effective_vertical_chip_labels( $vertical_key ) {
		$vertical_key = matewa_catalog_safe_key( $vertical_key, 'general' );

		$config = matewa_get_vertical_config( $vertical_key );
		$chips  = isset( $config['chips'] ) && is_array( $config['chips'] ) ? $config['chips'] : array();

		$overrides = get_option( 'matewa_chip_label_overrides', array() );
		$overrides = is_array( $overrides ) ? $overrides : array();

		$vertical_overrides = isset( $overrides[ $vertical_key ] ) && is_array( $overrides[ $vertical_key ] )
			? $overrides[ $vertical_key ]
			: array();

		$labels = array();

		foreach ( $chips as $intent_key ) {
			$intent_key = is_string( $intent_key ) ? trim( $intent_key ) : '';

			$override_label = '';
			if ( '' !== $intent_key && isset( $vertical_overrides[ $intent_key ] ) ) {
				$override_label = trim( (string) $vertical_overrides[ $intent_key ] );
			}

			if ( '' !== $override_label ) {
				$labels[] = $override_label;
			} else {
				$labels[] = matewa_catalog_resolve_intent_label( $intent_key );
			}
		}

		return $labels;
	}
}

/**
 * Get visible effective chip labels for the active vertical.
 *
 * @return array
 */
if ( ! function_exists( 'matewa_get_active_vertical_chip_labels' ) ) {
	function matewa_get_active_vertical_chip_labels() {
		return matewa_get_effective_vertical_chip_labels( matewa_get_active_vertical_key() );
	}
}

/**
 * Get visible vertical label for a vertical key.
 *
 * @param string $vertical_key
 * @return string
 */
if ( ! function_exists( 'matewa_get_vertical_display_label' ) ) {
	function matewa_get_vertical_display_label( $vertical_key ) {
		$config    = matewa_get_vertical_config( $vertical_key );
		$label_key = isset( $config['label_key'] ) ? (string) $config['label_key'] : '';

		return matewa_catalog_resolve_vertical_label( $vertical_key, $label_key );
	}
}

/**
 * Absolute safety fallback.
 * This must NEVER fail.
 *
 * @return array
 */
function matewa_verticals_fallback() {
	$fallback = array(
		'version'          => '1.2-fallback',
		'default_vertical' => 'general',
		'categories'       => array(
			'general' => array(
				'label'     => 'General',
				'verticals' => array( 'general' ),
			),
		),
		'verticals'        => array(
			'general' => array(
				'label_key' => 'vertical.general',
				'chips'     => array(
					'intent.quote',
					'intent.pricing',
					'intent.availability',
					'intent.ask_question',
					'intent.book_job',
					'intent.other',
				),
				'dropdown'  => array(),
				'rules'     => array(),
			),
		),
		'rules'            => array(
			'max_chips'             => 6,
			'ensure_other_last'     => true,
			'other_intent_key'      => 'intent.other',
			'other_type'            => 'service',
			'other_encourage_notes' => true,
		),
	);

	return matewa_catalog_apply_controlled_normalisation( $fallback );
}