<?php
/**
 * Plugin Name: APN Competitions
 * Description: Competition CPT and taxonomies for APNetwork multisite
 * Version: 0.2.0
 * Author: APNetwork
 * Network: true
 */

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

/**
 * APNetwork Competitions
 *
 * Registers the Competition CPT on the main site with taxonomies
 * and ACF field groups for managing competition data network-wide.
 */
class APN_Competitions {

    /** @var int Main site blog ID */
    const MAIN_SITE_ID = 1;

    /** @var APN_Competitions Singleton instance */
    private static $instance = null;

    /**
     * Get singleton instance
     */
    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Constructor - hook into WordPress
     */
    private function __construct() {
        // Register CPT and taxonomies on init
        add_action('init', [$this, 'register_post_type']);
        add_action('init', [$this, 'register_taxonomies']);

        // Register ACF fields (after ACF loads)
        add_action('acf/include_fields', [$this, 'register_acf_fields']);
    }

    /**
     * Check if we are on the main site
     */
    public function is_main_site() {
        return get_current_blog_id() === self::MAIN_SITE_ID;
    }

    /**
     * Register the Competition custom post type (main site only)
     */
    public function register_post_type() {
        // Only register CPT on main site
        if (!$this->is_main_site()) {
            return;
        }

        $labels = [
            'name'                  => 'Competitions',
            'singular_name'         => 'Competition',
            'menu_name'             => 'Competitions',
            'add_new'               => 'Add New',
            'add_new_item'          => 'Add New Competition',
            'edit_item'             => 'Edit Competition',
            'new_item'              => 'New Competition',
            'view_item'             => 'View Competition',
            'search_items'          => 'Search Competitions',
            'not_found'             => 'No competitions found',
            'not_found_in_trash'    => 'No competitions found in trash',
            'all_items'             => 'All Competitions',
        ];

        $args = [
            'labels'                => $labels,
            'public'                => false,
            'publicly_queryable'    => false,
            'show_ui'               => true,
            'show_in_menu'          => true,
            'show_in_rest'          => true,
            'menu_position'         => 5,
            'menu_icon'             => 'dashicons-awards',
            'supports'              => ['title', 'thumbnail'],
            'has_archive'           => false,
            'rewrite'               => false,
            'capability_type'       => 'post',
        ];

        register_post_type('apn_competition', $args);
    }

    /**
     * Register taxonomies (main site only)
     */
    public function register_taxonomies() {
        // Only register on main site
        if (!$this->is_main_site()) {
            return;
        }

        // Parent Category (Beverage vs Food & Beverage)
        register_taxonomy('apn_parent_category', 'apn_competition', [
            'labels' => [
                'name'              => 'Parent Categories',
                'singular_name'     => 'Parent Category',
                'search_items'      => 'Search Parent Categories',
                'all_items'         => 'All Parent Categories',
                'edit_item'         => 'Edit Parent Category',
                'update_item'       => 'Update Parent Category',
                'add_new_item'      => 'Add New Parent Category',
                'new_item_name'     => 'New Parent Category Name',
                'menu_name'         => 'Parent Categories',
            ],
            'hierarchical'      => false,
            'show_ui'           => true,
            'show_in_rest'      => true,
            'show_admin_column' => true,
            'rewrite'           => false,
        ]);

        // Product Type (Beer, Wine, Spirits, Olive Oil, etc.)
        register_taxonomy('apn_product_type', 'apn_competition', [
            'labels' => [
                'name'              => 'Product Types',
                'singular_name'     => 'Product Type',
                'search_items'      => 'Search Product Types',
                'all_items'         => 'All Product Types',
                'edit_item'         => 'Edit Product Type',
                'update_item'       => 'Update Product Type',
                'add_new_item'      => 'Add New Product Type',
                'new_item_name'     => 'New Product Type Name',
                'menu_name'         => 'Product Types',
            ],
            'hierarchical'      => false,
            'show_ui'           => true,
            'show_in_rest'      => true,
            'show_admin_column' => true,
            'rewrite'           => false,
        ]);

        // Region (hierarchical: Country > State > City)
        register_taxonomy('apn_region', 'apn_competition', [
            'labels' => [
                'name'              => 'Regions',
                'singular_name'     => 'Region',
                'search_items'      => 'Search Regions',
                'all_items'         => 'All Regions',
                'parent_item'       => 'Parent Region',
                'parent_item_colon' => 'Parent Region:',
                'edit_item'         => 'Edit Region',
                'update_item'       => 'Update Region',
                'add_new_item'      => 'Add New Region',
                'new_item_name'     => 'New Region Name',
                'menu_name'         => 'Regions',
            ],
            'hierarchical'      => true,
            'show_ui'           => true,
            'show_in_rest'      => true,
            'show_admin_column' => true,
            'rewrite'           => false,
        ]);
    }

    /**
     * Register ACF field groups
     */
    public function register_acf_fields() {
        // Only register on main site
        if (!$this->is_main_site()) {
            return;
        }

        // Check if ACF is available
        if (!function_exists('acf_add_local_field_group')) {
            return;
        }

        // Competition Details group
        acf_add_local_field_group([
            'key' => 'group_apn_competition_core',
            'title' => 'Competition Details',
            'fields' => [
                [
                    'key' => 'field_apn_site_id',
                    'label' => 'Linked Site',
                    'name' => 'site_id',
                    'type' => 'number',
                    'instructions' => 'The blog ID of the child site this competition belongs to',
                    'required' => 0,
                    'min' => 1,
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_abbreviation',
                    'label' => 'Abbreviation',
                    'name' => 'abbreviation',
                    'type' => 'text',
                    'instructions' => 'Short abbreviation (e.g., NYIBC)',
                    'maxlength' => 20,
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_website_url',
                    'label' => 'Website URL',
                    'name' => 'website_url',
                    'type' => 'url',
                    'instructions' => 'Competition website URL',
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_short_summary',
                    'label' => 'Short Summary',
                    'name' => 'short_summary',
                    'type' => 'textarea',
                    'instructions' => 'One sentence summary of this competition',
                    'rows' => 2,
                    'new_lines' => '',
                    'maxlength' => 200,
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_default_entry_page',
                    'label' => 'Default Entry Page',
                    'name' => 'default_entry_page',
                    'type' => 'url',
                    'instructions' => 'Default page where entrants go to enter',
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_default_entry_link',
                    'label' => 'Default Entry Link',
                    'name' => 'default_entry_link',
                    'type' => 'url',
                    'instructions' => 'Direct entry link (e.g., to entry form)',
                    'wrapper' => ['width' => '50'],
                ],
            ],
            'location' => [
                [
                    [
                        'param' => 'post_type',
                        'operator' => '==',
                        'value' => 'apn_competition',
                    ],
                ],
            ],
            'menu_order' => 0,
            'position' => 'normal',
            'style' => 'default',
            'label_placement' => 'top',
        ]);

        // Design group
        acf_add_local_field_group([
            'key' => 'group_apn_competition_design',
            'title' => 'Design',
            'fields' => [
                // Row 1: Logo, Primary Color, Theme Icon, Featured Image (4 columns)
                [
                    'key' => 'field_apn_logo',
                    'label' => 'Logo',
                    'name' => 'logo',
                    'type' => 'image',
                    'instructions' => 'Competition logo for cards and headers',
                    'return_format' => 'id',
                    'preview_size' => 'medium',
                    'wrapper' => ['width' => '25'],
                ],
                [
                    'key' => 'field_apn_primary_color',
                    'label' => 'Primary Color',
                    'name' => 'primary_color',
                    'type' => 'color_picker',
                    'instructions' => 'Primary brand color for this competition',
                    'default_value' => '',
                    'wrapper' => ['width' => '25'],
                ],
                [
                    'key' => 'field_apn_theme_icon',
                    'label' => 'Theme Icon',
                    'name' => 'theme_icon',
                    'type' => 'image',
                    'instructions' => 'Icon representing the competition theme (e.g., beer mug, wine glass)',
                    'return_format' => 'id',
                    'preview_size' => 'medium',
                    'wrapper' => ['width' => '25'],
                ],
                [
                    'key' => 'field_apn_opt_featured_msg',
                    'label' => 'Featured Image',
                    'name' => '',
                    'type' => 'message',
                    'message' => 'Set via the Featured Image panel on the right →',
                    'wrapper' => ['width' => '25'],
                ],
                // Row 2: Hero Image, Product Image, Flare (3 columns)
                [
                    'key' => 'field_apn_hero_image',
                    'label' => 'Hero Image',
                    'name' => 'hero_image',
                    'type' => 'image',
                    'instructions' => 'Full-width hero section image',
                    'return_format' => 'id',
                    'preview_size' => 'large',
                    'wrapper' => ['width' => '33'],
                ],
                [
                    'key' => 'field_apn_product_image',
                    'label' => 'Product Image',
                    'name' => 'product_image',
                    'type' => 'image',
                    'instructions' => 'Product layer for hero sections (e.g., beer glasses). Transparent PNG recommended.',
                    'return_format' => 'id',
                    'preview_size' => 'medium',
                    'wrapper' => ['width' => '33'],
                ],
                [
                    'key' => 'field_apn_flare_image',
                    'label' => 'Flare Image',
                    'name' => 'flare_image',
                    'type' => 'image',
                    'instructions' => 'Decorative overlay layer (e.g., bubbles, grape leaves). SVG recommended.',
                    'return_format' => 'id',
                    'preview_size' => 'medium',
                    'wrapper' => ['width' => '33'],
                ],
                // Row 3: Card Background, Mini Banner (2 columns)
                [
                    'key' => 'field_apn_card_bg',
                    'label' => 'Card Background Image',
                    'name' => 'card_background_image',
                    'type' => 'image',
                    'instructions' => 'Background image for competition cards',
                    'return_format' => 'id',
                    'preview_size' => 'medium',
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_mini_banner',
                    'label' => 'Mini Banner',
                    'name' => 'mini_banner',
                    'type' => 'image',
                    'instructions' => 'Smaller banner variant',
                    'return_format' => 'id',
                    'preview_size' => 'medium',
                    'wrapper' => ['width' => '50'],
                ],
                // Row 4: Awards (4 columns)
                [
                    'key' => 'field_apn_award_double_gold',
                    'label' => 'Award: Double Gold',
                    'name' => 'award_double_gold',
                    'type' => 'image',
                    'instructions' => 'Double Gold medal/award image',
                    'return_format' => 'id',
                    'preview_size' => 'medium',
                    'wrapper' => ['width' => '25'],
                ],
                [
                    'key' => 'field_apn_award_gold',
                    'label' => 'Award: Gold',
                    'name' => 'award_gold',
                    'type' => 'image',
                    'instructions' => 'Gold medal/award image',
                    'return_format' => 'id',
                    'preview_size' => 'medium',
                    'wrapper' => ['width' => '25'],
                ],
                [
                    'key' => 'field_apn_award_silver',
                    'label' => 'Award: Silver',
                    'name' => 'award_silver',
                    'type' => 'image',
                    'instructions' => 'Silver medal/award image',
                    'return_format' => 'id',
                    'preview_size' => 'medium',
                    'wrapper' => ['width' => '25'],
                ],
                [
                    'key' => 'field_apn_award_bronze',
                    'label' => 'Award: Bronze',
                    'name' => 'award_bronze',
                    'type' => 'image',
                    'instructions' => 'Bronze medal/award image',
                    'return_format' => 'id',
                    'preview_size' => 'medium',
                    'wrapper' => ['width' => '25'],
                ],
            ],
            'location' => [
                [
                    [
                        'param' => 'post_type',
                        'operator' => '==',
                        'value' => 'apn_competition',
                    ],
                ],
            ],
            'menu_order' => 5,
            'position' => 'normal',
            'style' => 'default',
            'label_placement' => 'top',
        ]);

        // Years Repeater group
        $this->register_years_field_group();

        // Scheduled CTAs group
        $this->register_cta_field_group();
    }

