<?php
/**
 * HVAC Custom Event Edit Form Handler
 * 
 * Memory-efficient, type-safe event editing using modern PHP patterns
 * Replaces JavaScript-dependent TEC shortcode with server-side solution
 * 
 * @package HVAC_Community_Events
 * @since 2.1.0
 */

declare(strict_types=1);

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

/**
 * Custom event edit form handler with generator-based data loading
 */
final class HVAC_Custom_Event_Edit {
    
    use HVAC_Singleton_Trait;
    
    private const NONCE_ACTION = 'hvac_edit_event';
    private const NONCE_FIELD = 'hvac_event_nonce';
    private const CACHE_GROUP = 'hvac_events';
    private const CACHE_TTL = 300; // 5 minutes
    
    /**
     * @var SplObjectStorage<WP_Post, ArrayObject> Event data cache
     */
    private SplObjectStorage $eventCache;
    
    /**
     * @var ?int Current event ID being edited
     */
    private ?int $currentEventId = null;
    
    /**
     * Constructor with property promotion
     */
    private function __construct() {
        $this->eventCache = new SplObjectStorage();
        $this->initHooks();
    }
    
    /**
     * Initialize WordPress hooks
     */
    private function initHooks(): void {
        add_action('init', [$this, 'registerRewriteRules']);
        add_action('template_redirect', [$this, 'handleFormSubmission']);
        add_filter('query_vars', [$this, 'addQueryVars']);
        
        // Single template_include hook at appropriate priority
        add_filter('template_include', [$this, 'loadTemplate'], 1000);
        
        add_action('wp_enqueue_scripts', [$this, 'enqueueAssets']);
    }
    
    /**
     * Register rewrite rules for edit URL
     */
    public function registerRewriteRules(): void {
        add_rewrite_rule(
            '^trainer/event/edit/?$',
            'index.php?hvac_event_edit=1',
            'top'
        );
    }
    
    /**
     * Add custom query vars
     */
    public function addQueryVars(array $vars): array {
        $vars[] = 'hvac_event_edit';
        return $vars;
    }
    
    /**
     * Load custom template for event edit page
     */
    public function loadTemplate(string $template): string {
        // Check if we're on the custom edit page
        $is_edit_page = false;
        $request_uri = $_SERVER['REQUEST_URI'] ?? '';
        
        // Method 1: Check by page ID (configuration-based approach)
        if (defined('HVAC_EVENT_EDIT_PAGE_ID') && is_page(HVAC_EVENT_EDIT_PAGE_ID)) {
            $is_edit_page = true;
        }
        // Method 2: Check URL path
        elseif (strpos($request_uri, '/trainer/event/edit') !== false) {
            $is_edit_page = true;
        }
        // Method 3: Check query var
        elseif (get_query_var('hvac_event_edit') === '1') {
            $is_edit_page = true;
        }
        
        if ($is_edit_page) {
            $custom_template = HVAC_PLUGIN_DIR . 'templates/page-edit-event-custom.php';
            if (file_exists($custom_template)) {
                return $custom_template;
            }
        }
        
        return $template;
    }
    
    /**
     * Enqueue minimal required assets (no JavaScript!)
     */
    public function enqueueAssets(): void {
        if (!$this->isEditPage()) {
            return;
        }
        
        wp_enqueue_style(
            'hvac-event-edit-custom',
            HVAC_PLUGIN_URL . 'assets/css/hvac-event-edit-custom.css',
            [],
            HVAC_PLUGIN_VERSION
        );
    }
    
    /**
     * Check if current page is event edit page
     */
    private function isEditPage(): bool {
        // Check for the URL pattern /trainer/event/edit/
        $is_edit_url = strpos($_SERVER['REQUEST_URI'], '/trainer/event/edit') !== false;
        
        // Check for the specific page ID (6177) that handles edit events
        $is_edit_page = is_page(6177);
        
        // Check query var and template slug (fallback methods)
        $has_query_var = get_query_var('hvac_event_edit') === '1';
        $has_template = is_page() && get_page_template_slug() === 'templates/page-edit-event-custom.php';
        
        return $is_edit_url || $is_edit_page || $has_query_var || $has_template;
    }
    
