<?php
/**
 * Platform Categories Registry
 *
 * Central registry for all marketplace offering categories.
 * Each category defines its booking mode, terminology, applicable pricing rules,
 * and subcategories. The admin enables/disables categories for the entire platform.
 *
 * @package WahraRentalsBookings
 * @since 1.1.0
 */

defined('ABSPATH') || exit;

/**
 * Platform Categories class
 */
class WAHRB_Platform_Categories {

    /**
     * Option key for saved category settings
     *
     * @var string
     */
    const OPTION_KEY = 'wahrb_settings_platform_categories';

    /**
     * Option key for per-category pricing rule defaults
     *
     * @var string
     */
    const PRICING_OPTION_KEY = 'wahrb_settings_pricing_rules';

    /**
     * Cached registry
     *
     * @var array|null
     */
    private static ?array $registry_cache = null;

    /**
     * Get the full category registry with built-in defaults.
     *
     * Each category defines:
     *  - label, icon, description
     *  - booking_modes: which DB booking_mode values this category uses
     *  - terminology: singular/plural/action/item names
     *  - pricing_rules: which rule types apply to this category
     *  - subcategories: keyed array of subcategory slugs
     *
     * @return array Full registry with defaults
     */
    public static function get_registry(): array {
        if (self::$registry_cache !== null) {
            return self::$registry_cache;
        }

        $registry = [
            'accommodation' => [
                'label'       => __('Accommodation', 'wahra-rentals-bookings'),
                'icon'        => 'dashicons-admin-home',
                'emoji'       => '🏠',
                'description' => __('Hotels, apartments, villas, camping — per-night stays', 'wahra-rentals-bookings'),
                'booking_modes' => ['day'],
                'terminology' => [
                    'singular' => __('Reservation', 'wahra-rentals-bookings'),
                    'plural'   => __('Reservations', 'wahra-rentals-bookings'),
                    'action'   => __('Reserve', 'wahra-rentals-bookings'),
                    'item'     => __('Property', 'wahra-rentals-bookings'),
                    'items'    => __('Properties', 'wahra-rentals-bookings'),
                ],
                'pricing_rules' => ['weekend', 'long_stay', 'early_bird', 'seasonal'],
                'subcategories' => [
                    'hotel'     => __('Hotel / Room', 'wahra-rentals-bookings'),
                    'apartment' => __('Apartment / House', 'wahra-rentals-bookings'),
                    'villa'     => __('Villa', 'wahra-rentals-bookings'),
                    'camping'   => __('Camping / Mobile Home', 'wahra-rentals-bookings'),
                ],
            ],
            'vehicle' => [
                'label'       => __('Vehicles & Transport', 'wahra-rentals-bookings'),
                'icon'        => 'dashicons-car',
                'emoji'       => '🚗',
                'description' => __('Cars, bikes, boats, scooters — per-day or per-hour rentals', 'wahra-rentals-bookings'),
                'booking_modes' => ['day', 'slot'],
                'terminology' => [
                    'singular' => __('Reservation', 'wahra-rentals-bookings'),
                    'plural'   => __('Reservations', 'wahra-rentals-bookings'),
                    'action'   => __('Reserve', 'wahra-rentals-bookings'),
                    'item'     => __('Vehicle', 'wahra-rentals-bookings'),
                    'items'    => __('Vehicles', 'wahra-rentals-bookings'),
                ],
                'pricing_rules' => ['weekend', 'long_stay', 'early_bird', 'seasonal'],
                'subcategories' => [
                    'car'     => __('Car / Van', 'wahra-rentals-bookings'),
                    'bike'    => __('Bike / Scooter', 'wahra-rentals-bookings'),
                    'boat'    => __('Boat', 'wahra-rentals-bookings'),
                ],
            ],
            'equipment' => [
                'label'       => __('Equipment & Gear', 'wahra-rentals-bookings'),
                'icon'        => 'dashicons-hammer',
                'emoji'       => '🔧',
                'description' => __('Sports, tech, tools, party equipment — per-day rentals', 'wahra-rentals-bookings'),
                'booking_modes' => ['day'],
                'terminology' => [
                    'singular' => __('Rental', 'wahra-rentals-bookings'),
                    'plural'   => __('Rentals', 'wahra-rentals-bookings'),
                    'action'   => __('Rent', 'wahra-rentals-bookings'),
                    'item'     => __('Item', 'wahra-rentals-bookings'),
                    'items'    => __('Items', 'wahra-rentals-bookings'),
                ],
                'pricing_rules' => ['long_stay', 'early_bird', 'seasonal'],
                'subcategories' => [
                    'sport'  => __('Sports & Leisure', 'wahra-rentals-bookings'),
                    'tech'   => __('High-Tech (Photo, Audio...)', 'wahra-rentals-bookings'),
                    'tools'  => __('DIY & Gardening', 'wahra-rentals-bookings'),
                    'party'  => __('Event Equipment', 'wahra-rentals-bookings'),
                ],
            ],
            'space' => [
                'label'       => __('Spaces & Venues', 'wahra-rentals-bookings'),
                'icon'        => 'dashicons-building',
                'emoji'       => '📍',
                'description' => __('Meeting rooms, studios, courts — per-hour or per-day', 'wahra-rentals-bookings'),
                'booking_modes' => ['day', 'slot'],
                'terminology' => [
                    'singular' => __('Reservation', 'wahra-rentals-bookings'),
                    'plural'   => __('Reservations', 'wahra-rentals-bookings'),
                    'action'   => __('Reserve', 'wahra-rentals-bookings'),
                    'item'     => __('Space', 'wahra-rentals-bookings'),
                    'items'    => __('Spaces', 'wahra-rentals-bookings'),
                ],
                'pricing_rules' => ['weekend', 'last_minute', 'early_bird', 'seasonal'],
                'subcategories' => [
                    'meeting_room' => __('Meeting Room', 'wahra-rentals-bookings'),
                    'studio'       => __('Studio / Workshop', 'wahra-rentals-bookings'),
                    'court'        => __('Sports Court', 'wahra-rentals-bookings'),
                    'event_space'  => __('Event Space', 'wahra-rentals-bookings'),
                ],
            ],
            'service' => [
                'label'       => __('Services & Appointments', 'wahra-rentals-bookings'),
                'icon'        => 'dashicons-businessman',
                'emoji'       => '💇',
                'description' => __('Massage, consultation, cleaning — fixed-duration sessions', 'wahra-rentals-bookings'),
                'booking_modes' => ['service'],
                'terminology' => [
                    'singular' => __('Appointment', 'wahra-rentals-bookings'),
                    'plural'   => __('Appointments', 'wahra-rentals-bookings'),
                    'action'   => __('Book', 'wahra-rentals-bookings'),
                    'item'     => __('Service', 'wahra-rentals-bookings'),
                    'items'    => __('Services', 'wahra-rentals-bookings'),
                ],
                'pricing_rules' => ['last_minute', 'early_bird', 'seasonal'],
                'subcategories' => [
                    'wellness'     => __('Wellness / Spa', 'wahra-rentals-bookings'),
                    'consultation' => __('Consultation', 'wahra-rentals-bookings'),
                    'cleaning'     => __('Cleaning / Housekeeping', 'wahra-rentals-bookings'),
                    'beauty'       => __('Beauty / Hair', 'wahra-rentals-bookings'),
                    'repair'       => __('Repair / Maintenance', 'wahra-rentals-bookings'),
                ],
            ],
            'product' => [
                'label'       => __('Products', 'wahra-rentals-bookings'),
                'icon'        => 'dashicons-cart',
                'emoji'       => '📦',
                'description' => __('Physical or digital products — per-day or per-period rentals', 'wahra-rentals-bookings'),
                'booking_modes' => ['day'],
                'terminology' => [
                    'singular' => __('Rental', 'wahra-rentals-bookings'),
                    'plural'   => __('Rentals', 'wahra-rentals-bookings'),
                    'action'   => __('Rent', 'wahra-rentals-bookings'),
                    'item'     => __('Product', 'wahra-rentals-bookings'),
                    'items'    => __('Products', 'wahra-rentals-bookings'),
                ],
                'pricing_rules' => ['early_bird', 'last_minute'],
                'subcategories' => [
                    'physical' => __('Physical Product', 'wahra-rentals-bookings'),
                    'digital'  => __('Digital Product', 'wahra-rentals-bookings'),
                    'clothing' => __('Clothing / Fashion', 'wahra-rentals-bookings'),
                ],
            ],
        ];

        self::$registry_cache = $registry;
        return $registry;
    }

