<?php
/**
 * Business logic service for Organization schema data
 *
 * Handles all organization-related CRUD operations, validation, and field definitions.
 * No UI logic here — this is pure business logic for settings management.
 *
 * @package BW_Schema
 * @since 3.0.0-babel
 */

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

class BW_Schema_Service_Organization {

	/**
	 * Prefix for all options (will be bw_schema_* in v3.0.0+)
	 * For now, keeps backward compatibility with bw_schema_*
	 *
	 * @var string
	 */
	const PREFIX = 'bw_schema_';

	/**
	 * Get all organization data from options
	 *
	 * Returns a complete organization record with defaults applied.
	 *
	 * @return array Organization data (name, url, logo, type, description, etc.)
	 */
	public static function get() {
		return wp_parse_args(
			get_option( self::PREFIX . 'organization', array() ),
			self::get_defaults()
		);
	}

	/**
	 * Fields the owner may explicitly mark as "not used"
	 *
	 * Opting out tells the health checks and the schema engine that the
	 * blank is deliberate — not a gap to nag about. Identity fields
	 * (name, url, logo) are never opt-outable.
	 *
	 * @return array Field key => label
	 */
	public static function get_optoutable_fields() {
		return array(
			'telephone' => __( 'phone number', 'bw-schema' ),
			'email'     => __( 'email', 'bw-schema' ),
		);
	}

	/**
	 * Field keys currently marked "not used"
	 *
	 * @return string[]
	 */
	public static function get_field_optouts() {
		$optouts = get_option( self::PREFIX . 'field_optouts', array() );
		if ( ! is_array( $optouts ) ) {
			return array();
		}
		// Only keys that are actually opt-outable
		return array_values( array_intersect( $optouts, array_keys( self::get_optoutable_fields() ) ) );
	}

	/**
	 * Save the set of "not used" field keys
	 *
	 * @param string[] $optouts Field keys
	 * @return void
	 */
	public static function set_field_optouts( $optouts ) {
		$optouts = is_array( $optouts ) ? array_map( 'sanitize_key', $optouts ) : array();
		$optouts = array_values( array_intersect( $optouts, array_keys( self::get_optoutable_fields() ) ) );
		update_option( self::PREFIX . 'field_optouts', $optouts );
	}

	/**
	 * Whether a field is marked "not used"
	 *
	 * @param string $field Field key (e.g. 'telephone')
	 * @return bool
	 */
	public static function is_field_opted_out( $field ) {
		return in_array( $field, self::get_field_optouts(), true );
	}

	/**
	 * Organization data for schema output — opted-out fields removed
	 *
	 * The generator uses this so a field marked "not used" never reaches
	 * the markup, even if a stale value is still stored.
	 *
	 * @return array Organization data
	 */
	public static function get_for_schema() {
		$org = self::get();
		foreach ( self::get_field_optouts() as $field ) {
			$org[ $field ] = '';
		}
		return $org;
	}

	/**
	 * Get organization schema defaults
	 *
	 * @return array Default values for all organization fields
	 */
	public static function get_defaults() {
		return array(
			'name'           => get_bloginfo( 'name' ),
			'url'            => home_url( '/' ),
			'logo'           => '',
			'telephone'      => '',
			'email'          => get_option( 'admin_email' ),
			'slogan'         => '',
			'alternateName'  => '',
			'legalName'      => '',
			'description'    => get_bloginfo( 'description' ),
			'sameAs'         => array(),
			'contactPoint'   => array(),
		);
	}

	/**
	 * Save organization data
	 *
	 * Validates input and saves to options. Returns error if validation fails.
	 *
	 * @param array $data Organization data to save
	 * @return array|WP_Error Array with 'success' => true on success, WP_Error on failure
	 */
	public static function save( $data ) {
		// Validate first
		$validation = self::validate( $data );
		if ( is_wp_error( $validation ) ) {
			return $validation;
		}

		// Sanitize
		$sanitized = self::sanitize( $data );

		// Save to options
		update_option( self::PREFIX . 'organization', $sanitized );

		// Clear related caches
		if ( class_exists( 'BW_Schema_Cache' ) ) {
			BW_Schema_Cache::clear_all();
		}

		return array( 'success' => true );
	}