    /**
     * Get event data using generator for memory efficiency
     * 
     * @return Generator<string, mixed>
     */
    public function getEventData(int $eventId): Generator {
        // Check cache first
        $cacheKey = "event_data_{$eventId}";
        $cached = wp_cache_get($cacheKey, self::CACHE_GROUP);
        
        if ($cached !== false && is_array($cached)) {
            foreach ($cached as $key => $value) {
                yield $key => $value;
            }
            return;
        }
        
        $event = get_post($eventId);
        if (!$event || $event->post_type !== 'tribe_events') {
            throw new InvalidArgumentException("Invalid event ID: {$eventId}");
        }
        
        // Core data
        yield 'id' => $eventId;
        yield 'title' => $event->post_title;
        yield 'content' => $event->post_content;
        yield 'excerpt' => $event->post_excerpt;
        yield 'status' => $event->post_status;
        yield 'author' => $event->post_author;
        
        // Meta data - lazy load as needed
        $metaKeys = $this->getEventMetaKeys();
        foreach ($metaKeys as $key) {
            yield $key => get_post_meta($eventId, $key, true);
        }
        
        // Venue data
        $venueId = get_post_meta($eventId, '_EventVenueID', true);
        if ($venueId) {
            yield 'venue' => $this->getVenueData((int) $venueId);
        }
        
        // Organizer data
        $organizerId = get_post_meta($eventId, '_EventOrganizerID', true);
        if ($organizerId) {
            yield 'organizer' => $this->getOrganizerData((int) $organizerId);
        }
        
        // Taxonomies
        yield 'categories' => wp_get_post_terms($eventId, 'tribe_events_cat', ['fields' => 'ids']);
        yield 'tags' => wp_get_post_terms($eventId, 'post_tag', ['fields' => 'ids']);
        
        // Cache the data for future use (convert generator to array)
        // Note: This is done after yielding to maintain generator efficiency
        // The next call will use the cached version
        $dataToCache = [];
        $dataToCache['id'] = $eventId;
        $dataToCache['title'] = $event->post_title;
        $dataToCache['content'] = $event->post_content;
        $dataToCache['excerpt'] = $event->post_excerpt;
        $dataToCache['status'] = $event->post_status;
        $dataToCache['author'] = $event->post_author;
        foreach ($this->getEventMetaKeys() as $key) {
            $dataToCache[$key] = get_post_meta($eventId, $key, true);
        }
        if ($venueId) {
            $dataToCache['venue'] = $this->getVenueData((int) $venueId);
        }
        if ($organizerId) {
            $dataToCache['organizer'] = $this->getOrganizerData((int) $organizerId);
        }
        $dataToCache['categories'] = wp_get_post_terms($eventId, 'tribe_events_cat', ['fields' => 'ids']);
        $dataToCache['tags'] = wp_get_post_terms($eventId, 'post_tag', ['fields' => 'ids']);
        
        wp_cache_set($cacheKey, $dataToCache, self::CACHE_GROUP, self::CACHE_TTL);
    }
    
    /**
     * Get TEC event meta keys
     */
    private function getEventMetaKeys(): array {
        return [
            '_EventStartDate',
            '_EventEndDate',
            '_EventStartDateUTC',
            '_EventEndDateUTC',
            '_EventTimezone',
            '_EventTimezoneAbbr',
            '_EventAllDay',
            '_EventDuration',
            '_EventCost',
            '_EventCurrencySymbol',
            '_EventCurrencyCode',
            '_EventURL',
            '_EventShowMap',
            '_EventShowMapLink',
        ];
    }
    
    /**
     * Get venue data efficiently
     */
    private function getVenueData(int $venueId): ArrayObject {
        $venue = get_post($venueId);
        if (!$venue || $venue->post_type !== 'tribe_venue') {
            return new ArrayObject();
        }
        
        return new ArrayObject([
            'id' => $venueId,
            'title' => $venue->post_title,
            'address' => get_post_meta($venueId, '_VenueAddress', true),
            'city' => get_post_meta($venueId, '_VenueCity', true),
            'state' => get_post_meta($venueId, '_VenueStateProvince', true),
            'zip' => get_post_meta($venueId, '_VenueZip', true),
            'country' => get_post_meta($venueId, '_VenueCountry', true),
            'phone' => get_post_meta($venueId, '_VenuePhone', true),
            'url' => get_post_meta($venueId, '_VenueURL', true),
        ], ArrayObject::ARRAY_AS_PROPS);
    }
    