    /**
     * Get saved platform category settings merged with defaults.
     *
     * Returns an array keyed by category slug with 'enabled' and 'subcategories' states.
     *
     * @return array
     */
    public static function get_settings(): array {
        $saved = get_option(self::OPTION_KEY, []);
        $registry = self::get_registry();
        $result = [];

        // Auto-repair: if option exists but ALL categories are explicitly disabled,
        // it was likely corrupted by the old save-all-tabs bug. Reset to defaults.
        if (!empty($saved)) {
            $any_enabled = false;
            foreach ($registry as $slug => $cat) {
                if (!empty($saved[$slug]['enabled'])) {
                    $any_enabled = true;
                    break;
                }
            }
            if (!$any_enabled) {
                // All categories disabled — likely corrupted. Delete the option
                // so defaults (enabled => true) kick in on next load.
                delete_option(self::OPTION_KEY);
                $saved = [];
            }
        }

        foreach ($registry as $slug => $cat) {
            $cat_saved = $saved[$slug] ?? [];
            $result[$slug] = [
                'enabled' => $cat_saved['enabled'] ?? true,
                'subcategories' => [],
            ];
            foreach ($cat['subcategories'] as $sub_slug => $sub_label) {
                $result[$slug]['subcategories'][$sub_slug] = $cat_saved['subcategories'][$sub_slug] ?? true;
            }
        }

        return $result;
    }