	/**
	 * Validate organization data
	 *
	 * @param array $data Data to validate
	 * @return bool|WP_Error True if valid, WP_Error if not
	 */
	public static function validate( $data ) {
		// Organization name is required
		if ( empty( $data['name'] ) ) {
			return new WP_Error(
				'missing_org_name',
				__( 'Organization name is required.', 'bw-schema' )
			);
		}

		// URL must be valid
		if ( ! empty( $data['url'] ) && ! filter_var( $data['url'], FILTER_VALIDATE_URL ) ) {
			return new WP_Error(
				'invalid_url',
				__( 'Organization URL must be a valid URL.', 'bw-schema' )
			);
		}

		// Email must be valid
		if ( ! empty( $data['email'] ) && ! is_email( $data['email'] ) ) {
			return new WP_Error(
				'invalid_email',
				__( 'Organization email must be a valid email address.', 'bw-schema' )
			);
		}

		return true;
	}

	/**
	 * Sanitize organization data
	 *
	 * Applies WordPress sanitization functions to each field.
	 * Preserves all fields, including type-specific conditional fields.
	 *
	 * @param array $data Data to sanitize
	 * @return array Sanitized data
	 */
	public static function sanitize( $data ) {
		$data = wp_parse_args( $data, self::get_defaults() );

		// Start with the core fields
		$sanitized = array(
			'name'           => sanitize_text_field( $data['name'] ?? '' ),
			'url'            => esc_url_raw( $data['url'] ?? '' ),
			'logo'           => esc_url_raw( $data['logo'] ?? '' ),
			'telephone'      => sanitize_text_field( $data['telephone'] ?? '' ),
			'email'          => sanitize_email( $data['email'] ?? '' ),
			'slogan'         => sanitize_text_field( $data['slogan'] ?? '' ),
			'alternateName'  => sanitize_text_field( $data['alternateName'] ?? '' ),
			'legalName'      => sanitize_text_field( $data['legalName'] ?? '' ),
			'description'    => wp_kses_post( $data['description'] ?? '' ),
			'sameAs'         => is_array( $data['sameAs'] ?? array() ) ? array_map( 'esc_url_raw', $data['sameAs'] ) : array(),
			'contactPoint'   => is_array( $data['contactPoint'] ?? array() ) ? $data['contactPoint'] : array(),
		);

		// IMPORTANT: Preserve only type-specific conditional fields that are still in the form
		// These are already sanitized by the form builder's validate_and_save() method
		$preserved_fields = array(
			// Accommodation fields
			'accommodation_chain_name',
			'accommodation_star_rating',
			'accommodation_num_rooms',
			// Food & Beverage fields
			'food_beverage_cuisine_type',
			'food_beverage_price_range',
			'food_beverage_delivery',
			// Medical & Healthcare fields
			'medical_license_number',
			'medical_specialization',
			// Retail fields
			'retail_accepts_returns',
			// Professional Services fields
			'professional_license_number',
			'professional_specialization',
			'professional_years_experience',
			// Real Estate fields
			'realestate_mls_number',
			'realestate_specialization',
			// Automotive fields
			'automotive_services',
			// Entertainment fields
			'entertainment_capacity',
			// Beauty & Personal Care fields
			'beauty_services',
			// Education fields
			'education_accreditation',
			// Finance & Banking fields
			'finance_member_networks',
			// NOTE: Removed FAQ, Review, and Article/WebPage schemas from Organization settings
			// - FAQ Schema: now handled as blocks in page content
			// - Review Schema: comes from Google My Business integration
			// - WebPage Schema: handled per-post-type, not organization-wide
		);

		foreach ( $preserved_fields as $field_name ) {
			if ( isset( $data[ $field_name ] ) && $data[ $field_name ] !== '' ) {
				$sanitized[ $field_name ] = $data[ $field_name ];
			}
		}

		return $sanitized;
	}

