<?php
/**
 * Order Manager Class
 *
 * @package ShopExplorer\Modules
 * @since 1.0.0
 */

namespace SHOPEXPLORER\Modules;

use SHOPEXPLORER\Database\DatabaseManager;
use SHOPEXPLORER\Models\OrderDataModel;
use SHOPEXPLORER\Exceptions\ShopExplorerException;
use SHOPEXPLORER\Auth\AuthenticationManager;
use SHOPEXPLORER\Sync\DataSyncEngine;

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

/**
 * Order Manager class
 *
 * Handles order management operations with CRUD functionality
 *
 * @since 1.0.0
 */
class SHOPEX_OrderManager {

	/**
	 * Database manager instance
	 *
	 * @var DatabaseManager
	 */
	private $database_handler;

	/**
	 * Authentication manager instance
	 *
	 * @var AuthenticationManager
	 */
	private $auth_manager;

	/**
	 * Sync engine instance
	 *
	 * @var DataSyncEngine
	 */
	private $sync_engine;

	/**
	 * Cache for order data
	 *
	 * @var array
	 */
	private $cache = [];

	/**
	 * Valid order statuses
	 *
	 * @var array
	 */
	private $valid_statuses = [
		'pending',
		'processing',
		'on-hold',
		'completed',
		'cancelled',
		'refunded',
		'failed',
	];

	/**
	 * Constructor
	 */
	public function __construct() {
		$this->database_handler = new DatabaseManager();
		$this->auth_manager = new AuthenticationManager();
		$this->sync_engine = new DataSyncEngine();
	}

	/**
	 * Get orders with filtering and pagination
	 *
	 * @param array $filters Filter parameters
	 * @return array
	 * @throws ShopExplorerException
	 */
	public function get_orders( $filters = [] ) {
		try {
			// Sanitize and validate filters
			$filters = $this->sanitize_filters( $filters );

			// Check permissions
			if ( ! $this->auth_manager->check_permissions( AuthenticationManager::CAPABILITY_MANAGE_ORDERS ) ) {
				return false;
			}

			// Apply vendor filtering if user is a vendor
			if ( $this->auth_manager->is_vendor_user() ) {
				$filters = $this->apply_vendor_filters( $filters );
			}

			// Get orders from database
			$orders_data = $this->database_handler->get_orders( $filters );

			// Convert to OrderDataModel objects
			$orders = [];
			foreach ( $orders_data as $order_data ) {
				$orders[] = OrderDataModel::from_db_row( $order_data );
			}

			// Get total count for pagination
			$total_count = $this->get_orders_count( $filters );

			return [
				'orders' => $orders,
				'total' => $total_count,
				'pages' => ceil( $total_count / $filters['limit'] ),
				'current_page' => ceil( $filters['offset'] / $filters['limit'] ) + 1,
			];

		} catch ( \Exception $e ) {
						return false;
		}
	}

	/**
	 * Get single order by ID
	 *
	 * @param int $order_id Order ID
	 * @return OrderDataModel|null
	 * @throws ShopExplorerException
	 */
	public function get_order( $order_id ) {
		try {
			$order_id = (int) $order_id;

			if ( empty( $order_id ) ) {
				return false;
			}

			// Check permissions
			if ( ! $this->auth_manager->check_permissions( AuthenticationManager::CAPABILITY_MANAGE_ORDERS ) ) {
				return false;
			}

			// Check cache first
			$cache_key = 'order_' . $order_id;
			if ( isset( $this->cache[ $cache_key ] ) ) {
				return $this->cache[ $cache_key ];
			}

			// Try WooCommerce function first
			if ( function_exists( 'wc_get_order' ) ) {
				$wc_order = wc_get_order( $order_id );
				if ( $wc_order ) {
					$order = OrderDataModel::from_wc_order( $wc_order );

					// Check vendor access
					if ( $this->auth_manager->is_vendor_user() && ! $this->can_access_order( $order ) ) {
						return false;
					}

					$this->cache[ $cache_key ] = $order;
					return $order;
				}
			}

			// Fallback to database query
			$orders_data = $this->database_handler->get_orders( [
				'limit' => 1,
				'meta_query' => [
					[
						'key' => 'id',
						'value' => $order_id,
						'compare' => '=',
					],
				],
			] );

			if ( empty( $orders_data ) ) {
				return null;
			}

			$order = OrderDataModel::from_db_row( $orders_data[0] );

			// Check vendor access
			if ( $this->auth_manager->is_vendor_user() && ! $this->can_access_order( $order ) ) {
				return false;
			}

			$this->cache[ $cache_key ] = $order;

			return $order;

		} catch ( \Exception $e ) {
						return false;
		}
	}