    /**
     * Get only the categories that are enabled on this platform.
     *
     * @return array Filtered registry (only enabled categories)
     */
    public static function get_enabled(): array {
        $settings = self::get_settings();
        $registry = self::get_registry();
        $enabled = [];

        foreach ($registry as $slug => $cat) {
            if (!empty($settings[$slug]['enabled'])) {
                $cat['_settings'] = $settings[$slug];
                $enabled[$slug] = $cat;
            }
        }

        return $enabled;
    }

    /**
     * Get a single category definition.
     *
     * @param string $slug Category slug
     * @return array|null Category data or null if not found
     */
    public static function get_category(string $slug): ?array {
        $registry = self::get_registry();
        return $registry[$slug] ?? null;
    }

    /**
     * Check if a specific category is enabled.
     *
     * @param string $slug Category slug
     * @return bool
     */
    public static function is_enabled(string $slug): bool {
        $settings = self::get_settings();
        return !empty($settings[$slug]['enabled']);
    }

    /**
     * Get terminology for a given category.
     *
     * @param string $slug Category slug
     * @param string $key  Terminology key (singular, plural, action, item, items)
     * @return string The translated term, or fallback 'Booking'
     */
    public static function get_term(string $slug, string $key = 'singular'): string {
        $cat = self::get_category($slug);
        if ($cat && isset($cat['terminology'][$key])) {
            return $cat['terminology'][$key];
        }
        // Fallback
        $fallbacks = [
            'singular' => __('Booking', 'wahra-rentals-bookings'),
            'plural'   => __('Bookings', 'wahra-rentals-bookings'),
            'action'   => __('Book', 'wahra-rentals-bookings'),
            'item'     => __('Listing', 'wahra-rentals-bookings'),
            'items'    => __('Listings', 'wahra-rentals-bookings'),
        ];
        return $fallbacks[$key] ?? $fallbacks['singular'];
    }

    /**
     * Resolve the category for a product based on its metadata.
     *
     * @param int $product_id WooCommerce product ID
     * @return string Category slug or 'accommodation' as default
     */
    public static function get_product_category(int $product_id): string {
        $category = get_post_meta($product_id, '_wahrb_platform_category', true);
        if ($category && isset(self::get_registry()[$category])) {
            return $category;
        }

        // Fallback: infer from booking_mode
        $mode = get_post_meta($product_id, '_wahrb_booking_mode', true);
        return self::mode_to_category($mode);
    }