	/**
	 * Get field definitions for form builder
	 *
	 * Returns an array of field definitions that the form builder can use
	 * to render the organization settings form. Each field includes validation,
	 * sanitization, help text, and metadata.
	 *
	 * @return array Array of field definitions
	 */
	public static function get_field_definitions() {
		$fields = array(
			// Basic Identity Section
			array(
				'section'   => 'basic_identity',
				'name'      => 'org_name',
				'label'     => __( 'Organization Name', 'bw-schema' ),
				'type'      => 'text',
				'required'  => true,
				'help'      => __( 'Your official organization name as it should appear in schema.', 'bw-schema' ),
				'sanitize'  => 'sanitize_text_field',
				'validate'  => 'required',
				'map_to'    => 'name',
			),
			array(
				'section'   => 'basic_identity',
				'name'      => 'org_alternate_name',
				'label'     => __( 'Alternate / Brand Name', 'bw-schema' ),
				'type'      => 'text',
				'help'      => __( 'A.k.a., DBA, or brand name (e.g., legal name "Acme Corp" but commonly known as "Acme").', 'bw-schema' ),
				'sanitize'  => 'sanitize_text_field',
				'map_to'    => 'alternateName',
			),
			array(
				'section'   => 'basic_identity',
				'name'      => 'org_legal_name',
				'label'     => __( 'Legal Name', 'bw-schema' ),
				'type'      => 'text',
				'help'      => __( 'The legal registered name of your organization (if different from brand name).', 'bw-schema' ),
				'sanitize'  => 'sanitize_text_field',
				'map_to'    => 'legalName',
			),
			array(
				'section'   => 'basic_identity',
				'name'      => 'org_url',
				'label'     => __( 'Website URL', 'bw-schema' ),
				'type'      => 'url',
				'required'  => true,
				'help'      => __( 'Your organization\'s main website URL.', 'bw-schema' ),
				'sanitize'  => 'esc_url_raw',
				'validate'  => array( 'required', 'url' ),
				'map_to'    => 'url',
			),
			array(
				'section'   => 'basic_identity',
				'name'      => 'org_slogan',
				'label'     => __( 'Slogan', 'bw-schema' ),
				'type'      => 'text',
				'help'      => __( 'A catchy phrase or tagline for your organization.', 'bw-schema' ),
				'sanitize'  => 'sanitize_text_field',
				'map_to'    => 'slogan',
			),

			// NOTE: Type-specific conditional fields (accommodation, food & beverage, medical, etc.) are defined
			// in BW_Schema_Page_Organization::get_business_type_fields() to keep them organized with the
			// page rendering logic. They are NOT duplicated here to avoid conflicts.
			// The page class handles saving these fields via handle_save().

			// Contact Section
			array(
				'section'   => 'contact',
				'name'      => 'org_telephone',
				'label'     => __( 'Phone Number', 'bw-schema' ),
				'type'      => 'tel',
				'help'      => __( 'Primary phone number in international format (e.g., +1-201-555-0123).', 'bw-schema' ),
				'sanitize'  => 'sanitize_text_field',
				'map_to'    => 'telephone',
				'optout'    => 'telephone',
			),
			array(
				'section'   => 'contact',
				'name'      => 'org_email',
				'label'     => __( 'Email Address', 'bw-schema' ),
				'type'      => 'email',
				'help'      => __( 'General contact email for your organization.', 'bw-schema' ),
				'sanitize'  => 'sanitize_email',
				'validate'  => 'email',
				'map_to'    => 'email',
				'optout'    => 'email',
			),

			// Logo & Branding
			array(
				'section'   => 'branding',
				'name'      => 'org_logo',
				'label'     => __( 'Logo URL', 'bw-schema' ),
				'type'      => 'url',
				'help'      => __( 'URL to your organization logo. Renders as a rich ImageObject (width/height auto-detected if in your media library).', 'bw-schema' ),
				'sanitize'  => 'esc_url_raw',
				'validate'  => array( 'url' ),
				'map_to'    => 'logo',
			),

			// Description
			array(
				'section'   => 'description',
				'name'      => 'org_description',
				'label'     => __( 'Description', 'bw-schema' ),
				'type'      => 'textarea',
				'rows'      => 5,
				'help'      => __( 'A comprehensive description of your organization. Appears as the description field in schema.', 'bw-schema' ),
				'sanitize'  => 'wp_kses_post',
				'map_to'    => 'description',
			),

			// ====== CONDITIONAL FIELDS (shown based on business type) ======

			// Medical / Healthcare specific
			array(
				'section'        => 'contact',
				'name'           => 'org_medical_hours',
				'label'          => __( 'Hours of Operation', 'bw-schema' ),
				'type'           => 'text',
				'help'           => __( 'e.g., Mon-Fri 9am-5pm, Sat-Sun Closed', 'bw-schema' ),
				'show_if'        => array( 'business_type' => 'medical' ),
				'sanitize'       => 'sanitize_text_field',
			),
			array(
				'section'        => 'contact',
				'name'           => 'org_medical_services',
				'label'          => __( 'Services Offered', 'bw-schema' ),
				'type'           => 'textarea',
				'rows'           => 3,
				'help'           => __( 'List of medical services provided (one per line).', 'bw-schema' ),
				'show_if'        => array( 'business_type' => 'medical' ),
				'sanitize'       => 'sanitize_textarea_field',
			),

			// Hospitality specific
			array(
				'section'        => 'contact',
				'name'           => 'org_hospitality_checkin',
				'label'          => __( 'Check-in Time', 'bw-schema' ),
				'type'           => 'time',
				'help'           => __( 'Default check-in time (HH:MM format)', 'bw-schema' ),
				'show_if'        => array( 'business_type' => 'hospitality' ),
				'sanitize'       => 'sanitize_text_field',
			),
			array(
				'section'        => 'contact',
				'name'           => 'org_hospitality_checkout',
				'label'          => __( 'Check-out Time', 'bw-schema' ),
				'type'           => 'time',
				'help'           => __( 'Default check-out time (HH:MM format)', 'bw-schema' ),
				'show_if'        => array( 'business_type' => 'hospitality' ),
				'sanitize'       => 'sanitize_text_field',
			),
			array(
				'section'        => 'branding',
				'name'           => 'org_hospitality_amenities',
				'label'          => __( 'Amenities', 'bw-schema' ),
				'type'           => 'textarea',
				'rows'           => 3,
				'help'           => __( 'List of amenities (one per line, e.g., WiFi, Pool, Gym)', 'bw-schema' ),
				'show_if'        => array( 'business_type' => 'hospitality' ),
				'sanitize'       => 'sanitize_textarea_field',
			),

			// Real Estate specific
			array(
				'section'        => 'branding',
				'name'           => 'org_realestate_license',
				'label'          => __( 'License Number', 'bw-schema' ),
				'type'           => 'text',
				'help'           => __( 'Real estate license number or broker ID', 'bw-schema' ),
				'show_if'        => array( 'business_type' => 'realestate' ),
				'sanitize'       => 'sanitize_text_field',
			),
			array(
				'section'        => 'branding',
				'name'           => 'org_realestate_service_area',
				'label'          => __( 'Service Area', 'bw-schema' ),
				'type'           => 'text',
				'help'           => __( 'Geographic area served (e.g., Los Angeles, CA and surrounding areas)', 'bw-schema' ),
				'show_if'        => array( 'business_type' => 'realestate' ),
				'sanitize'       => 'sanitize_text_field',
			),

			// Financial specific
			array(
				'section'        => 'branding',
				'name'           => 'org_financial_license',
				'label'          => __( 'License / Registration', 'bw-schema' ),
				'type'           => 'text',
				'help'           => __( 'Financial license or registration number', 'bw-schema' ),
				'show_if'        => array( 'business_type' => 'financial' ),
				'sanitize'       => 'sanitize_text_field',
			),
			array(
				'section'        => 'branding',
				'name'           => 'org_financial_specialties',
				'label'          => __( 'Specialties', 'bw-schema' ),
				'type'           => 'textarea',
				'rows'           => 3,
				'help'           => __( 'Areas of financial expertise (one per line, e.g., Retirement Planning, Tax Strategy)', 'bw-schema' ),
				'show_if'        => array( 'business_type' => 'financial' ),
				'sanitize'       => 'sanitize_textarea_field',
			),

			// E-commerce specific
			array(
				'section'        => 'branding',
				'name'           => 'org_ecommerce_currency',
				'label'          => __( 'Accepted Currency', 'bw-schema' ),
				'type'           => 'text',
				'help'           => __( 'e.g., USD, EUR, GBP', 'bw-schema' ),
				'show_if'        => array( 'business_type' => 'ecommerce' ),
				'sanitize'       => 'sanitize_text_field',
			),
			array(
				'section'        => 'contact',
				'name'           => 'org_ecommerce_returns',
				'label'          => __( 'Return Policy', 'bw-schema' ),
				'type'           => 'text',
				'help'           => __( 'e.g., 30-day money-back guarantee', 'bw-schema' ),
				'show_if'        => array( 'business_type' => 'ecommerce' ),
				'sanitize'       => 'sanitize_text_field',
			),

			// Education specific
			array(
				'section'        => 'branding',
				'name'           => 'org_education_accreditation',
				'label'          => __( 'Accreditation', 'bw-schema' ),
				'type'           => 'text',
				'help'           => __( 'Accrediting body and status', 'bw-schema' ),
				'show_if'        => array( 'business_type' => 'education' ),
				'sanitize'       => 'sanitize_text_field',
			),
			array(
				'section'        => 'branding',
				'name'           => 'org_education_programs',
				'label'          => __( 'Programs Offered', 'bw-schema' ),
				'type'           => 'textarea',
				'rows'           => 3,
				'help'           => __( 'Degree/program names (one per line)', 'bw-schema' ),
				'show_if'        => array( 'business_type' => 'education' ),
				'sanitize'       => 'sanitize_textarea_field',
			),
		);

		// ===== PHASE 6: REMOVED =====
		// FAQ Schema - now handled as blocks in page content
		// Review Schema - comes from Google My Business integration
		// WebPage Schema - handled per-post-type, not organization-wide

		return $fields;
	}