    /**
     * Register Years repeater field group (separated for readability)
     */
    private function register_years_field_group() {
        acf_add_local_field_group([
            'key' => 'group_apn_competition_years',
            'title' => 'Competition Years',
            'fields' => [
                [
                    'key' => 'field_apn_years',
                    'label' => 'Years',
                    'name' => 'years',
                    'type' => 'repeater',
                    'instructions' => 'Add competition details for each year',
                    'layout' => 'block',
                    'button_label' => 'Add Year',
                    'sub_fields' => [
                        [
                            'key' => 'field_apn_year_number',
                            'label' => 'Year',
                            'name' => 'year',
                            'type' => 'number',
                            'required' => 1,
                            'min' => 2000,
                            'max' => 2100,
                            'wrapper' => ['width' => '20'],
                        ],
                        [
                            'key' => 'field_apn_year_entry_page',
                            'label' => 'Entry Page Override',
                            'name' => 'entry_page_override',
                            'type' => 'url',
                            'wrapper' => ['width' => '40'],
                        ],
                        [
                            'key' => 'field_apn_year_entry_link',
                            'label' => 'Entry Link Override',
                            'name' => 'entry_link_override',
                            'type' => 'url',
                            'wrapper' => ['width' => '40'],
                        ],
                        [
                            'key' => 'field_apn_year_entry_pdf',
                            'label' => 'Entry PDF',
                            'name' => 'entry_pdf',
                            'type' => 'file',
                            'instructions' => 'Entry form PDF',
                            'return_format' => 'id',
                            'mime_types' => 'pdf',
                        ],
                        [
                            'key' => 'field_apn_year_tab_prices',
                            'label' => 'Entry Prices',
                            'type' => 'tab',
                        ],
                        [
                            'key' => 'field_apn_year_price_early',
                            'label' => 'Early Bird Price',
                            'name' => 'entry_price_early',
                            'type' => 'number',
                            'prepend' => '$',
                            'wrapper' => ['width' => '33'],
                        ],
                        [
                            'key' => 'field_apn_year_price_regular',
                            'label' => 'Regular Price',
                            'name' => 'entry_price_regular',
                            'type' => 'number',
                            'prepend' => '$',
                            'wrapper' => ['width' => '33'],
                        ],
                        [
                            'key' => 'field_apn_year_price_late',
                            'label' => 'Late Price',
                            'name' => 'entry_price_late',
                            'type' => 'number',
                            'prepend' => '$',
                            'wrapper' => ['width' => '33'],
                        ],
                        [
                            'key' => 'field_apn_year_tab_dates',
                            'label' => 'Entry Deadlines',
                            'type' => 'tab',
                        ],
                        [
                            'key' => 'field_apn_year_date_early',
                            'label' => 'Early Bird Deadline',
                            'name' => 'entry_date_early',
                            'type' => 'date_picker',
                            'display_format' => 'F j, Y',
                            'return_format' => 'Y-m-d',
                            'wrapper' => ['width' => '33'],
                        ],
                        [
                            'key' => 'field_apn_year_date_regular',
                            'label' => 'Regular Deadline',
                            'name' => 'entry_date_regular',
                            'type' => 'date_picker',
                            'display_format' => 'F j, Y',
                            'return_format' => 'Y-m-d',
                            'wrapper' => ['width' => '33'],
                        ],
                        [
                            'key' => 'field_apn_year_date_late',
                            'label' => 'Late Deadline',
                            'name' => 'entry_date_late',
                            'type' => 'date_picker',
                            'display_format' => 'F j, Y',
                            'return_format' => 'Y-m-d',
                            'wrapper' => ['width' => '33'],
                        ],
                        [
                            'key' => 'field_apn_year_tab_deadlines',
                            'label' => 'Other Deadlines',
                            'type' => 'tab',
                        ],
                        [
                            'key' => 'field_apn_year_delivery_deadline',
                            'label' => 'Product Delivery Deadline',
                            'name' => 'product_delivery_deadline',
                            'type' => 'date_picker',
                            'display_format' => 'F j, Y',
                            'return_format' => 'Y-m-d',
                            'wrapper' => ['width' => '50'],
                        ],
                        [
                            'key' => 'field_apn_year_payment_deadline',
                            'label' => 'Payment Deadline',
                            'name' => 'payment_deadline',
                            'type' => 'date_picker',
                            'display_format' => 'F j, Y',
                            'return_format' => 'Y-m-d',
                            'wrapper' => ['width' => '50'],
                        ],
                        [
                            'key' => 'field_apn_year_tab_comp_dates',
                            'label' => 'Competition Dates',
                            'type' => 'tab',
                        ],
                        [
                            'key' => 'field_apn_year_comp_start',
                            'label' => 'Competition Start',
                            'name' => 'competition_date_start',
                            'type' => 'date_picker',
                            'display_format' => 'F j, Y',
                            'return_format' => 'Y-m-d',
                            'wrapper' => ['width' => '33'],
                        ],
                        [
                            'key' => 'field_apn_year_comp_end',
                            'label' => 'Competition End',
                            'name' => 'competition_date_end',
                            'type' => 'date_picker',
                            'display_format' => 'F j, Y',
                            'return_format' => 'Y-m-d',
                            'wrapper' => ['width' => '33'],
                        ],
                        [
                            'key' => 'field_apn_year_comp_text',
                            'label' => 'Date Display Text',
                            'name' => 'competition_date_text',
                            'type' => 'text',
                            'instructions' => 'e.g., "March 15-17, 2026"',
                            'wrapper' => ['width' => '33'],
                        ],
                        [
                            'key' => 'field_apn_year_tab_winners',
                            'label' => 'Winner Announcement',
                            'type' => 'tab',
                        ],
                        [
                            'key' => 'field_apn_year_winner_date',
                            'label' => 'Winner Announcement Date',
                            'name' => 'winner_announcement_date',
                            'type' => 'date_picker',
                            'display_format' => 'F j, Y',
                            'return_format' => 'Y-m-d',
                            'wrapper' => ['width' => '50'],
                        ],
                        [
                            'key' => 'field_apn_year_winner_text',
                            'label' => 'Announcement Display Text',
                            'name' => 'winner_announcement_text',
                            'type' => 'text',
                            'wrapper' => ['width' => '50'],
                        ],
                        [
                            'key' => 'field_apn_year_tab_notes',
                            'label' => 'Notes',
                            'type' => 'tab',
                        ],
                        [
                            'key' => 'field_apn_year_notes',
                            'label' => 'Entry Notes',
                            'name' => 'entry_notes',
                            'type' => 'textarea',
                            'instructions' => 'Additional information for entrants',
                            'rows' => 4,
                        ],
                    ],
                ],
            ],
            'location' => [
                [
                    [
                        'param' => 'post_type',
                        'operator' => '==',
                        'value' => 'apn_competition',
                    ],
                ],
            ],
            'menu_order' => 10,
            'position' => 'normal',
            'style' => 'default',
            'label_placement' => 'top',
        ]);
    }