	/**
	 * Update order
	 *
	 * @param int   $order_id Order ID
	 * @param array $data Order data to update
	 * @return bool
	 * @throws ShopExplorerException
	 */
	public function update_order( $order_id, $data ) {
		try {
			$order_id = (int) $order_id;

			if ( empty( $order_id ) ) {
				return false;
			}

			// Check permissions
			if ( ! $this->auth_manager->check_permissions( AuthenticationManager::CAPABILITY_MANAGE_ORDERS ) ) {
				return false;
			}

			// Get existing order
			$existing_order = $this->get_order( $order_id );
			if ( ! $existing_order ) {
				return false;
			}

			// Check vendor access
			if ( $this->auth_manager->is_vendor_user() && ! $this->can_access_order( $existing_order ) ) {
				return false;
			}

			// Sanitize and validate data
			$sanitized_data = $this->sanitize_order_data( $data );
			$validation_errors = $this->validate_order_data( $sanitized_data );

			if ( ! empty( $validation_errors ) ) {
				return false;
			}

			// Update via WooCommerce if available
			if ( function_exists( 'wc_get_order' ) ) {
				$wc_order = wc_get_order( $order_id );
				if ( $wc_order ) {
					$success = $this->update_wc_order( $wc_order, $sanitized_data );

					if ( $success ) {
						// Clear cache
						unset( $this->cache[ 'order_' . $order_id ] );

						// Queue sync operation
						$this->sync_engine->queue_sync( 'order', $order_id, 'update' );

						return true;
					}
				}
			}

			// Fallback to direct database update
			$success = $this->database_handler->update_order( $order_id, $sanitized_data );

			if ( $success ) {
				// Clear cache
				unset( $this->cache[ 'order_' . $order_id ] );

				// Queue sync operation
				$this->sync_engine->queue_sync( 'order', $order_id, 'update' );
			}

			return $success;

		} catch ( \Exception $e ) {
						return false;
		}
	}

	/**
	 * Bulk update orders
	 *
	 * @param array $order_ids Array of order IDs
	 * @param array $data Data to update
	 * @return array Update results
	 * @throws ShopExplorerException
	 */
	public function bulk_update_orders( $order_ids, $data ) {
		try {
			// Check permissions
			if ( ! $this->auth_manager->check_permissions( AuthenticationManager::CAPABILITY_MANAGE_ORDERS ) ) {
				return false;
			}

			$results = [
				'total' => count( $order_ids ),
				'successful' => 0,
				'failed' => 0,
				'errors' => [],
			];

			foreach ( $order_ids as $order_id ) {
				try {
					$success = $this->update_order( $order_id, $data );

					if ( $success ) {
						$results['successful']++;
					} else {
						$results['failed']++;
						$results['errors'][] = "Failed to update order ID: {$order_id}";
					}
				} catch ( \Exception $e ) {
								return false;
				}
			}

			return $results;

		} catch ( \Exception $e ) {
						return false;
		}
	}