	/**
	 * Get business type options
	 *
	 * Used for categorizing organizations by industry/type.
	 *
	 * @return array Key => Label pairs
	 */
	/**
	 * Get business categories based on schema.org hierarchy
	 *
	 * Groups schema.org business types into logical categories.
	 *
	 * @return array Key => Label pairs for main categories
	 */
	public static function get_business_categories() {
		return array(
			'accommodation'  => __( 'Accommodation (Hotels, Resorts, etc.)', 'bw-schema' ),
			'food_beverage'  => __( 'Food & Beverage (Restaurants, Cafes, etc.)', 'bw-schema' ),
			'medical'        => __( 'Medical & Healthcare', 'bw-schema' ),
			'retail'         => __( 'Retail & Stores', 'bw-schema' ),
			'professional'   => __( 'Professional Services', 'bw-schema' ),
			'automotive'     => __( 'Automotive', 'bw-schema' ),
			'entertainment'  => __( 'Entertainment & Recreation', 'bw-schema' ),
			'beauty'         => __( 'Beauty & Personal Care', 'bw-schema' ),
			'education'      => __( 'Education', 'bw-schema' ),
			'finance'        => __( 'Banking & Finance', 'bw-schema' ),
			'realestate'     => __( 'Real Estate', 'bw-schema' ),
			'services'       => __( 'General Services', 'bw-schema' ),
		);
	}