    /**
     * Map a booking_mode to the most likely category (for backward compat).
     *
     * @param string $mode Booking mode (day, slot, service, product)
     * @return string Best-guess category slug
     */
    public static function mode_to_category(string $mode): string {
        $map = [
            'day'     => 'accommodation',
            'slot'    => 'space',
            'service' => 'service',
        ];
        return $map[$mode] ?? 'accommodation';
    }

    /**
     * Get the allowed booking modes for a category.
     *
     * @param string $slug Category slug
     * @return array Array of booking_mode strings
     */
    public static function get_booking_modes(string $slug): array {
        $cat = self::get_category($slug);
        return $cat['booking_modes'] ?? ['day'];
    }

    /**
     * Get the pricing rule types applicable to a category.
     *
     * @param string $slug Category slug
     * @return array Array of rule type strings
     */
    public static function get_applicable_rules(string $slug): array {
        $cat = self::get_category($slug);
        return $cat['pricing_rules'] ?? [];
    }

    /**
     * Get default pricing rules per category.
     *
     * Merges saved overrides with built-in defaults.
     *
     * @return array Keyed by category slug, then rule type
     */
    public static function get_pricing_defaults(): array {
        $saved = get_option(self::PRICING_OPTION_KEY, []);

        // Built-in defaults per category
        $defaults = [
            'accommodation' => [
                'weekend'    => ['enabled' => true, 'modifier' => 15, 'days' => [5, 6, 0]],
                'long_stay'  => ['enabled' => true, 'threshold' => 7, 'discount' => 10],
                'early_bird' => ['enabled' => true, 'days' => 30, 'discount' => 5],
                'seasonal'   => ['enabled' => false],
            ],
            'vehicle' => [
                'weekend'    => ['enabled' => true, 'modifier' => 10, 'days' => [5, 6, 0]],
                'long_stay'  => ['enabled' => true, 'threshold' => 7, 'discount' => 15],
                'early_bird' => ['enabled' => true, 'days' => 14, 'discount' => 5],
                'seasonal'   => ['enabled' => false],
            ],
            'equipment' => [
                'long_stay'  => ['enabled' => true, 'threshold' => 7, 'discount' => 10],
                'early_bird' => ['enabled' => false, 'days' => 14, 'discount' => 5],
                'seasonal'   => ['enabled' => false],
            ],
            'space' => [
                'weekend'     => ['enabled' => true, 'modifier' => 20, 'days' => [6, 0]],
                'last_minute' => ['enabled' => true, 'hours' => 24, 'modifier' => 15],
                'early_bird'  => ['enabled' => false, 'days' => 7, 'discount' => 5],
                'seasonal'    => ['enabled' => false],
            ],
            'service' => [
                'last_minute' => ['enabled' => true, 'hours' => 48, 'modifier' => 20],
                'early_bird'  => ['enabled' => true, 'days' => 30, 'discount' => 5],
                'seasonal'    => ['enabled' => false],
            ],
            'product' => [
                'early_bird'  => ['enabled' => true, 'days' => 14, 'discount' => 5],
                'last_minute' => ['enabled' => true, 'hours' => 24, 'modifier' => 15],
            ],
        ];

        // Merge saved over defaults
        if (is_array($saved) && !empty($saved)) {
            // Handle legacy flat format (pre-1.1.0)
            if (isset($saved['weekend_modifier'])) {
                $saved = self::migrate_flat_pricing($saved);
            }
            foreach ($defaults as $cat_slug => &$cat_rules) {
                if (isset($saved[$cat_slug]) && is_array($saved[$cat_slug])) {
                    foreach ($cat_rules as $rule_type => &$rule_defaults) {
                        if (isset($saved[$cat_slug][$rule_type]) && is_array($saved[$cat_slug][$rule_type])) {
                            $rule_defaults = array_merge($rule_defaults, $saved[$cat_slug][$rule_type]);
                        }
                    }
                    unset($rule_defaults);
                }
            }
            unset($cat_rules);
        }

        return $defaults;
    }

