<?php
/**
 * Ticket Tailor Order Manager
 *
 * Handles order caching, syncing, and retrieval
 */

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

class Ticket_Tailor_Order_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_orders';
        $this->cache_duration = get_option('ticket_tailor_cache_duration', 3600); // 1 hour default
    }
    
    /**
     * Get all orders - PERFORMANCE FIX: Improved query building
     */
    public function get_orders($args = array(), $force_refresh = false) {
        if ($force_refresh) {
            return $this->sync_all_orders();
        }

        global $wpdb;

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

        $query = "SELECT order_data FROM {$this->table} WHERE last_synced > %s";
        $query_args = array($cache_valid_time);

        // Filter by event if specified
        if (!empty($args['event_id'])) {
            $query .= " AND event_id = %s";
            $query_args[] = sanitize_text_field($args['event_id']);
        }

        $query .= " ORDER BY last_synced DESC";

        // PERFORMANCE FIX: Always apply a reasonable default limit if not specified
        if (!empty($args['limit'])) {
            $query .= " LIMIT %d";
            $query_args[] = absint($args['limit']);
        } else {
            // Default limit of 1000 to prevent loading unlimited orders
            $query .= " LIMIT 1000";
        }

        $cached_orders = $wpdb->get_results(
            $wpdb->prepare($query, $query_args)
        );

        if (!empty($cached_orders)) {
            $orders = array();
            foreach ($cached_orders as $row) {
                $order_data = json_decode($row->order_data, true);
                if ($order_data) {
                    $orders[] = $order_data;
                }
            }
            return $orders;
        }

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

        // Apply limit to synced orders if specified
        if (!empty($args['limit']) && is_array($all_orders)) {
            return array_slice($all_orders, 0, absint($args['limit']));
        }

        // Apply default limit
        if (is_array($all_orders)) {
            return array_slice($all_orders, 0, 1000);
        }

        return $all_orders;
    }
    
    /**
     * Get single order
     */
    public function get_order($order_id, $force_refresh = false) {
        $order_id = sanitize_text_field($order_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 order_data FROM {$this->table} WHERE order_id = %s AND last_synced > %s",
                    $order_id,
                    $cache_valid_time
                )
            );
            
            if ($cached) {
                $order_data = json_decode($cached, true);
                if ($order_data) {
                    return $order_data;
                }
            }
        }
        
        // Fetch from API
        $order = $this->api->get_order($order_id);
        
        if (is_wp_error($order)) {
            return $order;
        }
        
        // Cache it
        $this->cache_order($order);
        
        return $order;
    }
    
    /**
     * Sync all orders from API - ENTERPRISE: Race condition protection
     */
    public function sync_all_orders() {
        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_orders_lock';
        $lock_acquired = $this->acquire_sync_lock($lock_key);

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

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

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

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

            try {
                // Cache all orders
                $cached_count = 0;
                foreach ($orders as $order) {
                    if ($this->cache_order($order)) {
                        $cached_count++;
                    }
                }

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

                $wpdb->query('COMMIT');

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

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

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

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

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

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

    /**
     * Acquire sync lock - ENTERPRISE: Prevent concurrent syncs
     */
    private function acquire_sync_lock($lock_key, $timeout = 300) {
        $acquired = set_transient($lock_key, time(), $timeout);

        if (!$acquired) {
            $lock_time = get_transient($lock_key);
            if ($lock_time && (time() - $lock_time) > $timeout) {
                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 order
     */
    private function cache_order($order) {
        if (empty($order['id'])) {
            return false;
        }
        
        global $wpdb;
        
        $order_id = sanitize_text_field($order['id']);
        $event_id = !empty($order['event_id']) ? sanitize_text_field($order['event_id']) : '';
        $order_data = wp_json_encode($order);
        
        // Check if exists
        $exists = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT id FROM {$this->table} WHERE order_id = %s",
                $order_id
            )
        );
        
        if ($exists) {
            // Update existing
            return $wpdb->update(
                $this->table,
                array(
                    'event_id' => $event_id,
                    'order_data' => $order_data,
                    'last_synced' => current_time('mysql', 1),
                ),
                array('order_id' => $order_id),
                array('%s', '%s', '%s'),
                array('%s')
            );
        } else {
            // Insert new
            return $wpdb->insert(
                $this->table,
                array(
                    'order_id' => $order_id,
                    'event_id' => $event_id,
                    'order_data' => $order_data,
                    'last_synced' => current_time('mysql', 1),
                ),
                array('%s', '%s', '%s', '%s')
            );
        }
    }
    
    /**
     * Get orders for a specific event
     */
    public function get_event_orders($event_id) {
        return $this->get_orders(array('event_id' => $event_id));
    }
    
    /**
     * Get order statistics
     */
    public function get_order_stats($event_id = null) {
        $orders = $event_id ? $this->get_event_orders($event_id) : $this->get_orders();
        
        if (is_wp_error($orders)) {
            return $orders;
        }
        
        $stats = array(
            'total_orders' => count($orders),
            'total_revenue' => 0,
            'total_tickets' => 0,
            'by_status' => array(),
        );
        
        foreach ($orders as $order) {
            // Count tickets
            if (isset($order['total_quantity'])) {
                $stats['total_tickets'] += (int) $order['total_quantity'];
            }
            
            // Sum revenue
            if (isset($order['total'])) {
                $stats['total_revenue'] += (int) $order['total'];
            }
            
            // Count by status
            $status = $order['status'] ?? 'unknown';
            if (!isset($stats['by_status'][$status])) {
                $stats['by_status'][$status] = 0;
            }
            $stats['by_status'][$status]++;
        }
        
        // Format revenue (convert from cents to dollars/pounds)
        $currency = get_option('ticket_tailor_currency', 'USD');
        $stats['total_revenue_formatted'] = $this->format_currency($stats['total_revenue'], $currency);
        
        return $stats;
    }
    
    /**
     * Format currency
     */
    private function format_currency($amount_cents, $currency = 'USD') {
        $amount = $amount_cents / 100;
        
        $symbols = array(
            'USD' => '$',
            'GBP' => '£',
            'EUR' => '€',
            'CAD' => 'C$',
            'AUD' => 'A$',
        );
        
        $symbol = $symbols[$currency] ?? $currency . ' ';
        
        return $symbol . number_format($amount, 2);
    }
    
    /**
     * Search orders
     */
    public function search_orders($search_term) {
        $orders = $this->get_orders();
        
        if (is_wp_error($orders)) {
            return $orders;
        }
        
        $search_term = strtolower($search_term);
        
        return array_filter($orders, function($order) use ($search_term) {
            $email = strtolower($order['email'] ?? '');
            $name = strtolower($order['customer_name'] ?? '');
            $order_id = strtolower($order['id'] ?? '');
            
            return strpos($email, $search_term) !== false || 
                   strpos($name, $search_term) !== false ||
                   strpos($order_id, $search_term) !== false;
        });
    }
    
    /**
     * Get recent orders
     */
    public function get_recent_orders($limit = 10) {
        return $this->get_orders(array('limit' => $limit));
    }
    
    /**
     * Clear order cache - SECURITY FIX: Validate table name
     */
    public function clear_cache($order_id = null) {
        global $wpdb;

        if ($order_id) {
            $order_id = sanitize_text_field($order_id);
            $wpdb->delete($this->table, array('order_id' => $order_id), array('%s'));
        } else {
            // SECURITY FIX: Validate table name before TRUNCATE
            if (preg_match('/^[a-zA-Z0-9_]+$/', $this->table)) {
                $wpdb->query("TRUNCATE TABLE `{$this->table}`");
            }
        }

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

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

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

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

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

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

        $cache_key = 'tt_order_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 orders count
        $total_orders = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$this->table} WHERE last_synced > %s",
                $cache_valid_time
            )
        );

        // Get all order data to calculate revenue (we need to parse JSON)
        $orders_data = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT order_data FROM {$this->table} WHERE last_synced > %s",
                $cache_valid_time
            )
        );

        $total_revenue = 0;

        foreach ($orders_data as $row) {
            $order = json_decode($row->order_data, true);
            if (!empty($order['total'])) {
                $total_revenue += floatval($order['total']);
            }
        }

        $stats = array(
            'total_orders' => (int) $total_orders,
            'total_revenue' => $total_revenue,
        );

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

        return $stats;
    }
}