	/**
	 * Get schema.org business types organized by category
	 *
	 * Each type includes the actual schema.org class name for proper markup.
	 *
	 * @return array Hierarchical: category => array(key => array(label, schemaorg_type))
	 */
	public static function get_business_types() {
		return array(
			'accommodation' => array(
				'hotel'           => array( __( 'Hotel', 'bw-schema' ), 'Hotel' ),
				'resort'          => array( __( 'Resort', 'bw-schema' ), 'Resort' ),
				'bedandbreakfast' => array( __( 'Bed & Breakfast', 'bw-schema' ), 'BedAndBreakfast' ),
				'hostel'          => array( __( 'Hostel', 'bw-schema' ), 'Hostel' ),
				'campground'      => array( __( 'Campground', 'bw-schema' ), 'CampingPitch' ),
			),
			'food_beverage' => array(
				'restaurant'      => array( __( 'Restaurant', 'bw-schema' ), 'Restaurant' ),
				'cafe'            => array( __( 'Cafe or Coffee Shop', 'bw-schema' ), 'CafeOrCoffeeShop' ),
				'bar'             => array( __( 'Bar or Grill', 'bw-schema' ), 'BarOrGrill' ),
				'bakery'          => array( __( 'Bakery', 'bw-schema' ), 'Bakery' ),
				'brewery'         => array( __( 'Brewery', 'bw-schema' ), 'BreweryOrDistillery' ),
				'icecream'        => array( __( 'Ice Cream Shop', 'bw-schema' ), 'IceCreamShop' ),
			),
			'medical' => array(
				'hospital'        => array( __( 'Hospital', 'bw-schema' ), 'Hospital' ),
				'dentist'         => array( __( 'Dentist', 'bw-schema' ), 'Dentist' ),
				'physician'       => array( __( 'Physician', 'bw-schema' ), 'Physician' ),
				'clinic'          => array( __( 'Medical Clinic', 'bw-schema' ), 'MedicalClinic' ),
				'pharmacy'        => array( __( 'Pharmacy', 'bw-schema' ), 'Pharmacy' ),
				'veterinary'      => array( __( 'Veterinary Clinic', 'bw-schema' ), 'VeterinaryClinic' ),
			),
			'retail' => array(
				'bookstore'       => array( __( 'Book Store', 'bw-schema' ), 'BookStore' ),
				'clothingstore'   => array( __( 'Clothing Store', 'bw-schema' ), 'ClothingStore' ),
				'electronicsstore'=> array( __( 'Electronics Store', 'bw-schema' ), 'ElectronicsStore' ),
				'grocerystore'    => array( __( 'Grocery Store', 'bw-schema' ), 'GroceryStore' ),
				'hardwarestore'   => array( __( 'Hardware Store', 'bw-schema' ), 'HardwareStore' ),
				'toysstore'       => array( __( 'Toys Store', 'bw-schema' ), 'ToyStore' ),
			),
			'professional' => array(
				'attorney'        => array( __( 'Attorney / Law Firm', 'bw-schema' ), 'Attorney' ),
				'accountant'      => array( __( 'Accountant', 'bw-schema' ), 'Accountant' ),
				'realestateagent' => array( __( 'Real Estate Agent', 'bw-schema' ), 'RealEstateAgent' ),
				'insuranceagency' => array( __( 'Insurance Agency', 'bw-schema' ), 'InsuranceAgency' ),
				'consulting'      => array( __( 'Consulting Service', 'bw-schema' ), 'ProfessionalService' ),
			),
			'automotive' => array(
				'autorepair'      => array( __( 'Auto Repair', 'bw-schema' ), 'AutoRepair' ),
				'autorental'      => array( __( 'Auto Rental', 'bw-schema' ), 'AutoRentalService' ),
				'carwash'         => array( __( 'Car Wash', 'bw-schema' ), 'AutoWash' ),
				'gasstation'      => array( __( 'Gas Station', 'bw-schema' ), 'GasStation' ),
			),
			'entertainment' => array(
				'movietheater'    => array( __( 'Movie Theater', 'bw-schema' ), 'MovieTheater' ),
				'artgallery'      => array( __( 'Art Gallery', 'bw-schema' ), 'ArtGallery' ),
				'nightclub'       => array( __( 'Night Club', 'bw-schema' ), 'NightClub' ),
				'bowling'         => array( __( 'Bowling Alley', 'bw-schema' ), 'BowlingAlley' ),
				'sportsfacility'  => array( __( 'Sports Facility', 'bw-schema' ), 'SportsActivityLocation' ),
			),
			'beauty' => array(
				'spa'             => array( __( 'Spa / Day Spa', 'bw-schema' ), 'HealthAndBeautyBusiness' ),
				'hairdresser'     => array( __( 'Hair Salon', 'bw-schema' ), 'HairSalon' ),
				'tattoo'          => array( __( 'Tattoo Parlor', 'bw-schema' ), 'TattooParlor' ),
			),
			'education' => array(
				'university'      => array( __( 'University / College', 'bw-schema' ), 'CollegeOrUniversity' ),
				'highschool'      => array( __( 'High School', 'bw-schema' ), 'HighSchool' ),
				'middleschool'    => array( __( 'Middle School', 'bw-schema' ), 'MiddleSchool' ),
				'preschool'       => array( __( 'Preschool', 'bw-schema' ), 'Preschool' ),
				'library'         => array( __( 'Library', 'bw-schema' ), 'Library' ),
			),
			'finance' => array(
				'bank'            => array( __( 'Bank', 'bw-schema' ), 'Bank' ),
				'creditunion'     => array( __( 'Credit Union', 'bw-schema' ), 'CreditUnion' ),
				'atm'             => array( __( 'ATM', 'bw-schema' ), 'ATM' ),
			),
			'realestate' => array(
				'realestateagent' => array( __( 'Real Estate Agent', 'bw-schema' ), 'RealEstateAgent' ),
				'realestatebiz'   => array( __( 'Real Estate Business', 'bw-schema' ), 'RealEstateBusiness' ),
			),
			'services' => array(
				'cleaningservice' => array( __( 'Cleaning Service', 'bw-schema' ), 'CleaningService' ),
				'deliveryservice' => array( __( 'Delivery Service', 'bw-schema' ), 'DeliveryService' ),
				'laundry'         => array( __( 'Dry Cleaning / Laundry', 'bw-schema' ), 'DryCleaningOrLaundry' ),
				'movingcompany'   => array( __( 'Moving Company', 'bw-schema' ), 'MovingCompany' ),
				'plumber'         => array( __( 'Plumber', 'bw-schema' ), 'Plumber' ),
			),
		);
	}