    /**
     * Get pricing defaults for a specific category.
     *
     * @param string $slug Category slug
     * @return array Rule defaults for this category
     */
    public static function get_category_pricing(string $slug): array {
        $all = self::get_pricing_defaults();
        return $all[$slug] ?? [];
    }

    /**
     * Migrate legacy flat pricing settings to per-category structure.
     *
     * Converts the old wahrb_settings_pricing_rules format:
     *   { weekend_modifier: 15, long_stay_threshold: 7, ... }
     * To the new per-category format.
     *
     * @param array $flat Old flat pricing array
     * @return array New per-category structure
     */
    public static function migrate_flat_pricing(array $flat): array {
        $weekend_mod   = intval($flat['weekend_modifier'] ?? 15);
        $ls_threshold  = intval($flat['long_stay_threshold'] ?? 7);
        $ls_discount   = intval($flat['long_stay_discount'] ?? 10);
        $eb_days       = intval($flat['early_bird_days'] ?? 30);
        $eb_discount   = intval($flat['early_bird_discount'] ?? 5);
        $lm_hours      = intval($flat['last_minute_hours'] ?? 48);
        $lm_modifier   = intval($flat['last_minute_modifier'] ?? 20);

        return [
            'accommodation' => [
                'weekend'    => ['enabled' => true, 'modifier' => $weekend_mod, 'days' => [5, 6, 0]],
                'long_stay'  => ['enabled' => true, 'threshold' => $ls_threshold, 'discount' => $ls_discount],
                'early_bird' => ['enabled' => true, 'days' => $eb_days, 'discount' => $eb_discount],
            ],
            'vehicle' => [
                'weekend'    => ['enabled' => true, 'modifier' => $weekend_mod, 'days' => [5, 6, 0]],
                'long_stay'  => ['enabled' => true, 'threshold' => $ls_threshold, 'discount' => $ls_discount],
                'early_bird' => ['enabled' => true, 'days' => $eb_days, 'discount' => $eb_discount],
            ],
            'equipment' => [
                'long_stay'  => ['enabled' => true, 'threshold' => $ls_threshold, 'discount' => $ls_discount],
                'early_bird' => ['enabled' => false, 'days' => $eb_days, 'discount' => $eb_discount],
            ],
            'space' => [
                'weekend'     => ['enabled' => true, 'modifier' => $weekend_mod, 'days' => [6, 0]],
                'last_minute' => ['enabled' => true, 'hours' => $lm_hours, 'modifier' => $lm_modifier],
                'early_bird'  => ['enabled' => false, 'days' => $eb_days, 'discount' => $eb_discount],
            ],
            'service' => [
                'last_minute' => ['enabled' => true, 'hours' => $lm_hours, 'modifier' => $lm_modifier],
                'early_bird'  => ['enabled' => true, 'days' => $eb_days, 'discount' => $eb_discount],
            ],
            'product' => [],
        ];
    }

    /**
     * Get all categories as a simple slug → label array (for dropdowns).
     *
     * @param bool $enabled_only Only include enabled categories
     * @return array
     */
    public static function get_labels(bool $enabled_only = false): array {
        $source = $enabled_only ? self::get_enabled() : self::get_registry();
        $labels = [];
        foreach ($source as $slug => $cat) {
            $labels[$slug] = $cat['label'];
        }
        return $labels;
    }

    /**
     * Get the configuration array to pass to the React wizard via JS.
     *
     * @return array
     */
    public static function get_js_config(): array {
        $enabled = self::get_enabled();
        $pricing = self::get_pricing_defaults();
        $config = [];

        foreach ($enabled as $slug => $cat) {
            $config[$slug] = [
                'label'          => $cat['label'],
                'emoji'          => $cat['emoji'],
                'description'    => $cat['description'],
                'booking_modes'  => $cat['booking_modes'],
                'terminology'    => $cat['terminology'],
                'pricing_rules'  => $cat['pricing_rules'],
                'pricing_defaults' => $pricing[$slug] ?? [],
                'subcategories'  => [],
            ];
            // Only include enabled subcategories
            $settings = $cat['_settings'] ?? [];
            foreach ($cat['subcategories'] as $sub_slug => $sub_label) {
                if (!empty($settings['subcategories'][$sub_slug])) {
                    $config[$slug]['subcategories'][$sub_slug] = $sub_label;
                }
            }
        }

        return $config;
    }