    /**
     * Register Scheduled CTAs field group on main site CPT
     */
    private function register_cta_field_group() {
        $phases = [
            'early_bird'        => 'Early Bird Entry',
            'regular'           => 'Regular Entry',
            'late'              => 'Late Entry',
            'upcoming'          => 'Upcoming Competition',
            'winner_anticipation' => 'Winner Anticipation',
            'winners_announced' => 'Winners Announced',
            'next_anticipation' => 'Next Competition Anticipation',
        ];

        $fields = [];

        foreach ($phases as $slug => $label) {
            $fields[] = [
                'key' => "field_apn_cta_tab_{$slug}",
                'label' => $label,
                'type' => 'tab',
            ];
            $fields[] = [
                'key' => "field_apn_cta_{$slug}_activation_date",
                'label' => 'Activation Date',
                'name' => "cta_{$slug}_activation_date",
                'type' => 'text',
                'placeholder' => 'e.g., [next_year_start] or [early_bird_deadline]',
            ];
            $fields[] = [
                'key' => "field_apn_cta_{$slug}_primary_headline",
                'label' => 'Primary CTA Headline',
                'name' => "cta_{$slug}_primary_headline",
                'type' => 'text',
                'wrapper' => ['width' => '50'],
            ];
            $fields[] = [
                'key' => "field_apn_cta_{$slug}_secondary_headline",
                'label' => 'Secondary CTA Headline',
                'name' => "cta_{$slug}_secondary_headline",
                'type' => 'text',
                'wrapper' => ['width' => '50'],
            ];
            $fields[] = [
                'key' => "field_apn_cta_{$slug}_primary_subheading",
                'label' => 'Primary CTA Subheading',
                'name' => "cta_{$slug}_primary_subheading",
                'type' => 'text',
                'wrapper' => ['width' => '50'],
            ];
            $fields[] = [
                'key' => "field_apn_cta_{$slug}_secondary_subheading",
                'label' => 'Secondary CTA Subheading',
                'name' => "cta_{$slug}_secondary_subheading",
                'type' => 'text',
                'wrapper' => ['width' => '50'],
            ];
            $fields[] = [
                'key' => "field_apn_cta_{$slug}_primary_link",
                'label' => 'Primary CTA Link',
                'name' => "cta_{$slug}_primary_link",
                'type' => 'text',
                'wrapper' => ['width' => '50'],
            ];
            $fields[] = [
                'key' => "field_apn_cta_{$slug}_secondary_link",
                'label' => 'Secondary CTA Link',
                'name' => "cta_{$slug}_secondary_link",
                'type' => 'text',
                'wrapper' => ['width' => '50'],
            ];
        }

        acf_add_local_field_group([
            'key' => 'group_apn_competition_ctas',
            'title' => 'Scheduled CTAs',
            'fields' => $fields,
            'location' => [
                [
                    [
                        'param' => 'post_type',
                        'operator' => '==',
                        'value' => 'apn_competition',
                    ],
                ],
            ],
            'menu_order' => 20,
            'position' => 'normal',
            'style' => 'default',
            'label_placement' => 'top',
        ]);
    }
}

/**
 * APNetwork Competition Sync
 *
 * Handles the child site options page that proxies to the main site's CPT.
 * On child sites, admins see a "Competition Settings" page that looks like
 * local options but actually reads/writes to the main site's competition CPT.
 */
class APN_Competition_Sync {

    /** @var int Main site blog ID */
    const MAIN_SITE_ID = 1;

    /** @var string Options page slug */
    const OPTIONS_PAGE_SLUG = 'apn-competition-settings';

    /** @var APN_Competition_Sync Singleton instance */
    private static $instance = null;

    /** @var int|null Cached competition post ID for current site */
    private $competition_id = null;

    /**
     * Get singleton instance
     */
    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    /**
     * Constructor
     *
     * Note: We register all hooks unconditionally and check is_main_site()
     * inside each method. This is required for multisite because the blog
     * context isn't determined until after plugins_loaded.
     */
    private function __construct() {
        // Register options page on child sites
        add_action('acf/init', [$this, 'register_options_page']);

        // Register the same field groups for the options page
        // Use acf/init with later priority to ensure options page is registered first
        add_action('acf/init', [$this, 'register_options_fields'], 15);

        // Dynamically load taxonomy choices right before field is rendered
        add_filter('acf/prepare_field/key=field_apn_opt_parent_category', [$this, 'load_taxonomy_choices']);
        add_filter('acf/prepare_field/key=field_apn_opt_product_type', [$this, 'load_taxonomy_choices']);
        add_filter('acf/prepare_field/key=field_apn_opt_region', [$this, 'load_taxonomy_choices']);

        // Convert entry_pdf field to read-only preview on child sites
        add_filter('acf/prepare_field/key=field_apn_opt_year_entry_pdf', [$this, 'prepare_entry_pdf_field']);

        // Intercept field loading to pull from main site
        add_filter('acf/pre_load_value', [$this, 'load_value_from_main_site'], 10, 3);

        // Intercept WordPress option reads for repeater subfields
        add_filter('pre_option', [$this, 'intercept_option_read'], 10, 3);

        // Intercept saving to push to main site
        add_action('acf/save_post', [$this, 'save_to_main_site'], 5);
    }

    /**
     * Check if we're on the main site
     */
    public function is_main_site() {
        return get_current_blog_id() === self::MAIN_SITE_ID;
    }

    /**
     * Get the competition post ID for the current site
     *
     * @return int|null Competition post ID or null if not linked
     */
    public function get_competition_for_current_site() {
        if ($this->competition_id !== null) {
            return $this->competition_id ?: null;
        }

        $current_site_id = get_current_blog_id();

        // Switch to main site to query
        switch_to_blog(self::MAIN_SITE_ID);

        $posts = get_posts([
            'post_type'      => 'apn_competition',
            'posts_per_page' => 1,
            'meta_key'       => 'site_id',
            'meta_value'     => $current_site_id,
            'post_status'    => 'any',
        ]);

        $post_id = !empty($posts) ? $posts[0]->ID : 0;

        restore_current_blog();

        $this->competition_id = $post_id;
        return $post_id ?: null;
    }

    /**
     * Register the options page on child sites
     */
    public function register_options_page() {
        // Only on child sites
        if ($this->is_main_site()) {
            return;
        }

        if (!function_exists('acf_add_options_page')) {
            return;
        }

        $competition_id = $this->get_competition_for_current_site();

        // Get competition name for the page title
        $page_title = 'Competition Settings';
        if ($competition_id) {
            switch_to_blog(self::MAIN_SITE_ID);
            $competition_name = get_the_title($competition_id);
            restore_current_blog();
            if ($competition_name) {
                $page_title = $competition_name . ' Settings';
            }
        }

        acf_add_options_page([
            'page_title'    => $page_title,
            'menu_title'    => 'Competition Settings',
            'menu_slug'     => self::OPTIONS_PAGE_SLUG,
            'capability'    => 'manage_options',
            'icon_url'      => 'dashicons-awards',
            'position'      => 3,
            'redirect'      => false,
            'autoload'      => false,
            'update_button' => 'Save Competition Settings',
            'updated_message' => 'Competition settings saved.',
        ]);
    }