	/**
	 * Get schema.org type for a business category + type combination
	 *
	 * @param string $category Main category (e.g., 'accommodation')
	 * @param string $type Specific type (e.g., 'hotel')
	 * @return string Schema.org class name or empty string if not found
	 */
	public static function get_schema_type( $category, $type ) {
		$all_types = self::get_business_types();
		if ( isset( $all_types[ $category ][ $type ] ) ) {
			$type_data = $all_types[ $category ][ $type ];
			return is_array( $type_data ) ? $type_data[1] : '';
		}
		return '';
	}

	/**
	 * Get label for a category + type combination
	 *
	 * @param string $category Main category
	 * @param string $type Specific type
	 * @return string Label or empty string
	 */
	public static function get_type_label( $category, $type ) {
		$all_types = self::get_business_types();
		if ( isset( $all_types[ $category ][ $type ] ) ) {
			$type_data = $all_types[ $category ][ $type ];
			return is_array( $type_data ) ? $type_data[0] : '';
		}
		return '';
	}

	/**
	 * Get types for a specific category
	 *
	 * @param string $category Main category key
	 * @return array Types for this category with labels
	 */
	public static function get_types_for_category( $category ) {
		$all_types = self::get_business_types();
		if ( ! isset( $all_types[ $category ] ) ) {
			return array();
		}

		// Convert from array format to simple key => label
		$types = array();
		foreach ( $all_types[ $category ] as $key => $data ) {
			$types[ $key ] = is_array( $data ) ? $data[0] : $data;
		}
		return $types;
	}