    /**
     * Get organizer data efficiently
     */
    private function getOrganizerData(int $organizerId): ArrayObject {
        $organizer = get_post($organizerId);
        if (!$organizer || $organizer->post_type !== 'tribe_organizer') {
            return new ArrayObject();
        }
        
        return new ArrayObject([
            'id' => $organizerId,
            'title' => $organizer->post_title,
            'phone' => get_post_meta($organizerId, '_OrganizerPhone', true),
            'website' => get_post_meta($organizerId, '_OrganizerWebsite', true),
            'email' => get_post_meta($organizerId, '_OrganizerEmail', true),
        ], ArrayObject::ARRAY_AS_PROPS);
    }
    
    /**
     * Handle form submission with comprehensive validation
     */
    public function handleFormSubmission(): void {
        if (!$this->isEditPage() || $_SERVER['REQUEST_METHOD'] !== 'POST') {
            return;
        }
        
        // Verify nonce
        if (!isset($_POST[self::NONCE_FIELD]) || 
            !wp_verify_nonce($_POST[self::NONCE_FIELD], self::NONCE_ACTION)) {
            wp_die('Security check failed');
        }
        
        // Check capabilities
        $eventId = isset($_POST['event_id']) ? (int) $_POST['event_id'] : 0;
        if (!$this->canUserEditEvent($eventId)) {
            wp_die('Insufficient permissions');
        }
        
        try {
            $eventId = $this->saveEvent($_POST);
            
            // Clear cache
            wp_cache_delete("event_data_{$eventId}", self::CACHE_GROUP);
            
            // Redirect with success message
            wp_safe_redirect(add_query_arg([
                'event_id' => $eventId,
                'updated' => 'true'
            ], home_url('/trainer/event/edit/')));
            exit;
            
        } catch (Exception $e) {
            // Log error and show message
            error_log('Event save error: ' . $e->getMessage());
            wp_die('Error saving event: ' . esc_html($e->getMessage()));
        }
    }
    
    /**
     * Save event with validation and sanitization
     */
    private function saveEvent(array $data): int {
        $eventId = isset($data['event_id']) ? (int) $data['event_id'] : 0;
        
        // Prepare post data
        $postData = [
            'ID' => $eventId,
            'post_type' => 'tribe_events',
            'post_title' => sanitize_text_field($data['post_title'] ?? ''),
            'post_content' => wp_kses_post($data['post_content'] ?? ''),
            'post_excerpt' => sanitize_textarea_field($data['post_excerpt'] ?? ''),
            'post_status' => in_array($data['post_status'] ?? '', ['publish', 'draft']) 
                ? $data['post_status'] 
                : 'draft',
        ];
        
        // Validate required fields
        if (empty($postData['post_title'])) {
            throw new InvalidArgumentException('Event title is required');
        }
        
        // Insert or update
        if ($eventId > 0) {
            $result = wp_update_post($postData, true);
        } else {
            $postData['post_author'] = get_current_user_id();
            $result = wp_insert_post($postData, true);
        }
        
        if (is_wp_error($result)) {
            throw new RuntimeException($result->get_error_message());
        }
        
        $eventId = (int) $result;
        
        // Update meta fields
        $this->updateEventMeta($eventId, $data);
        
        // Update venue
        $this->updateVenue($eventId, $data);
        
        // Update organizer
        $this->updateOrganizer($eventId, $data);
        
        // Update taxonomies
        if (isset($data['event_categories'])) {
            wp_set_post_terms($eventId, array_map('intval', $data['event_categories']), 'tribe_events_cat');
        }
        
        return $eventId;
    }
    