    /**
     * Register field groups for the options page
     */
    public function register_options_fields() {
        // Only on child sites
        if ($this->is_main_site()) {
            return;
        }

        if (!function_exists('acf_add_local_field_group')) {
            return;
        }

        $competition_id = $this->get_competition_for_current_site();

        // Show a message if no competition is linked
        if (!$competition_id) {
            acf_add_local_field_group([
                'key' => 'group_apn_no_competition',
                'title' => 'Competition Not Linked',
                'fields' => [
                    [
                        'key' => 'field_apn_no_competition_message',
                        'label' => '',
                        'name' => '',
                        'type' => 'message',
                        'message' => '<div style="padding: 20px; background: #fff3cd; border: 1px solid #ffc107; border-radius: 4px;">
                            <strong>This site is not linked to a competition.</strong><br><br>
                            To manage competition settings here, an administrator needs to:
                            <ol>
                                <li>Go to the <a href="' . esc_url(get_admin_url(self::MAIN_SITE_ID, 'edit.php?post_type=apn_competition')) . '" target="_blank">main site\'s Competitions</a></li>
                                <li>Create or edit a competition</li>
                                <li>Set the "Linked Site" field to this site\'s ID: <strong>' . get_current_blog_id() . '</strong></li>
                            </ol>
                        </div>',
                        'esc_html' => 0,
                    ],
                ],
                'location' => [
                    [
                        [
                            'param' => 'options_page',
                            'operator' => '==',
                            'value' => self::OPTIONS_PAGE_SLUG,
                        ],
                    ],
                ],
            ]);
            return;
        }

        // Get taxonomy choices for select fields
        $taxonomy_choices = $this->get_taxonomy_choices();

        // Competition Details - options page
        acf_add_local_field_group([
            'key' => 'group_apn_options_core',
            'title' => 'Competition Details',
            'fields' => [
                [
                    'key' => 'field_apn_opt_competition_name',
                    'label' => 'Competition Name',
                    'name' => 'competition_name',
                    'type' => 'text',
                    'instructions' => 'The name of this competition',
                    'required' => 1,
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_opt_abbreviation',
                    'label' => 'Abbreviation',
                    'name' => 'abbreviation',
                    'type' => 'text',
                    'instructions' => 'Short abbreviation (e.g., NYIBC)',
                    'maxlength' => 20,
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_opt_parent_category',
                    'label' => 'Competition Network',
                    'name' => 'parent_category',
                    'type' => 'select',
                    'instructions' => 'Which network does this competition belong to?',
                    'choices' => $taxonomy_choices['apn_parent_category'],
                    'allow_null' => 1,
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_opt_product_type',
                    'label' => 'Product Type',
                    'name' => 'product_type',
                    'type' => 'select',
                    'instructions' => 'What type of products are judged?',
                    'choices' => $taxonomy_choices['apn_product_type'],
                    'multiple' => 1,
                    'ui' => 1,
                    'allow_null' => 1,
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_opt_region',
                    'label' => 'Region',
                    'name' => 'region',
                    'type' => 'select',
                    'instructions' => 'Geographic region for this competition',
                    'choices' => $taxonomy_choices['apn_region'],
                    'multiple' => 1,
                    'ui' => 1,
                    'allow_null' => 1,
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_opt_website_url',
                    'label' => 'Website URL',
                    'name' => 'website_url',
                    'type' => 'url',
                    'instructions' => 'Competition website URL',
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_opt_short_summary',
                    'label' => 'Short Summary',
                    'name' => 'short_summary',
                    'type' => 'textarea',
                    'instructions' => 'One sentence summary of this competition',
                    'rows' => 2,
                    'new_lines' => '',
                    'maxlength' => 200,
                ],
                [
                    'key' => 'field_apn_opt_default_entry_page',
                    'label' => 'Default Entry Page',
                    'name' => 'default_entry_page',
                    'type' => 'url',
                    'instructions' => 'Default page where entrants go to enter',
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_opt_default_entry_link',
                    'label' => 'Default Entry Link',
                    'name' => 'default_entry_link',
                    'type' => 'url',
                    'instructions' => 'Direct entry link (e.g., to entry form)',
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_opt_years_count',
                    'label' => 'Years Running',
                    'name' => '',
                    'type' => 'message',
                    'message' => $this->get_years_count_html(),
                    'esc_html' => 0,
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_opt_annual_text',
                    'label' => 'Annual Edition',
                    'name' => '',
                    'type' => 'message',
                    'message' => $this->get_annual_text_html(),
                    'esc_html' => 0,
                    'wrapper' => ['width' => '50'],
                ],
            ],
            'location' => [
                [
                    [
                        'param' => 'options_page',
                        'operator' => '==',
                        'value' => self::OPTIONS_PAGE_SLUG,
                    ],
                ],
            ],
            'menu_order' => 0,
        ]);

        // Design - options page
        acf_add_local_field_group([
            'key' => 'group_apn_options_design',
            'title' => 'Design',
            'fields' => [
                // Row 1: Logo, Primary Color, Theme Icon, Featured Image (4 columns)
                [
                    'key' => 'field_apn_opt_logo',
                    'label' => 'Logo',
                    'name' => '',
                    'type' => 'message',
                    'message' => $this->get_image_preview_html('logo', 'Logo', 'medium'),
                    'esc_html' => 0,
                    'wrapper' => ['width' => '25'],
                ],
                [
                    'key' => 'field_apn_opt_primary_color',
                    'label' => 'Primary Color',
                    'name' => 'primary_color',
                    'type' => 'color_picker',
                    'instructions' => 'Primary brand color for this competition',
                    'default_value' => '',
                    'wrapper' => ['width' => '25'],
                ],
                [
                    'key' => 'field_apn_opt_theme_icon',
                    'label' => 'Theme Icon',
                    'name' => '',
                    'type' => 'message',
                    'message' => $this->get_image_preview_html('theme_icon', 'Theme Icon', 'medium'),
                    'esc_html' => 0,
                    'wrapper' => ['width' => '25'],
                ],
                [
                    'key' => 'field_apn_opt_featured_image',
                    'label' => 'Featured Image',
                    'name' => '',
                    'type' => 'message',
                    'message' => $this->get_featured_image_preview_html('medium'),
                    'esc_html' => 0,
                    'wrapper' => ['width' => '25'],
                ],
                // Row 2: Hero Image, Product Image, Flare (3 columns)
                [
                    'key' => 'field_apn_opt_hero_image',
                    'label' => 'Hero Image',
                    'name' => '',
                    'type' => 'message',
                    'message' => $this->get_image_preview_html('hero_image', 'Hero Image', 'large'),
                    'esc_html' => 0,
                    'wrapper' => ['width' => '33'],
                ],
                [
                    'key' => 'field_apn_opt_product_image',
                    'label' => 'Product Image',
                    'name' => '',
                    'type' => 'message',
                    'message' => $this->get_image_preview_html('product_image', 'Product Image', 'medium'),
                    'esc_html' => 0,
                    'wrapper' => ['width' => '33'],
                ],
                [
                    'key' => 'field_apn_opt_flare_image',
                    'label' => 'Flare Image',
                    'name' => '',
                    'type' => 'message',
                    'message' => $this->get_image_preview_html('flare_image', 'Flare Image', 'medium'),
                    'esc_html' => 0,
                    'wrapper' => ['width' => '33'],
                ],
                // Row 3: Card Background, Mini Banner (2 columns)
                [
                    'key' => 'field_apn_opt_card_bg',
                    'label' => 'Card Background Image',
                    'name' => '',
                    'type' => 'message',
                    'message' => $this->get_image_preview_html('card_background_image', 'Card Background', 'medium'),
                    'esc_html' => 0,
                    'wrapper' => ['width' => '50'],
                ],
                [
                    'key' => 'field_apn_opt_mini_banner',
                    'label' => 'Mini Banner',
                    'name' => '',
                    'type' => 'message',
                    'message' => $this->get_image_preview_html('mini_banner', 'Mini Banner', 'medium'),
                    'esc_html' => 0,
                    'wrapper' => ['width' => '50'],
                ],
                // Row 4: Awards (4 columns)
                [
                    'key' => 'field_apn_opt_award_double_gold',
                    'label' => 'Award: Double Gold',
                    'name' => '',
                    'type' => 'message',
                    'message' => $this->get_image_preview_html('award_double_gold', 'Double Gold', 'medium'),
                    'esc_html' => 0,
                    'wrapper' => ['width' => '25'],
                ],
                [
                    'key' => 'field_apn_opt_award_gold',
                    'label' => 'Award: Gold',
                    'name' => '',
                    'type' => 'message',
                    'message' => $this->get_image_preview_html('award_gold', 'Gold', 'medium'),
                    'esc_html' => 0,
                    'wrapper' => ['width' => '25'],
                ],
                [
                    'key' => 'field_apn_opt_award_silver',
                    'label' => 'Award: Silver',
                    'name' => '',
                    'type' => 'message',
                    'message' => $this->get_image_preview_html('award_silver', 'Silver', 'medium'),
                    'esc_html' => 0,
                    'wrapper' => ['width' => '25'],
                ],
                [
                    'key' => 'field_apn_opt_award_bronze',
                    'label' => 'Award: Bronze',
                    'name' => '',
                    'type' => 'message',
                    'message' => $this->get_image_preview_html('award_bronze', 'Bronze', 'medium'),
                    'esc_html' => 0,
                    'wrapper' => ['width' => '25'],
                ],
            ],
            'location' => [
                [
                    [
                        'param' => 'options_page',
                        'operator' => '==',
                        'value' => self::OPTIONS_PAGE_SLUG,
                    ],
                ],
            ],
            'menu_order' => 5,
        ]);

        // Years Repeater - same structure
        acf_add_local_field_group([
            'key' => 'group_apn_options_years',
            'title' => 'Competition Years',
            'fields' => [
                [
                    'key' => 'field_apn_opt_years',
                    'label' => 'Years',
                    'name' => 'years',
                    'type' => 'repeater',
                    'instructions' => 'Add competition details for each year',
                    'layout' => 'block',
                    'button_label' => 'Add Year',
                    'sub_fields' => $this->get_year_subfields('opt_'),
                ],
            ],
            'location' => [
                [
                    [
                        'param' => 'options_page',
                        'operator' => '==',
                        'value' => self::OPTIONS_PAGE_SLUG,
                    ],
                ],
            ],
            'menu_order' => 10,
        ]);
    }