	/**
	 * Get business type for current organization
	 *
	 * @return string Current business type selection
	 */
	public static function get_business_type() {
		return get_option( self::PREFIX . 'business_type', '' );
	}

	/**
	 * Set business type
	 *
	 * @param string $business_type Business type key
	 * @return bool Success
	 */
	public static function set_business_type( $business_type ) {
		if ( ! array_key_exists( $business_type, self::get_business_types() ) ) {
			return false;
		}

		update_option( self::PREFIX . 'business_type', $business_type );

		// Clear caches
		if ( class_exists( 'BW_Schema_Cache' ) ) {
			BW_Schema_Cache::clear_all();
		}

		return true;
	}

	/**
	 * Verify a remote image URL actually resolves to an image
	 *
	 * Sends a HEAD request (falling back to a 1KB ranged GET for servers
	 * that reject HEAD) and checks the response code and Content-Type.
	 * Uses wp_safe_remote_* so the URL can never point the server at
	 * localhost or LAN addresses (SSRF protection).
	 *
	 * @param string $url Image URL to verify
	 * @return true|WP_Error True when reachable and an image; WP_Error with a human-readable reason otherwise
	 */
	public static function verify_remote_image( $url ) {
		$url = trim( (string) $url );

		if ( '' === $url ) {
			return true; // Empty is allowed — the field is optional
		}

		if ( ! wp_http_validate_url( $url ) ) {
			return new WP_Error( 'logo_invalid_url', __( 'That is not a valid public URL.', 'bw-schema' ) );
		}

		$args = array(
			'timeout'     => 5,
			'redirection' => 3,
			'user-agent'  => 'SolomonSchema/' . BW_SCHEMA_VERSION . '; ' . home_url( '/' ),
		);

		$response = wp_safe_remote_head( $url, $args );
		$code     = is_wp_error( $response ) ? 0 : (int) wp_remote_retrieve_response_code( $response );

		// Some servers reject HEAD (405/403/501) — retry with a tiny ranged GET
		if ( is_wp_error( $response ) || in_array( $code, array( 403, 405, 501 ), true ) ) {
			$args['headers']             = array( 'Range' => 'bytes=0-1023' );
			$args['limit_response_size'] = 2048;

			$response = wp_safe_remote_get( $url, $args );
		}

		if ( is_wp_error( $response ) ) {
			return new WP_Error(
				'logo_unreachable',
				sprintf(
					/* translators: %s: HTTP error message */
					__( 'The URL could not be reached (%s).', 'bw-schema' ),
					$response->get_error_message()
				)
			);
		}

		$code = (int) wp_remote_retrieve_response_code( $response );
		if ( $code < 200 || $code >= 300 ) {
			return new WP_Error(
				'logo_http_error',
				sprintf(
					/* translators: %d: HTTP status code */
					__( 'The URL responded with HTTP %d — the file does not seem to exist.', 'bw-schema' ),
					$code
				)
			);
		}

		$content_type = (string) wp_remote_retrieve_header( $response, 'content-type' );
		if ( '' !== $content_type
			&& 0 !== stripos( $content_type, 'image/' )
			&& 0 !== stripos( $content_type, 'application/octet-stream' ) ) {
			return new WP_Error(
				'logo_not_image',
				sprintf(
					/* translators: %s: Content-Type header value */
					__( 'The URL exists but is not an image (it returned %s).', 'bw-schema' ),
					$content_type
				)
			);
		}

		return true;
	}
}