    /**
     * Get all pricing rule type definitions (metadata about each rule type).
     *
     * @return array
     */
    public static function get_pricing_rule_types(): array {
        return [
            'weekend' => [
                'label'       => __('Weekend Supplement', 'wahra-rentals-bookings'),
                'icon'        => '📅',
                'description' => __('Price increase on specific days of the week', 'wahra-rentals-bookings'),
                'type'        => 'supplement',
                'fields'      => ['modifier', 'days'],
            ],
            'long_stay' => [
                'label'       => __('Long Stay Discount', 'wahra-rentals-bookings'),
                'icon'        => '📆',
                'description' => __('Discount when duration exceeds threshold', 'wahra-rentals-bookings'),
                'type'        => 'discount',
                'fields'      => ['threshold', 'discount'],
            ],
            'early_bird' => [
                'label'       => __('Early Bird Discount', 'wahra-rentals-bookings'),
                'icon'        => '🐦',
                'description' => __('Discount for booking well in advance', 'wahra-rentals-bookings'),
                'type'        => 'discount',
                'fields'      => ['days', 'discount'],
            ],
            'last_minute' => [
                'label'       => __('Last Minute Supplement', 'wahra-rentals-bookings'),
                'icon'        => '⚡',
                'description' => __('Urgency surcharge for very short notice', 'wahra-rentals-bookings'),
                'type'        => 'supplement',
                'fields'      => ['hours', 'modifier'],
            ],
            'seasonal' => [
                'label'       => __('Seasonal Pricing', 'wahra-rentals-bookings'),
                'icon'        => '🌞',
                'description' => __('Price adjustments for high/low season periods', 'wahra-rentals-bookings'),
                'type'        => 'adjustment',
                'fields'      => ['date_ranges'],
            ],
        ];
    }

    /**
     * Payment settings defaults for any category.
     *
     * @var array
     */
    private static $payment_defaults = [
        'deposit_enabled'          => true,
        'deposit_type'             => 'percent',
        'deposit_value'            => 30,
        'deposit_refundable'       => true,
        'security_deposit_enabled' => true,
        'security_mode'            => 'capture',
        'balance_enabled'          => true,
        'balance_due_days_before'  => 3,
        'balance_allow_cod'        => true,
    ];

    /**
     * Get payment settings for a specific platform category.
     *
     * Returns admin-configured per-category payment settings merged with defaults.
     *
     * @param string $slug Platform category slug (e.g. 'accommodation')
     * @return array Payment settings for the category
     */
    public static function get_payment_settings(string $slug): array {
        $payment_option = get_option('wahrb_settings_payment', []);
        $cat_settings   = $payment_option['categories'][$slug] ?? [];

        return wp_parse_args($cat_settings, self::$payment_defaults);
    }

    /**
     * Get payment settings for a specific product (resolves via its platform category).
     *
     * @param int $product_id WooCommerce product ID
     * @return array Payment settings for the product's category
     */
    public static function get_product_payment_settings(int $product_id): array {
        $slug = self::get_product_category($product_id);
        return self::get_payment_settings($slug);
    }

    /**
     * Get all per-category payment settings (keyed by category slug).
     *
     * @param bool $enabled_only Only include enabled categories (default true)
     * @return array [ 'accommodation' => [...], 'vehicle' => [...], ... ]
     */
    public static function get_all_payment_settings(bool $enabled_only = true): array {
        $categories = $enabled_only ? self::get_enabled() : self::get_registry();
        $result     = [];

        foreach ($categories as $slug => $cat) {
            $result[$slug] = self::get_payment_settings($slug);
        }

        return $result;
    }