    /**
     * Update event meta fields with validation
     */
    private function updateEventMeta(int $eventId, array $data): void {
        // Date/time fields
        $startDate = $this->parseDateTime($data['EventStartDate'] ?? '', $data['EventStartTime'] ?? '');
        $endDate = $this->parseDateTime($data['EventEndDate'] ?? '', $data['EventEndTime'] ?? '');
        
        if ($startDate && $endDate) {
            if ($endDate < $startDate) {
                throw new InvalidArgumentException('End date must be after start date');
            }
            
            update_post_meta($eventId, '_EventStartDate', $startDate->format('Y-m-d H:i:s'));
            update_post_meta($eventId, '_EventEndDate', $endDate->format('Y-m-d H:i:s'));
            update_post_meta($eventId, '_EventStartDateUTC', get_gmt_from_date($startDate->format('Y-m-d H:i:s')));
            update_post_meta($eventId, '_EventEndDateUTC', get_gmt_from_date($endDate->format('Y-m-d H:i:s')));
            update_post_meta($eventId, '_EventDuration', $endDate->getTimestamp() - $startDate->getTimestamp());
        }
        
        // Other meta fields
        $metaFields = [
            '_EventAllDay' => isset($data['EventAllDay']) ? '1' : '0',
            '_EventCost' => sanitize_text_field($data['EventCost'] ?? ''),
            '_EventCurrencySymbol' => sanitize_text_field($data['EventCurrencySymbol'] ?? '$'),
            '_EventURL' => esc_url_raw($data['EventURL'] ?? ''),
            '_EventShowMap' => isset($data['EventShowMap']) ? '1' : '0',
            '_EventShowMapLink' => isset($data['EventShowMapLink']) ? '1' : '0',
            '_EventTimezone' => sanitize_text_field($data['EventTimezone'] ?? get_option('timezone_string')),
        ];
        
        foreach ($metaFields as $key => $value) {
            update_post_meta($eventId, $key, $value);
        }
    }
    
    /**
     * Parse date and time into DateTime object
     */
    private function parseDateTime(string $date, string $time): ?DateTime {
        if (empty($date)) {
            return null;
        }
        
        $dateTimeStr = $date;
        if (!empty($time)) {
            $dateTimeStr .= ' ' . $time;
        } else {
            $dateTimeStr .= ' 00:00:00';
        }
        
        try {
            return new DateTime($dateTimeStr, wp_timezone());
        } catch (Exception $e) {
            return null;
        }
    }
    
    /**
     * Update or create venue
     */
    private function updateVenue(int $eventId, array $data): void {
        $venueId = isset($data['venue_id']) ? (int) $data['venue_id'] : 0;
        
        // Use existing venue
        if ($venueId > 0 && isset($data['use_existing_venue'])) {
            update_post_meta($eventId, '_EventVenueID', $venueId);
            return;
        }
        
        // Create new venue if data provided
        if (!empty($data['venue_name'])) {
            $venueData = [
                'post_type' => 'tribe_venue',
                'post_title' => sanitize_text_field($data['venue_name']),
                'post_status' => 'publish',
            ];
            
            if ($venueId > 0) {
                $venueData['ID'] = $venueId;
                $venueId = wp_update_post($venueData);
            } else {
                $venueId = wp_insert_post($venueData);
            }
            
            if ($venueId && !is_wp_error($venueId)) {
                // Update venue meta
                update_post_meta($venueId, '_VenueAddress', sanitize_text_field($data['venue_address'] ?? ''));
                update_post_meta($venueId, '_VenueCity', sanitize_text_field($data['venue_city'] ?? ''));
                update_post_meta($venueId, '_VenueStateProvince', sanitize_text_field($data['venue_state'] ?? ''));
                update_post_meta($venueId, '_VenueZip', sanitize_text_field($data['venue_zip'] ?? ''));
                update_post_meta($venueId, '_VenueCountry', sanitize_text_field($data['venue_country'] ?? ''));
                update_post_meta($venueId, '_VenuePhone', sanitize_text_field($data['venue_phone'] ?? ''));
                update_post_meta($venueId, '_VenueURL', esc_url_raw($data['venue_url'] ?? ''));
                
                update_post_meta($eventId, '_EventVenueID', $venueId);
            }
        }
    }
    