    /**
     * Get year subfields with a key prefix
     */
    private function get_year_subfields($prefix = '') {
        return [
            [
                'key' => 'field_apn_' . $prefix . 'year_number',
                'label' => 'Year',
                'name' => 'year',
                'type' => 'number',
                'required' => 1,
                'min' => 2000,
                'max' => 2100,
                'wrapper' => ['width' => '20'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_entry_page',
                'label' => 'Entry Page Override',
                'name' => 'entry_page_override',
                'type' => 'url',
                'wrapper' => ['width' => '40'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_entry_link',
                'label' => 'Entry Link Override',
                'name' => 'entry_link_override',
                'type' => 'url',
                'wrapper' => ['width' => '40'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_entry_pdf',
                'label' => 'Entry PDF',
                'name' => 'entry_pdf',
                'type' => 'file',
                'instructions' => 'Entry form PDF',
                'return_format' => 'id',
                'mime_types' => 'pdf',
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_tab_prices',
                'label' => 'Entry Prices',
                'type' => 'tab',
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_price_early',
                'label' => 'Early Bird Price',
                'name' => 'entry_price_early',
                'type' => 'number',
                'prepend' => '$',
                'wrapper' => ['width' => '33'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_price_regular',
                'label' => 'Regular Price',
                'name' => 'entry_price_regular',
                'type' => 'number',
                'prepend' => '$',
                'wrapper' => ['width' => '33'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_price_late',
                'label' => 'Late Price',
                'name' => 'entry_price_late',
                'type' => 'number',
                'prepend' => '$',
                'wrapper' => ['width' => '33'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_tab_dates',
                'label' => 'Entry Deadlines',
                'type' => 'tab',
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_date_early',
                'label' => 'Early Bird Deadline',
                'name' => 'entry_date_early',
                'type' => 'date_picker',
                'display_format' => 'F j, Y',
                'return_format' => 'Y-m-d',
                'wrapper' => ['width' => '33'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_date_regular',
                'label' => 'Regular Deadline',
                'name' => 'entry_date_regular',
                'type' => 'date_picker',
                'display_format' => 'F j, Y',
                'return_format' => 'Y-m-d',
                'wrapper' => ['width' => '33'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_date_late',
                'label' => 'Late Deadline',
                'name' => 'entry_date_late',
                'type' => 'date_picker',
                'display_format' => 'F j, Y',
                'return_format' => 'Y-m-d',
                'wrapper' => ['width' => '33'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_tab_deadlines',
                'label' => 'Other Deadlines',
                'type' => 'tab',
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_delivery_deadline',
                'label' => 'Product Delivery Deadline',
                'name' => 'product_delivery_deadline',
                'type' => 'date_picker',
                'display_format' => 'F j, Y',
                'return_format' => 'Y-m-d',
                'wrapper' => ['width' => '50'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_payment_deadline',
                'label' => 'Payment Deadline',
                'name' => 'payment_deadline',
                'type' => 'date_picker',
                'display_format' => 'F j, Y',
                'return_format' => 'Y-m-d',
                'wrapper' => ['width' => '50'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_tab_comp_dates',
                'label' => 'Competition Dates',
                'type' => 'tab',
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_comp_start',
                'label' => 'Competition Start',
                'name' => 'competition_date_start',
                'type' => 'date_picker',
                'display_format' => 'F j, Y',
                'return_format' => 'Y-m-d',
                'wrapper' => ['width' => '33'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_comp_end',
                'label' => 'Competition End',
                'name' => 'competition_date_end',
                'type' => 'date_picker',
                'display_format' => 'F j, Y',
                'return_format' => 'Y-m-d',
                'wrapper' => ['width' => '33'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_comp_text',
                'label' => 'Date Display Text',
                'name' => 'competition_date_text',
                'type' => 'text',
                'instructions' => 'e.g., "March 15-17, 2026"',
                'wrapper' => ['width' => '33'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_tab_winners',
                'label' => 'Winner Announcement',
                'type' => 'tab',
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_winner_date',
                'label' => 'Winner Announcement Date',
                'name' => 'winner_announcement_date',
                'type' => 'date_picker',
                'display_format' => 'F j, Y',
                'return_format' => 'Y-m-d',
                'wrapper' => ['width' => '50'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_winner_text',
                'label' => 'Announcement Display Text',
                'name' => 'winner_announcement_text',
                'type' => 'text',
                'wrapper' => ['width' => '50'],
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_tab_notes',
                'label' => 'Notes',
                'type' => 'tab',
            ],
            [
                'key' => 'field_apn_' . $prefix . 'year_notes',
                'label' => 'Entry Notes',
                'name' => 'entry_notes',
                'type' => 'textarea',
                'instructions' => 'Additional information for entrants',
                'rows' => 4,
            ],
        ];
    }

    /**
     * Load field values from main site's competition CPT
     *
     * @param mixed $value The value to preload
     * @param int $post_id The post ID (will be 'options' for options page)
     * @param array $field The field array
     * @return mixed The value from main site or original value
     */
    /**
     * Fields that should be synced from main site
     */
    /**
     * Get list of field names to sync between child site and main site
     */
    private function get_synced_field_names() {
        return [
            'competition_name',      // Special: maps to post_title
            'featured_image',        // Special: maps to post thumbnail
            'parent_category',       // Special: maps to taxonomy
            'product_type',          // Special: maps to taxonomy
            'region',                // Special: maps to taxonomy
            'abbreviation',
            'website_url',
            'short_summary',
            'logo',
            'card_background_image',
            'hero_image',
            'mini_banner',
            'product_image',
            'flare_image',
            'primary_color',
            'default_entry_page',
            'default_entry_link',
            'years',
        ];
    }

    /**
     * Generate HTML for displaying an image from main site with edit link
     *
     * @param string $field_name The field name (e.g., 'logo', 'hero_image')
     * @param string $label The display label
     * @param string $size The image size to display ('thumbnail', 'medium', 'large')
     * @return string HTML for the image preview
     */
    private function get_image_preview_html($field_name, $label, $size = 'medium') {
        $competition_id = $this->get_competition_for_current_site();
        if (!$competition_id) {
            return '<p><em>No competition linked</em></p>';
        }

        // Get attachment ID and URL from main site
        switch_to_blog(self::MAIN_SITE_ID);

        $attachment_id = get_post_meta($competition_id, $field_name, true);
        $image_url = $attachment_id ? wp_get_attachment_image_url($attachment_id, $size) : '';
        $full_url = $attachment_id ? wp_get_attachment_url($attachment_id) : '';

        restore_current_blog();

        // Build edit URL explicitly for main site (get_edit_post_link doesn't work in switch_to_blog context)
        $edit_url = get_admin_url(self::MAIN_SITE_ID, 'post.php?post=' . $competition_id . '&action=edit');

        $html = '<div style="margin-bottom: 10px;">';

        if ($image_url) {
            $html .= '<div style="margin-bottom: 8px;">';
            $html .= '<a href="' . esc_url($full_url) . '" target="_blank">';
            $html .= '<img src="' . esc_url($image_url) . '" style="max-width: 300px; max-height: 200px; border: 1px solid #ddd; border-radius: 4px;" />';
            $html .= '</a>';
            $html .= '</div>';
        } else {
            $html .= '<div style="padding: 20px; background: #f5f5f5; border: 1px dashed #ccc; border-radius: 4px; color: #666; margin-bottom: 8px;">';
            $html .= '<em>No image set</em>';
            $html .= '</div>';
        }

        $html .= '<a href="' . esc_url($edit_url) . '" target="_blank" class="button button-small">';
        $html .= $image_url ? 'Change Image' : 'Add Image';
        $html .= '</a>';
        $html .= ' <span class="description" style="margin-left: 8px;">Opens main site editor</span>';
        $html .= '</div>';

        return $html;
    }

    /**
     * Generate HTML for displaying the featured image from main site with edit link
     *
     * @param string $size The image size to display
     * @return string HTML for the image preview
     */
    private function get_featured_image_preview_html($size = 'medium') {
        $competition_id = $this->get_competition_for_current_site();
        if (!$competition_id) {
            return '<p><em>No competition linked</em></p>';
        }

        // Get featured image from main site
        switch_to_blog(self::MAIN_SITE_ID);

        $attachment_id = get_post_thumbnail_id($competition_id);
        $image_url = $attachment_id ? wp_get_attachment_image_url($attachment_id, $size) : '';
        $full_url = $attachment_id ? wp_get_attachment_url($attachment_id) : '';

        restore_current_blog();

        // Build edit URL explicitly for main site (get_edit_post_link doesn't work in switch_to_blog context)
        $edit_url = get_admin_url(self::MAIN_SITE_ID, 'post.php?post=' . $competition_id . '&action=edit');

        $html = '<div style="margin-bottom: 10px;">';

        if ($image_url) {
            $html .= '<div style="margin-bottom: 8px;">';
            $html .= '<a href="' . esc_url($full_url) . '" target="_blank">';
            $html .= '<img src="' . esc_url($image_url) . '" style="max-width: 300px; max-height: 200px; border: 1px solid #ddd; border-radius: 4px;" />';
            $html .= '</a>';
            $html .= '</div>';
        } else {
            $html .= '<div style="padding: 20px; background: #f5f5f5; border: 1px dashed #ccc; border-radius: 4px; color: #666; margin-bottom: 8px;">';
            $html .= '<em>No featured image set</em>';
            $html .= '</div>';
        }

        $html .= '<a href="' . esc_url($edit_url) . '" target="_blank" class="button button-small">';
        $html .= $image_url ? 'Change Featured Image' : 'Add Featured Image';
        $html .= '</a>';
        $html .= ' <span class="description" style="margin-left: 8px;">Opens main site editor</span>';
        $html .= '</div>';

        return $html;
    }

    /**
     * Generate HTML for displaying a PDF/file from main site with edit link
     *
     * @param string $field_name The field name
     * @param int $row_index The repeater row index (0-based)
     * @return string HTML for the file preview
     */
    private function get_file_preview_html($field_name, $row_index = null) {
        $competition_id = $this->get_competition_for_current_site();
        if (!$competition_id) {
            return '<p><em>No competition linked</em></p>';
        }

        // Build the meta key for repeater fields
        $meta_key = $row_index !== null ? "years_{$row_index}_{$field_name}" : $field_name;

        // Get attachment info from main site
        switch_to_blog(self::MAIN_SITE_ID);

        $attachment_id = get_post_meta($competition_id, $meta_key, true);
        $file_url = $attachment_id ? wp_get_attachment_url($attachment_id) : '';
        $file_name = $attachment_id ? basename(get_attached_file($attachment_id)) : '';

        restore_current_blog();

        // Build edit URL explicitly for main site (get_edit_post_link doesn't work in switch_to_blog context)
        $edit_url = get_admin_url(self::MAIN_SITE_ID, 'post.php?post=' . $competition_id . '&action=edit');

        $html = '<div style="margin-bottom: 10px;">';

        if ($file_url) {
            $html .= '<div style="padding: 10px; background: #f9f9f9; border: 1px solid #ddd; border-radius: 4px; margin-bottom: 8px;">';
            $html .= '<span class="dashicons dashicons-pdf" style="color: #cb4b16; margin-right: 5px;"></span>';
            $html .= '<a href="' . esc_url($file_url) . '" target="_blank">' . esc_html($file_name) . '</a>';
            $html .= '</div>';
        } else {
            $html .= '<div style="padding: 15px; background: #f5f5f5; border: 1px dashed #ccc; border-radius: 4px; color: #666; margin-bottom: 8px;">';
            $html .= '<em>No PDF uploaded</em>';
            $html .= '</div>';
        }

        $html .= '<a href="' . esc_url($edit_url) . '" target="_blank" class="button button-small">';
        $html .= $file_url ? 'Change PDF' : 'Add PDF';
        $html .= '</a>';
        $html .= ' <span class="description" style="margin-left: 8px;">Opens main site editor</span>';
        $html .= '</div>';

        return $html;
    }

    /**
     * Get the number of years this competition has been running
     * Counts the rows in the years repeater
     *
     * @return string HTML displaying the years count
     */
    private function get_years_count_html() {
        $competition_id = $this->get_competition_for_current_site();
        if (!$competition_id) {
            return '<p><em>No competition linked</em></p>';
        }

        // Get years count from main site
        switch_to_blog(self::MAIN_SITE_ID);
        $years_count = (int) get_post_meta($competition_id, 'years', true);
        restore_current_blog();

        $html = '<div style="padding: 12px 15px; background: #f0f6fc; border: 1px solid #c8d8e9; border-radius: 4px; display: inline-block;">';
        $html .= '<strong style="font-size: 24px; color: #0073aa;">' . $years_count . '</strong>';
        $html .= '<span style="margin-left: 8px; color: #555;">' . ($years_count === 1 ? 'year' : 'years') . '</span>';
        $html .= '</div>';

        return $html;
    }

    /**
     * Get the ordinal text for the annual edition (1st Annual, 2nd Annual, etc.)
     * Based on the number of years in the repeater
     *
     * @return string HTML displaying the annual edition text
     */
    private function get_annual_text_html() {
        $competition_id = $this->get_competition_for_current_site();
        if (!$competition_id) {
            return '<p><em>No competition linked</em></p>';
        }

        // Get years count from main site
        switch_to_blog(self::MAIN_SITE_ID);
        $years_count = (int) get_post_meta($competition_id, 'years', true);
        restore_current_blog();

        if ($years_count < 1) {
            return '<p><em>No years added yet</em></p>';
        }

        // Convert number to ordinal
        $ordinal = $this->number_to_ordinal($years_count);

        $html = '<div style="padding: 12px 15px; background: #fef9e7; border: 1px solid #f0c36d; border-radius: 4px; display: inline-block;">';
        $html .= '<strong style="font-size: 18px; color: #856404;">' . $ordinal . ' Annual</strong>';
        $html .= '</div>';

        return $html;
    }

    /**
     * Convert a number to its ordinal form (1st, 2nd, 3rd, etc.)
     *
     * @param int $number The number to convert
     * @return string The ordinal string
     */
    private function number_to_ordinal($number) {
        $ends = ['th', 'st', 'nd', 'rd', 'th', 'th', 'th', 'th', 'th', 'th'];

        if (($number % 100) >= 11 && ($number % 100) <= 13) {
            return $number . 'th';
        }

        return $number . $ends[$number % 10];
    }

    /**
     * Get taxonomy term choices for select fields
     * Fetches from main site
     */
    private function get_taxonomy_choices() {
        $choices = [
            'apn_parent_category' => [],
            'apn_product_type' => [],
            'apn_region' => [],
        ];

        // Query taxonomy terms directly from main site's database
        // We can't use get_terms() because the taxonomy isn't registered after switch_to_blog()
        global $wpdb;

        switch_to_blog(self::MAIN_SITE_ID);

        foreach (array_keys($choices) as $taxonomy) {
            // Direct database query for terms
            $terms = $wpdb->get_results($wpdb->prepare(
                "SELECT t.term_id, t.name, tt.parent
                FROM {$wpdb->terms} t
                INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
                WHERE tt.taxonomy = %s
                ORDER BY t.name ASC",
                $taxonomy
            ));

            if ($terms) {
                foreach ($terms as $term) {
                    // For hierarchical taxonomies (region), show the hierarchy
                    $prefix = '';
                    if ($taxonomy === 'apn_region' && $term->parent) {
                        // Count ancestors for indentation
                        $parent_id = $term->parent;
                        $depth = 0;
                        while ($parent_id && $depth < 10) {
                            $parent = $wpdb->get_var($wpdb->prepare(
                                "SELECT parent FROM {$wpdb->term_taxonomy} WHERE term_id = %d",
                                $parent_id
                            ));
                            $depth++;
                            $parent_id = $parent;
                        }
                        $prefix = str_repeat('— ', $depth);
                    }
                    $choices[$taxonomy][$term->term_id] = $prefix . $term->name;
                }
            }
        }

        restore_current_blog();

        return $choices;
    }

    /**
     * Dynamically load taxonomy choices for select fields
     * Called via acf/load_field filter to ensure fresh data
     *
     * @param array $field The field array
     * @return array Modified field with choices
     */
    public function load_taxonomy_choices($field) {
        // Only on child sites
        if ($this->is_main_site()) {
            return $field;
        }

        // Map field keys to taxonomy names
        $field_to_taxonomy = [
            'field_apn_opt_parent_category' => 'apn_parent_category',
            'field_apn_opt_product_type' => 'apn_product_type',
            'field_apn_opt_region' => 'apn_region',
        ];

        $field_key = isset($field['key']) ? $field['key'] : '';
        if (!isset($field_to_taxonomy[$field_key])) {
            return $field;
        }

        $taxonomy = $field_to_taxonomy[$field_key];

        // Query taxonomy terms directly from main site's database
        // We can't use get_terms() because the taxonomy isn't registered after switch_to_blog()
        global $wpdb;

        switch_to_blog(self::MAIN_SITE_ID);

        $terms = $wpdb->get_results($wpdb->prepare(
            "SELECT t.term_id, t.name, tt.parent
            FROM {$wpdb->terms} t
            INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id
            WHERE tt.taxonomy = %s
            ORDER BY t.name ASC",
            $taxonomy
        ));

        $choices = [];
        if ($terms) {
            foreach ($terms as $term) {
                // For hierarchical taxonomies (region), show the hierarchy
                $prefix = '';
                if ($taxonomy === 'apn_region' && $term->parent) {
                    // Count ancestors for indentation
                    $parent_id = $term->parent;
                    $depth = 0;
                    while ($parent_id && $depth < 10) {
                        $parent = $wpdb->get_var($wpdb->prepare(
                            "SELECT parent FROM {$wpdb->term_taxonomy} WHERE term_id = %d",
                            $parent_id
                        ));
                        $depth++;
                        $parent_id = $parent;
                    }
                    $prefix = str_repeat('— ', $depth);
                }
                $choices[$term->term_id] = $prefix . $term->name;
            }
        }

        restore_current_blog();

        $field['choices'] = $choices;
        return $field;
    }

    /**
     * Convert entry_pdf field to read-only preview on child sites
     * This runs for each row in the repeater, showing the actual PDF with edit link
     *
     * @param array $field The field array
     * @return array Modified field
     */
    public function prepare_entry_pdf_field($field) {
        // Only on child sites
        if ($this->is_main_site()) {
            return $field;
        }

        // Extract row index from the field's prefix
        // Prefix format: acf[field_apn_opt_years][row-0] -> row index is 0
        $prefix = isset($field['prefix']) ? $field['prefix'] : '';
        if (preg_match('/\[row-(\d+)\]/', $prefix, $matches)) {
            $row_index = (int) $matches[1];

            // Change to message field with PDF preview
            $field['type'] = 'message';
            $field['message'] = $this->get_file_preview_html('entry_pdf', $row_index);
            $field['esc_html'] = 0;
            // Remove file-specific settings
            unset($field['return_format']);
            unset($field['mime_types']);
        }

        return $field;
    }

    public function load_value_from_main_site($value, $post_id, $field) {
        // Only on child sites
        if ($this->is_main_site()) {
            return $value;
        }

        // Only intercept options page loads
        if ($post_id !== 'options') {
            return $value;
        }

        $field_name = isset($field['name']) ? $field['name'] : '';

        // Only intercept our synced fields (check by field name)
        // Note: years repeater is handled by the pre_option filter, not here
        if (!in_array($field_name, $this->get_synced_field_names())) {
            return $value;
        }

        $competition_id = $this->get_competition_for_current_site();
        if (!$competition_id) {
            return $value;
        }

        // Switch to main site and get the value
        switch_to_blog(self::MAIN_SITE_ID);

        // Handle special fields differently
        switch ($field_name) {
            case 'competition_name':
                // Get the post title
                $main_value = get_the_title($competition_id);
                break;

            case 'featured_image':
                // Get the post thumbnail ID
                $main_value = get_post_thumbnail_id($competition_id);
                break;

            case 'parent_category':
                // Get taxonomy term IDs (single) - use direct DB query
                // wp_get_post_terms() doesn't work after switch_to_blog() since taxonomy isn't registered
                global $wpdb;
                $term_ids = $wpdb->get_col($wpdb->prepare(
                    "SELECT tt.term_id
                    FROM {$wpdb->term_relationships} tr
                    INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
                    WHERE tr.object_id = %d AND tt.taxonomy = %s",
                    $competition_id,
                    'apn_parent_category'
                ));
                $main_value = !empty($term_ids) ? (int) $term_ids[0] : '';
                break;

            case 'product_type':
                // Get taxonomy term IDs (multiple) - use direct DB query
                global $wpdb;
                $term_ids = $wpdb->get_col($wpdb->prepare(
                    "SELECT tt.term_id
                    FROM {$wpdb->term_relationships} tr
                    INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
                    WHERE tr.object_id = %d AND tt.taxonomy = %s",
                    $competition_id,
                    'apn_product_type'
                ));
                $main_value = !empty($term_ids) ? array_map('intval', $term_ids) : [];
                break;

            case 'region':
                // Get taxonomy term IDs (multiple) - use direct DB query
                global $wpdb;
                $term_ids = $wpdb->get_col($wpdb->prepare(
                    "SELECT tt.term_id
                    FROM {$wpdb->term_relationships} tr
                    INNER JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
                    WHERE tr.object_id = %d AND tt.taxonomy = %s",
                    $competition_id,
                    'apn_region'
                ));
                $main_value = !empty($term_ids) ? array_map('intval', $term_ids) : [];
                break;

            case 'years':
                // Let the pre_option filter handle repeater loading
                // Return the original value so ACF proceeds with normal loading
                // (which will hit our pre_option filter for each option key)
                restore_current_blog();
                return $value;

            default:
                // Regular ACF field
                $main_value = get_field($field_name, $competition_id);
                break;
        }

        restore_current_blog();

        // Return the value from main site (or null which lets ACF show empty)
        return $main_value !== null ? $main_value : $value;
    }

    /**
     * Load a years repeater subfield value from main site
     *
     * @param int $row_index The row index (0-based)
     * @param string $subfield_name The subfield name (e.g., "year", "entry_price_early")
     * @return mixed The value from main site
     */
    private function load_years_subfield($row_index, $subfield_name) {
        $competition_id = $this->get_competition_for_current_site();
        if (!$competition_id) {
            return null;
        }

        // Build the meta key (e.g., "years_0_year")
        $meta_key = "years_{$row_index}_{$subfield_name}";

        switch_to_blog(self::MAIN_SITE_ID);
        $value = get_post_meta($competition_id, $meta_key, true);
        restore_current_blog();

        return $value;
    }

    /**
     * Intercept WordPress option reads for ACF repeater subfields
     * ACF stores options page data in wp_options with keys like "options_years_0_year"
     * Field key references are stored with underscore prefix: "_options_years_0_year"
     *
     * @param mixed $value The pre-option value (false to continue normal lookup)
     * @param string $option The option name
     * @param mixed $default The default value
     * @return mixed The value from main site or false to continue
     */
    public function intercept_option_read($value, $option, $default) {
        // Only on child sites
        if ($this->is_main_site()) {
            return $value;
        }

        // Check if this is an ACF options field for years repeater or CTA fields
        // Pattern: options_years* or options_cta_* (values) or _options_years* or _options_cta_* (field key references)
        if (!preg_match('/^(_?)options_((years|cta_).*)$/', $option, $matches)) {
            return $value;
        }

        $is_field_key_ref = ($matches[1] === '_');
        $meta_suffix = $matches[2]; // e.g., "years" or "years_0_year"

        // Build the meta key - add underscore prefix for field key references
        $meta_key = ($is_field_key_ref ? '_' : '') . $meta_suffix;

        $competition_id = $this->get_competition_for_current_site();
        if (!$competition_id) {
            return $value;
        }

        // Get the value from main site's post meta
        switch_to_blog(self::MAIN_SITE_ID);
        $main_value = get_post_meta($competition_id, $meta_key, true);
        restore_current_blog();

        // For field key references, map main site keys to options page keys
        if ($is_field_key_ref && $main_value) {
            $main_value = $this->map_field_key_to_options($main_value);
        }

        // Return the value (empty string if not found, which tells WP it exists but is empty)
        return $main_value !== '' ? $main_value : $default;
    }

    /**
     * Map main site field keys to options page field keys
     * Main site uses field_apn_*, options page uses field_apn_opt_*
     *
     * @param string $field_key The main site field key
     * @return string The mapped options page field key
     */
    private function map_field_key_to_options($field_key) {
        $mapping = [
            // Parent repeater
            'field_apn_years' => 'field_apn_opt_years',
            // Year subfields
            'field_apn_year_number' => 'field_apn_opt_year_number',
            'field_apn_year_entry_page' => 'field_apn_opt_year_entry_page',
            'field_apn_year_entry_link' => 'field_apn_opt_year_entry_link',
            'field_apn_year_entry_pdf' => 'field_apn_opt_year_entry_pdf',
            'field_apn_year_price_early' => 'field_apn_opt_year_price_early',
            'field_apn_year_price_regular' => 'field_apn_opt_year_price_regular',
            'field_apn_year_price_late' => 'field_apn_opt_year_price_late',
            'field_apn_year_date_early' => 'field_apn_opt_year_date_early',
            'field_apn_year_date_regular' => 'field_apn_opt_year_date_regular',
            'field_apn_year_date_late' => 'field_apn_opt_year_date_late',
            'field_apn_year_delivery_deadline' => 'field_apn_opt_year_delivery_deadline',
            'field_apn_year_payment_deadline' => 'field_apn_opt_year_payment_deadline',
            'field_apn_year_comp_start' => 'field_apn_opt_year_comp_start',
            'field_apn_year_comp_end' => 'field_apn_opt_year_comp_end',
            'field_apn_year_comp_text' => 'field_apn_opt_year_comp_text',
            'field_apn_year_winner_date' => 'field_apn_opt_year_winner_date',
            'field_apn_year_winner_text' => 'field_apn_opt_year_winner_text',
            'field_apn_year_notes' => 'field_apn_opt_year_notes',
        ];

        if (isset($mapping[$field_key])) {
            return $mapping[$field_key];
        }

        // CTA fields: field_apn_cta_* maps directly (same key used on both sides)
        if (strpos($field_key, 'field_apn_cta_') === 0) {
            return $field_key;
        }

        return $field_key;
    }

    /**
     * Save field values to main site's competition CPT
     *
     * @param int|string $post_id The post ID being saved
     */
    public function save_to_main_site($post_id) {
        // Only on child sites
        if ($this->is_main_site()) {
            return;
        }

        // Only intercept options page saves
        if ($post_id !== 'options') {
            return;
        }

        // Check if this is our options page
        $screen = get_current_screen();
        if (!$screen || strpos($screen->id, self::OPTIONS_PAGE_SLUG) === false) {
            return;
        }

        $competition_id = $this->get_competition_for_current_site();
        if (!$competition_id) {
            return;
        }

        // Get values from $_POST and save to main site
        $fields_to_sync = $this->get_synced_field_names();
        switch_to_blog(self::MAIN_SITE_ID);

        foreach ($fields_to_sync as $field_name) {
            // ACF posts field values with 'acf' prefix
            if (!isset($_POST['acf'])) {
                continue;
            }

            // Find the field key for this field name in our options fields
            $field_key = $this->get_options_field_key($field_name);
            if (!$field_key || !isset($_POST['acf'][$field_key])) {
                continue;
            }

            $value = $_POST['acf'][$field_key];

            // Handle special fields differently
            switch ($field_name) {
                case 'competition_name':
                    // Update the post title
                    wp_update_post([
                        'ID' => $competition_id,
                        'post_title' => sanitize_text_field($value),
                    ]);
                    break;

                case 'featured_image':
                    // Update the post thumbnail
                    if ($value) {
                        set_post_thumbnail($competition_id, intval($value));
                    } else {
                        delete_post_thumbnail($competition_id);
                    }
                    break;

                case 'parent_category':
                    // Update taxonomy (single term)
                    $term_id = intval($value);
                    if ($term_id) {
                        wp_set_post_terms($competition_id, [$term_id], 'apn_parent_category');
                    } else {
                        wp_set_post_terms($competition_id, [], 'apn_parent_category');
                    }
                    break;

                case 'product_type':
                    // Update taxonomy (multiple terms)
                    $term_ids = is_array($value) ? array_map('intval', $value) : [];
                    wp_set_post_terms($competition_id, $term_ids, 'apn_product_type');
                    break;

                case 'region':
                    // Update taxonomy (multiple terms)
                    $term_ids = is_array($value) ? array_map('intval', $value) : [];
                    wp_set_post_terms($competition_id, $term_ids, 'apn_region');
                    break;

                default:
                    // Regular ACF field
                    update_field($field_name, $value, $competition_id);
                    break;
            }
        }

        // Save CTA fields (dynamic: any field key starting with field_apn_cta_)
        if (isset($_POST['acf'])) {
            foreach ($_POST['acf'] as $field_key => $value) {
                if (strpos($field_key, 'field_apn_cta_') === 0) {
                    // Derive the meta key from the field key: field_apn_cta_early_bird_activation_date -> cta_early_bird_activation_date
                    $acf_field = acf_get_field($field_key);
                    if ($acf_field && !empty($acf_field['name'])) {
                        update_post_meta($competition_id, $acf_field['name'], sanitize_text_field($value));
                    }
                }
            }
        }

        restore_current_blog();

        // Prevent ACF from saving to local options
        // We do this by removing our fields from $_POST['acf']
        if (isset($_POST['acf'])) {
            foreach ($fields_to_sync as $field_name) {
                $field_key = $this->get_options_field_key($field_name);
                if ($field_key) {
                    unset($_POST['acf'][$field_key]);
                }
            }

            // Also remove CTA fields from local save
            foreach (array_keys($_POST['acf']) as $field_key) {
                if (strpos($field_key, 'field_apn_cta_') === 0) {
                    unset($_POST['acf'][$field_key]);
                }
            }
        }
    }

    /**
     * Get the options page field key for a field name
     *
     * @param string $field_name The field name
     * @return string|null The field key or null
     */
    private function get_options_field_key($field_name) {
        $mapping = [
            'competition_name' => 'field_apn_opt_competition_name',
            'featured_image' => 'field_apn_opt_featured_image',
            'parent_category' => 'field_apn_opt_parent_category',
            'product_type' => 'field_apn_opt_product_type',
            'region' => 'field_apn_opt_region',
            'abbreviation' => 'field_apn_opt_abbreviation',
            'website_url' => 'field_apn_opt_website_url',
            'short_summary' => 'field_apn_opt_short_summary',
            'logo' => 'field_apn_opt_logo',
            'card_background_image' => 'field_apn_opt_card_bg',
            'hero_image' => 'field_apn_opt_hero_image',
            'mini_banner' => 'field_apn_opt_mini_banner',
            'product_image' => 'field_apn_opt_product_image',
            'flare_image' => 'field_apn_opt_flare_image',
            'primary_color' => 'field_apn_opt_primary_color',
            'default_entry_page' => 'field_apn_opt_default_entry_page',
            'default_entry_link' => 'field_apn_opt_default_entry_link',
            'years' => 'field_apn_opt_years',
        ];
        return isset($mapping[$field_name]) ? $mapping[$field_name] : null;
    }
}

// Initialize both classes
APN_Competitions::get_instance();
APN_Competition_Sync::get_instance();
