<?php
/**
 * Ticket Tailor Event Manager
 *
 * Handles event caching, syncing, and retrieval
 */

// Exit if accessed directly
if (!defined('ABSPATH')) {
    exit;
}

class Ticket_Tailor_Event_Manager {
    
    /**
     * API Client
     */
    private $api;
    
    /**
     * Table name
     */
    private $table;
    
    /**
     * Cache duration (in seconds)
     */
    private $cache_duration;
    
    /**
     * Constructor
     */
    public function __construct($api) {
        global $wpdb;
        
        $this->api = $api;
        $this->table = $wpdb->prefix . 'ticket_tailor_events';
        $this->cache_duration = get_option('ticket_tailor_cache_duration', 3600); // 1 hour default
    }
    
    /**
     * Get all events (from cache or API) - PERFORMANCE FIX: Added limit parameter
     */
    public function get_events($force_refresh = false, $limit = null) {
        if ($force_refresh) {
            return $this->sync_all_events();
        }

        global $wpdb;

        // Check if cache is still valid
        $cache_valid_time = gmdate('Y-m-d H:i:s', time() - $this->cache_duration);

        // Build query with optional limit
        $query = $wpdb->prepare(
            "SELECT event_data FROM {$this->table} WHERE last_synced > %s ORDER BY last_synced DESC",
            $cache_valid_time
        );

        // PERFORMANCE FIX: Add LIMIT if specified
        if ($limit !== null && is_numeric($limit)) {
            $query .= $wpdb->prepare(" LIMIT %d", absint($limit));
        }

        $cached_events = $wpdb->get_results($query);

        if (!empty($cached_events)) {
            $events = array();
            foreach ($cached_events as $row) {
                $event_data = json_decode($row->event_data, true);
                if ($event_data) {
                    $events[] = $event_data;
                }
            }
            return $events;
        }

        // Cache is expired or empty, fetch from API
        $all_events = $this->sync_all_events();

        // Apply limit to synced events if specified
        if ($limit !== null && is_array($all_events)) {
            return array_slice($all_events, 0, absint($limit));
        }

        return $all_events;
    }
    
    /**
     * Get single event
     */
    public function get_event($event_id, $force_refresh = false) {
        $event_id = sanitize_text_field($event_id);
        
        if (!$force_refresh) {
            global $wpdb;
            
            $cache_valid_time = gmdate('Y-m-d H:i:s', time() - $this->cache_duration);
            
            $cached = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT event_data FROM {$this->table} WHERE event_id = %s AND last_synced > %s",
                    $event_id,
                    $cache_valid_time
                )
            );
            