	/**
	 * Update order status
	 *
	 * @param int    $order_id Order ID
	 * @param string $new_status New status
	 * @param string $note Optional note
	 * @return bool
	 * @throws ShopExplorerException
	 */
	public function update_order_status( $order_id, $new_status, $note = '' ) {
		try {
			// Validate status
			if ( ! in_array( $new_status, $this->valid_statuses, true ) ) {
				return false;
			}

			// Get existing order
			$order = $this->get_order( $order_id );
			if ( ! $order ) {
				return false;
			}

			// Check if status change is allowed
			if ( ! $this->is_status_change_allowed( $order->status, $new_status ) ) {
				return false;
			}

			// Update via WooCommerce if available
			if ( function_exists( 'wc_get_order' ) ) {
				$wc_order = wc_get_order( $order_id );
				if ( $wc_order ) {
					$wc_order->update_status( $new_status, $note );

					// Clear cache
					unset( $this->cache[ 'order_' . $order_id ] );

					// Queue sync operation
					$this->sync_engine->queue_sync( 'order', $order_id, 'update' );

					return true;
				}
			}

			// Fallback to direct update
			return $this->update_order( $order_id, [
				'status' => $new_status,
				'notes' => $order->notes . "\n" . $note,
			] );

		} catch ( \Exception $e ) {
						return false;
		}
	}

	/**
	 * Search orders
	 *
	 * @param string $search_term Search term
	 * @param array  $filters Additional filters
	 * @return array
	 * @throws ShopExplorerException
	 */
	public function search_orders( $search_term, $filters = [] ) {
		try {
			// Check permissions
			if ( ! $this->auth_manager->check_permissions( AuthenticationManager::CAPABILITY_MANAGE_ORDERS ) ) {
				return false;
			}

			$search_term = sanitize_text_field( $search_term );

			if ( empty( $search_term ) ) {
				return $this->get_orders( $filters );
			}

			// Add search parameters to filters
			$filters['search'] = $search_term;
			$filters['search_fields'] = [
				'order_number',
				'customer_name',
				'customer_email',
				'billing_address',
				'shipping_address',
			];

			return $this->get_orders( $filters );

		} catch ( \Exception $e ) {
						return false;
		}
	}

	/**
	 * Get order statistics
	 *
	 * @param array $filters Filters for statistics
	 * @return array
	 * @throws ShopExplorerException
	 */
	public function get_order_statistics( $filters = [] ) {
		try {
			// Check permissions
			if ( ! $this->auth_manager->check_permissions( AuthenticationManager::CAPABILITY_VIEW_REPORTS ) ) {
				return false;
			}

			// Apply vendor filtering if user is a vendor
			if ( $this->auth_manager->is_vendor_user() ) {
				$filters = $this->apply_vendor_filters( $filters );
			}

			return $this->database_handler->get_order_statistics( $filters );

		} catch ( \Exception $e ) {
						return false;
		}
	}

	/**
	 * Export orders
	 *
	 * @param array  $filters Export filters
	 * @param string $format Export format (csv, json)
	 * @return string Export data
	 * @throws ShopExplorerException
	 */
	public function export_orders( $filters = [], $format = 'csv' ) {
		try {
			// Check permissions
			if ( ! $this->auth_manager->check_permissions( AuthenticationManager::CAPABILITY_EXPORT_DATA ) ) {
				return false;
			}

			// Remove pagination for export
			$filters['limit'] = -1;
			$filters['offset'] = 0;

			$orders_result = $this->get_orders( $filters );
			$orders = $orders_result['orders'];

			switch ( $format ) {
				case 'csv':
					return $this->export_orders_csv( $orders );

				case 'json':
					return $this->export_orders_json( $orders );

				default:
					return false;
			}
		} catch ( \Exception $e ) {
						return false;
		}
	}