    /**
     * Get vendor permission settings for a specific platform category.
     *
     * Returns admin-configured per-category vendor permissions merged with category defaults.
     *
     * @param string $slug Platform category slug
     * @return array Permissions for the category
     */
    public static function get_vendor_permissions(string $slug): array {
        $perms_option = get_option('wahrb_settings_vendor_permissions', []);
        $cat_perms    = $perms_option['categories'][$slug] ?? [];

        $defaults = [
            'can_set_own_prices'          => true,
            'can_set_cancellation_policy' => true,
            'can_set_deposit_amount'      => true,
            'can_set_security_deposit'    => true,
            'min_price_allowed'           => 0,
            'max_price_allowed'           => 0,
        ];

        $merged = wp_parse_args($cat_perms, $defaults);

        // require_approval is global, not per-category
        $merged['require_approval'] = !empty($perms_option['require_approval']);

        return $merged;
    }

    /**
     * Clear the internal cache. Call after saving category settings.
     */
    public static function clear_cache(): void {
        self::$registry_cache = null;
    }

    /**
     * Save platform category settings from admin form POST data.
     *
     * @param array $post_data Sanitized POST data
     */
    public static function save_settings(array $post_data): void {
        $registry = self::get_registry();
        $settings = [];

        foreach ($registry as $slug => $cat) {
            $settings[$slug] = [
                'enabled' => !empty($post_data["wahrb_cat_{$slug}_enabled"]),
                'subcategories' => [],
            ];
            foreach ($cat['subcategories'] as $sub_slug => $sub_label) {
                $settings[$slug]['subcategories'][$sub_slug] = !empty($post_data["wahrb_subcat_{$slug}_{$sub_slug}"]);
            }
        }

        update_option(self::OPTION_KEY, $settings);
        self::clear_cache();
    }

    /**
     * Save pricing rule defaults from admin form POST data.
     *
     * @param array $post_data Sanitized POST data
     */
    public static function save_pricing(array $post_data): void {
        $registry = self::get_registry();
        $rule_types = self::get_pricing_rule_types();
        $pricing = [];

        foreach ($registry as $cat_slug => $cat) {
            $pricing[$cat_slug] = [];
            foreach ($cat['pricing_rules'] as $rule_type) {
                if (!isset($rule_types[$rule_type])) {
                    continue;
                }
                $prefix = "wahrb_pr_{$cat_slug}_{$rule_type}";
                $rule_data = [
                    'enabled' => !empty($post_data["{$prefix}_enabled"]),
                ];

                // Parse rule-specific fields
                switch ($rule_type) {
                    case 'weekend':
                        $rule_data['modifier'] = absint($post_data["{$prefix}_modifier"] ?? 15);
                        // Parse weekend days checkboxes
                        $days = [];
                        if (!empty($post_data["{$prefix}_days"]) && is_array($post_data["{$prefix}_days"])) {
                            $days = array_map('absint', $post_data["{$prefix}_days"]);
                        }
                        $rule_data['days'] = $days ?: [5, 6, 0];
                        break;

                    case 'long_stay':
                        $rule_data['threshold'] = absint($post_data["{$prefix}_threshold"] ?? 7);
                        $rule_data['discount'] = absint($post_data["{$prefix}_discount"] ?? 10);
                        break;

                    case 'early_bird':
                        $rule_data['days'] = absint($post_data["{$prefix}_days"] ?? 30);
                        $rule_data['discount'] = absint($post_data["{$prefix}_discount"] ?? 5);
                        break;

                    case 'last_minute':
                        $rule_data['hours'] = absint($post_data["{$prefix}_hours"] ?? 48);
                        $rule_data['modifier'] = absint($post_data["{$prefix}_modifier"] ?? 20);
                        break;

                    case 'seasonal':
                        // Seasonal has no quick default fields (configured per vendor/product)
                        break;
                }

                $pricing[$cat_slug][$rule_type] = $rule_data;
            }
        }

        update_option(self::PRICING_OPTION_KEY, $pricing);
    }
}