            if ($cached) {
                $event_data = json_decode($cached, true);
                if ($event_data) {
                    return $event_data;
                }
            }
        }
        
        // Fetch from API
        $event = $this->api->get_event($event_id);
        
        if (is_wp_error($event)) {
            return $event;
        }
        
        // Cache it
        $this->cache_event($event);
        
        return $event;
    }
    
    /**
     * Sync all events from API - ENTERPRISE: Race condition protection
     */
    public function sync_all_events() {
        if (!$this->api->is_configured()) {
            return new WP_Error('no_api_key', __('API key not configured', 'ticket-tailor'));
        }

        // ENTERPRISE: Acquire lock to prevent concurrent syncs
        $lock_key = 'ticket_tailor_sync_events_lock';
        $lock_acquired = $this->acquire_sync_lock($lock_key);

        if (!$lock_acquired) {
            return new WP_Error(
                'sync_in_progress',
                __('Event sync already in progress. Please wait.', 'ticket-tailor'),
                array('lock_key' => $lock_key)
            );
        }

        try {
            $events = $this->api->get_all_paginated('events');

            if (is_wp_error($events)) {
                $this->release_sync_lock($lock_key);
                return $events;
            }

            // ENTERPRISE: Use transaction for atomic cache updates
            global $wpdb;
            $wpdb->query('START TRANSACTION');

            try {
                // Cache all events
                $cached_count = 0;
                foreach ($events as $event) {
                    if ($this->cache_event($event)) {
                        $cached_count++;
                    }
                }

                // Update last sync time
                update_option('ticket_tailor_last_event_sync', time());

                $wpdb->query('COMMIT');

                error_log(sprintf(
                    'Ticket Tailor: Successfully synced %d events (%d cached)',
                    count($events),
                    $cached_count
                ));

            } catch (Exception $e) {
                $wpdb->query('ROLLBACK');
                $this->release_sync_lock($lock_key);

                return new WP_Error(
                    'sync_transaction_failed',
                    sprintf('Event sync transaction failed: %s', $e->getMessage())
                );
            }

            $this->release_sync_lock($lock_key);
            return $events;

        } catch (Exception $e) {
            $this->release_sync_lock($lock_key);

            return new WP_Error(
                'sync_failed',
                sprintf('Event sync failed: %s', $e->getMessage())
            );
        }
    }

    /**
     * Acquire sync lock - ENTERPRISE: Prevent concurrent syncs
     */
    private function acquire_sync_lock($lock_key, $timeout = 300) {
        // Try to set transient with 5-minute expiry
        // If it already exists, returns false
        $acquired = set_transient($lock_key, time(), $timeout);

        if (!$acquired) {
            // Check if lock is stale (older than timeout)
            $lock_time = get_transient($lock_key);
            if ($lock_time && (time() - $lock_time) > $timeout) {
                // Stale lock, force release and reacquire
                delete_transient($lock_key);
                return set_transient($lock_key, time(), $timeout);
            }
            return false;
        }

        return true;
    }

    /**
     * Release sync lock - ENTERPRISE
     */
    private function release_sync_lock($lock_key) {
        return delete_transient($lock_key);
    }
    
    /**
     * Cache a single event
     */
    private function cache_event($event) {
        if (empty($event['id'])) {
            return false;
        }
        
        global $wpdb;
        
        $event_id = sanitize_text_field($event['id']);
        $event_data = wp_json_encode($event);
        
        // Check if exists
        $exists = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT id FROM {$this->table} WHERE event_id = %s",
                $event_id
            )
        );
        
        if ($exists) {
            // Update existing
            return $wpdb->update(
                $this->table,
                array(
                    'event_data' => $event_data,
                    'last_synced' => current_time('mysql', 1),
                ),
                array('event_id' => $event_id),
                array('%s', '%s'),
                array('%s')
            );
        } else {
            // Insert new
            return $wpdb->insert(
                $this->table,
                array(
                    'event_id' => $event_id,
                    'event_data' => $event_data,
                    'last_synced' => current_time('mysql', 1),
                ),
                array('%s', '%s', '%s')
            );
        }
    }
    
    /**
     * Get upcoming events
     */
    public function get_upcoming_events($limit = 10) {
        $events = $this->get_events();
        
        if (is_wp_error($events)) {
            return $events;
        }
        
        // Filter and sort by start date
        $upcoming = array_filter($events, function($event) {
            if (!isset($event['start']['iso'])) {
                return false;
            }
            
            $start_time = strtotime($event['start']['iso']);
            return $start_time >= time();
        });
        
        // Sort by start date
        usort($upcoming, function($a, $b) {
            $time_a = strtotime($a['start']['iso'] ?? 0);
            $time_b = strtotime($b['start']['iso'] ?? 0);
            return $time_a - $time_b;
        });
        
        return array_slice($upcoming, 0, $limit);
    }
    
    /**
     * Get past events
     */
    public function get_past_events($limit = 10) {
        $events = $this->get_events();
        
        if (is_wp_error($events)) {
            return $events;
        }
        
        // Filter and sort by start date
        $past = array_filter($events, function($event) {
            if (!isset($event['start']['iso'])) {
                return false;
            }
            
            $start_time = strtotime($event['start']['iso']);
            return $start_time < time();
        });
        
        // Sort by start date (newest first)
        usort($past, function($a, $b) {
            $time_a = strtotime($a['start']['iso'] ?? 0);
            $time_b = strtotime($b['start']['iso'] ?? 0);
            return $time_b - $time_a;
        });
        
        return array_slice($past, 0, $limit);
    }
    
    /**
     * Search events
     */
    public function search_events($search_term) {
        $events = $this->get_events();
        
        if (is_wp_error($events)) {
            return $events;
        }
        
        $search_term = strtolower($search_term);
        
        return array_filter($events, function($event) use ($search_term) {
            $name = strtolower($event['name'] ?? '');
            $description = strtolower($event['description'] ?? '');
            
            return strpos($name, $search_term) !== false || 
                   strpos($description, $search_term) !== false;
        });
    }
    
    /**
     * Get events by category
     */
    public function get_events_by_category($category) {
        $events = $this->get_events();
        
        if (is_wp_error($events)) {
            return $events;
        }
        
        $category = strtolower($category);
        
        return array_filter($events, function($event) use ($category) {
            $event_category = strtolower($event['category'] ?? '');
            return $event_category === $category;
        });
    }
    
    /**
     * Get event ticket types
     */
    public function get_event_tickets($event_id) {
        $event_id = sanitize_text_field($event_id);
        
        // Try to get from transient first
        $cache_key = 'tt_tickets_' . $event_id;
        $cached = get_transient($cache_key);
        
        if ($cached !== false) {
            return $cached;
        }
        
        // Fetch from API
        $tickets = $this->api->get_ticket_types($event_id);
        
        if (is_wp_error($tickets)) {
            return $tickets;
        }
        
        // Cache for 15 minutes (tickets change less frequently)
        set_transient($cache_key, $tickets, 900);
        
        return $tickets;
    }
    
    /**
     * Clear event cache - SECURITY FIX: Use prepared statements
     */
    public function clear_cache($event_id = null) {
        global $wpdb;

        if ($event_id) {
            $event_id = sanitize_text_field($event_id);
            $wpdb->delete($this->table, array('event_id' => $event_id), array('%s'));

            // Also clear ticket cache
            delete_transient('tt_tickets_' . $event_id);
        } else {
            // SECURITY FIX: Validate table name before TRUNCATE
            if (preg_match('/^[a-zA-Z0-9_]+$/', $this->table)) {
                $wpdb->query("TRUNCATE TABLE `{$this->table}`");
            }

            // Clear all ticket transients - SECURITY FIX: Use prepared statement
            $wpdb->query($wpdb->prepare(
                "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
                $wpdb->esc_like('_transient_tt_tickets_') . '%'
            ));
        }

        return true;
    }
    
    /**
     * Get cache statistics
     */
    public function get_cache_stats() {
        global $wpdb;

        $total_events = $wpdb->get_var("SELECT COUNT(*) FROM {$this->table}");

        $cache_valid_time = gmdate('Y-m-d H:i:s', time() - $this->cache_duration);
        $valid_events = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$this->table} WHERE last_synced > %s",
                $cache_valid_time
            )
        );

        $last_sync = get_option('ticket_tailor_last_event_sync', 0);

        return array(
            'total_cached' => (int) $total_events,
            'valid_cached' => (int) $valid_events,
            'expired_cached' => (int) $total_events - (int) $valid_events,
            'last_sync' => $last_sync,
            'cache_duration' => $this->cache_duration,
        );
    }

    /**
     * Get event statistics efficiently - PERFORMANCE OPTIMIZATION
     * Uses aggregated database queries instead of loading all events
     */
    public function get_event_statistics() {
        global $wpdb;

        $cache_key = 'tt_event_stats';
        $cached = wp_cache_get($cache_key);

        if ($cached !== false) {
            return $cached;
        }

        $cache_valid_time = gmdate('Y-m-d H:i:s', time() - $this->cache_duration);

        // Get total events count
        $total_events = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$this->table} WHERE last_synced > %s",
                $cache_valid_time
            )
        );

        // Get upcoming events count (parse JSON to check dates)
        $all_events = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT event_data FROM {$this->table} WHERE last_synced > %s",
                $cache_valid_time
            )
        );

        $upcoming_count = 0;
        $now = time();

        foreach ($all_events as $row) {
            $event = json_decode($row->event_data, true);
            if (!empty($event['start']['iso'])) {
                $start_time = strtotime($event['start']['iso']);
                if ($start_time >= $now) {
                    $upcoming_count++;
                }
            }
        }

        $stats = array(
            'total_events' => (int) $total_events,
            'upcoming_events' => $upcoming_count,
        );

        // Cache for 5 minutes
        wp_cache_set($cache_key, $stats, '', 300);

        return $stats;
    }
}