	/**
	 * Sanitize order filters
	 *
	 * @param array $filters Raw filters
	 * @return array Sanitized filters
	 */
	private function sanitize_filters( $filters ) {
		$sanitized = [
			'limit' => isset( $filters['limit'] ) ? max( 1, min( 100, (int) $filters['limit'] ) ) : 20,
			'offset' => isset( $filters['offset'] ) ? max( 0, (int) $filters['offset'] ) : 0,
			'orderby' => isset( $filters['orderby'] ) ? sanitize_key( $filters['orderby'] ) : 'date_created',
			'order' => isset( $filters['order'] ) && in_array( strtoupper( $filters['order'] ), [ 'ASC', 'DESC' ] ) ? strtoupper( $filters['order'] ) : 'DESC',
		];

		// Status filter
		if ( ! empty( $filters['status'] ) ) {
			if ( is_array( $filters['status'] ) ) {
				$sanitized['status'] = array_intersect( $filters['status'], $this->valid_statuses );
			} else {
				$status = sanitize_text_field( $filters['status'] );
				if ( in_array( $status, $this->valid_statuses, true ) ) {
					$sanitized['status'] = [ $status ];
				}
			}
		}

		// Date filters
		if ( ! empty( $filters['date_from'] ) ) {
			$sanitized['date_from'] = sanitize_text_field( $filters['date_from'] );
		}

		if ( ! empty( $filters['date_to'] ) ) {
			$sanitized['date_to'] = sanitize_text_field( $filters['date_to'] );
		}

		// Customer filter
		if ( ! empty( $filters['customer_id'] ) ) {
			$sanitized['customer_id'] = (int) $filters['customer_id'];
		}

		// Search filter
		if ( ! empty( $filters['search'] ) ) {
			$sanitized['search'] = sanitize_text_field( $filters['search'] );
		}

		return $sanitized;
	}

	/**
	 * Apply vendor-specific filters
	 *
	 * @param array $filters Existing filters
	 * @return array Modified filters
	 */
	private function apply_vendor_filters( $filters ) {
		$vendor_id = $this->auth_manager->get_current_vendor_id();

		if ( $vendor_id ) {
			$filters['vendor_id'] = $vendor_id;
		}

		return $filters;
	}

	/**
	 * Check if user can access order
	 *
	 * @param OrderDataModel $order Order data model
	 * @return bool
	 */
	private function can_access_order( $order ) {
		if ( ! $this->auth_manager->is_vendor_user() ) {
			return true; // Admin users can access all orders
		}

		$vendor_id = $this->auth_manager->get_current_vendor_id();
		return $order->vendor_id === $vendor_id;
	}

	/**
	 * Get orders count
	 *
	 * @param array $filters Filters
	 * @return int
	 */
	private function get_orders_count( $filters ) {
		$count_filters = $filters;
		unset( $count_filters['limit'], $count_filters['offset'] );

		return $this->database_handler->get_orders_count( $count_filters );
	}

	/**
	 * Sanitize order data
	 *
	 * @param array $data Raw order data
	 * @return array Sanitized data
	 */
	private function sanitize_order_data( $data ) {
		$sanitized = [];

		$allowed_fields = [
			'status' => 'sanitize_text_field',
			'customer_name' => 'sanitize_text_field',
			'customer_email' => 'sanitize_email',
			'total' => 'floatval',
			'currency' => 'sanitize_text_field',
			'payment_method' => 'sanitize_text_field',
			'notes' => 'sanitize_textarea_field',
		];

		foreach ( $allowed_fields as $field => $sanitizer ) {
			if ( isset( $data[ $field ] ) ) {
				$sanitized[ $field ] = call_user_func( $sanitizer, $data[ $field ] );
			}
		}

		return $sanitized;
	}

	/**
	 * Validate order data
	 *
	 * @param array $data Order data
	 * @return array Validation errors
	 */
	private function validate_order_data( $data ) {
		$errors = [];

		if ( isset( $data['status'] ) && ! in_array( $data['status'], $this->valid_statuses, true ) ) {
			$errors[] = 'Invalid order status';
		}

		if ( isset( $data['customer_email'] ) && ! is_email( $data['customer_email'] ) ) {
			$errors[] = 'Invalid customer email';
		}

		if ( isset( $data['total'] ) && $data['total'] < 0 ) {
			$errors[] = 'Order total cannot be negative';
		}

		return $errors;
	}