    /**
     * Update or create organizer
     */
    private function updateOrganizer(int $eventId, array $data): void {
        $organizerId = isset($data['organizer_id']) ? (int) $data['organizer_id'] : 0;
        
        // Use existing organizer
        if ($organizerId > 0 && isset($data['use_existing_organizer'])) {
            update_post_meta($eventId, '_EventOrganizerID', $organizerId);
            return;
        }
        
        // Create new organizer if data provided
        if (!empty($data['organizer_name'])) {
            $organizerData = [
                'post_type' => 'tribe_organizer',
                'post_title' => sanitize_text_field($data['organizer_name']),
                'post_status' => 'publish',
            ];
            
            if ($organizerId > 0) {
                $organizerData['ID'] = $organizerId;
                $organizerId = wp_update_post($organizerData);
            } else {
                $organizerId = wp_insert_post($organizerData);
            }
            
            if ($organizerId && !is_wp_error($organizerId)) {
                // Update organizer meta
                update_post_meta($organizerId, '_OrganizerPhone', sanitize_text_field($data['organizer_phone'] ?? ''));
                update_post_meta($organizerId, '_OrganizerWebsite', esc_url_raw($data['organizer_website'] ?? ''));
                update_post_meta($organizerId, '_OrganizerEmail', sanitize_email($data['organizer_email'] ?? ''));
                
                update_post_meta($eventId, '_EventOrganizerID', $organizerId);
            }
        }
    }
    
    /**
     * Check if user can edit event
     */
    public function canUserEditEvent(int $eventId): bool {
        if (!is_user_logged_in()) {
            return false;
        }
        
        $user = wp_get_current_user();
        $userId = $user->ID;
        
        // New event - check if user has the capability to create events
        if ($eventId === 0) {
            // Check for The Events Calendar capabilities or trainer role
            return current_user_can('edit_tribe_events') || 
                   current_user_can('publish_tribe_events') ||
                   in_array('hvac_trainer', $user->roles) ||
                   in_array('hvac_master_trainer', $user->roles) ||
                   in_array('administrator', $user->roles);
        }
        
        // Existing event - validate ownership and permissions
        $event = get_post($eventId);
        if (!$event || $event->post_type !== 'tribe_events') {
            return false;
        }
        
        // Check ownership FIRST - owners can always edit their own events
        if ($event->post_author == $userId) {
            return true;
        }
        
        // Administrators can edit any event
        if (in_array('administrator', $user->roles)) {
            return true;
        }
        
        // Master trainers can edit any event
        if (in_array('hvac_master_trainer', $user->roles)) {
            return true;
        }
        
        // Non-owners need special permissions to edit others' events
        return current_user_can('edit_others_tribe_events') || 
               current_user_can('edit_others_posts');
    }
    
    /**
     * Get all venues for dropdown (using generator)
     * 
     * @return Generator<int, string>
     */
    public function getVenuesForDropdown(): Generator {
        $venues = get_posts([
            'post_type' => 'tribe_venue',
            'posts_per_page' => 100, // Limit to prevent memory issues
            'orderby' => 'title',
            'order' => 'ASC',
            'author' => get_current_user_id(),
        ]);
        
        foreach ($venues as $venue) {
            yield $venue->ID => $venue->post_title;
        }
    }
    
    /**
     * Get all organizers for dropdown (using generator)
     * 
     * @return Generator<int, string>
     */
    public function getOrganizersForDropdown(): Generator {
        $organizers = get_posts([
            'post_type' => 'tribe_organizer',
            'posts_per_page' => 100, // Limit to prevent memory issues
            'orderby' => 'title',
            'order' => 'ASC',
            'author' => get_current_user_id(),
        ]);
        
        foreach ($organizers as $organizer) {
            yield $organizer->ID => $organizer->post_title;
        }
    }
    
    /**
     * Get event categories for checkboxes
     * 
     * @return Generator<int, string>
     */
    public function getCategoriesForCheckboxes(): Generator {
        $categories = get_terms([
            'taxonomy' => 'tribe_events_cat',
            'hide_empty' => false,
        ]);
        
        if (!is_wp_error($categories)) {
            foreach ($categories as $category) {
                yield $category->term_id => $category->name;
            }
        }
    }
}

/**
 * Singleton trait for memory efficiency
 */
trait HVAC_Singleton_Trait {
    private static ?self $instance = null;
    
    public static function instance(): self {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    private function __clone() {}
    public function __wakeup() {
        throw new Exception("Cannot unserialize singleton");
    }
}