	/**
	 * Check if status change is allowed
	 *
	 * @param string $from_status Current status
	 * @param string $to_status New status
	 * @return bool
	 */
	private function is_status_change_allowed( $from_status, $to_status ) {
		// Define status transition rules
		$allowed_transitions = [
			'pending' => [ 'processing', 'on-hold', 'cancelled' ],
			'processing' => [ 'completed', 'cancelled', 'on-hold' ],
			'on-hold' => [ 'processing', 'cancelled' ],
			'completed' => [ 'refunded' ],
			'cancelled' => [ 'pending' ],
			'refunded' => [],
			'failed' => [ 'pending', 'cancelled' ],
		];

		return in_array( $to_status, $allowed_transitions[ $from_status ] ?? [], true );
	}

	/**
	 * Update WooCommerce order
	 *
	 * @param \WC_Order $wc_order WooCommerce order
	 * @param array     $data Update data
	 * @return bool
	 */
	private function update_wc_order( $wc_order, $data ) {
		try {
			foreach ( $data as $field => $value ) {
				switch ( $field ) {
					case 'status':
						$wc_order->set_status( $value );
						break;
					case 'customer_name':
						$wc_order->set_billing_first_name( $value );
						break;
					case 'customer_email':
						$wc_order->set_billing_email( $value );
						break;
					case 'total':
						$wc_order->set_total( $value );
						break;
					case 'currency':
						$wc_order->set_currency( $value );
						break;
					case 'notes':
						$wc_order->set_customer_note( $value );
						break;
				}
			}

			$wc_order->save();
			return true;

		} catch ( \Exception $e ) {
			return false;
		}
	}

	/**
	 * Export orders as CSV
	 *
	 * @param array $orders Orders array
	 * @return string CSV data
	 */
	private function export_orders_csv( $orders ) {
		$csv_data = [];

		// Headers
		$headers = [
			'Order ID',
			'Order Number',
			'Status',
			'Customer Name',
			'Customer Email',
			'Total',
			'Currency',
			'Payment Method',
			'Date Created',
			'Date Modified',
		];

		$csv_data[] = $headers;

		// Data rows
		foreach ( $orders as $order ) {
			$csv_data[] = [
				$order->order_id,
				$order->order_number,
				$order->status,
				$order->customer_name,
				$order->customer_email,
				$order->total,
				$order->currency,
				$order->payment_method,
				$order->date_created,
				$order->date_modified,
			];
		}

		// Convert to CSV string
		$output = fopen( 'php://temp', 'r+' );
		foreach ( $csv_data as $row ) {
			fputcsv( $output, $row );
		}
		rewind( $output );
		$csv_string = stream_get_contents( $output );
		fclose( $output );

		return $csv_string;
	}

	/**
	 * Export orders as JSON
	 *
	 * @param array $orders Orders array
	 * @return string JSON data
	 */
	private function export_orders_json( $orders ) {
		$export_data = [];

		foreach ( $orders as $order ) {
			$export_data[] = $order->to_array();
		}

		return wp_json_encode( $export_data, JSON_PRETTY_PRINT );
	}

	/**
	 * Get valid order statuses
	 *
	 * @return array
	 */
	public function get_valid_statuses() {
		return $this->valid_statuses;
	}

	/**
	 * Clear order cache
	 *
	 * @param int|null $order_id Specific order ID or null for all
	 */
	public function clear_cache( $order_id = null ) {
		if ( $order_id ) {
			unset( $this->cache[ 'order_' . $order_id ] );
		} else {
			$this->cache = [];
		}
	}
}
