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

namespace SHOPEXPLORER\Modules;

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

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

/**
 * Product Manager class
 *
 * Handles product management operations with inventory and CRUD functionality
 *
 * @since 1.0.0
 */
class SHOPEX_ProductManager {

	/**
	 * 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 product data
	 *
	 * @var array
	 */
	private $cache = [];

	/**
	 * Stock level change tracking
	 *
	 * @var array
	 */
	private $stock_changes = [];

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

	/**
	 * Initialize WordPress hooks
	 */
	private function init_hooks() {
		// Hook into WooCommerce stock changes for real-time sync
		add_action( 'woocommerce_product_set_stock', [ $this, 'on_stock_change' ], 10, 1 );
		add_action( 'woocommerce_variation_set_stock', [ $this, 'on_stock_change' ], 10, 1 );

		// Hook into product save for sync
		add_action( 'woocommerce_update_product', [ $this, 'on_product_update' ], 10, 1 );
		add_action( 'woocommerce_new_product', [ $this, 'on_product_create' ], 10, 1 );
	}

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

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

			}

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

			// Get products from database
			$products_data = $this->database_handler->get_products( $filters );

			// Convert to ProductDataModel objects
			$products = [];
			foreach ( $products_data as $product_data ) {
				$products[] = ProductDataModel::from_db_row( $product_data );
			}

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

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

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

	/**
	 * Get single product by ID
	 *
	 * @param int $product_id Product ID
	 * @return ProductDataModel|null
	 * @throws ShopExplorerException
	 */
	public function get_product( $product_id ) {
		try {
			$product_id = (int) $product_id;

			if ( empty( $product_id ) ) {
								return false;

			}

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

			}

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

			// Try WooCommerce function first
			if ( function_exists( 'wc_get_product' ) ) {
				$wc_product = wc_get_product( $product_id );
				if ( $wc_product ) {
					$product = ProductDataModel::from_wc_product( $wc_product );

					// Check vendor access
					if ( $this->auth_manager->is_vendor_user() && ! $this->can_access_product( $product ) ) {
										return false;

					}

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

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

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

			$product = ProductDataModel::from_db_row( $products_data[0] );

			// Check vendor access
			if ( $this->auth_manager->is_vendor_user() && ! $this->can_access_product( $product ) ) {
								return false;

			}

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

			return $product;

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

	/**
	 * Update product
	 *
	 * @param int   $product_id Product ID
	 * @param array $data Product data to update
	 * @return bool
	 * @throws ShopExplorerException
	 */
	public function update_product( $product_id, $data ) {
		try {
			$product_id = (int) $product_id;

			if ( empty( $product_id ) ) {
								return false;

			}

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

			}

			// Get existing product
			$existing_product = $this->get_product( $product_id );
			if ( ! $existing_product ) {
								return false;

			}

			// Check vendor access
			if ( $this->auth_manager->is_vendor_user() && ! $this->can_access_product( $existing_product ) ) {
								return false;

			}

			// Sanitize and validate data
			$sanitized_data = $this->sanitize_product_data( $data );
			$validation_errors = $this->validate_product_data( $sanitized_data, $product_id );

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

			}

			// Track stock changes for real-time sync
			if ( isset( $sanitized_data['stock_quantity'] ) &&
				 $sanitized_data['stock_quantity'] !== $existing_product->stock_quantity ) {
				$this->track_stock_change( $product_id, $existing_product->stock_quantity, $sanitized_data['stock_quantity'] );
			}

			// Update via WooCommerce if available
			if ( function_exists( 'wc_get_product' ) ) {
				$wc_product = wc_get_product( $product_id );
				if ( $wc_product ) {
					$success = $this->update_wc_product( $wc_product, $sanitized_data );

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

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

						return true;
					}
				}
			}

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

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

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

			return $success;

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

	/**
	 * Update product stock level
	 *
	 * @param int  $product_id Product ID
	 * @param int  $stock_quantity New stock quantity
	 * @param bool $sync_immediately Whether to sync immediately
	 * @return bool
	 * @throws ShopExplorerException
	 */
	public function update_stock_level( $product_id, $stock_quantity, $sync_immediately = true ) {
		try {
			$product_id = (int) $product_id;
			$stock_quantity = (int) $stock_quantity;

			// Get existing product
			$product = $this->get_product( $product_id );
			if ( ! $product ) {
								return false;

			}

			// Check if stock management is enabled
			if ( ! $product->manage_stock ) {
								return false;

			}

			$old_stock = $product->stock_quantity;

			// Update stock via WooCommerce if available
			if ( function_exists( 'wc_get_product' ) ) {
				$wc_product = wc_get_product( $product_id );
				if ( $wc_product ) {
					$wc_product->set_stock_quantity( $stock_quantity );
					$wc_product->save();

					// Clear cache
					unset( $this->cache[ 'product_' . $product_id ] );

					// Track stock change
					$this->track_stock_change( $product_id, $old_stock, $stock_quantity );

					// Sync immediately if requested
					if ( $sync_immediately ) {
						$this->sync_engine->queue_sync( 'product', $product_id, 'update', 'to_sheets', [
							'priority' => 10, // High priority for stock updates
						] );
					}

					return true;
				}
			}

			// Fallback to direct update
			$update_data = [
				'stock_quantity' => $stock_quantity,
				'stock_status' => $stock_quantity > 0 ? 'instock' : 'outofstock',
			];

			return $this->update_product( $product_id, $update_data );

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

	/**
	 * Bulk update products
	 *
	 * @param array $product_ids Array of product IDs
	 * @param array $data Data to update
	 * @return array Update results
	 * @throws ShopExplorerException
	 */
	public function bulk_update_products( $product_ids, $data ) {
		try {
			// Check permissions
			if ( ! $this->auth_manager->check_permissions( AuthenticationManager::CAPABILITY_MANAGE_PRODUCTS ) ) {
								return false;

			}

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

			foreach ( $product_ids as $product_id ) {
				try {
					$success = $this->update_product( $product_id, $data );

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

			return $results;

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

	/**
	 * Bulk update stock levels
	 *
	 * @param array $stock_updates Array of product_id => stock_quantity
	 * @param bool  $sync_immediately Whether to sync immediately
	 * @return array Update results
	 * @throws ShopExplorerException
	 */
	public function bulk_update_stock_levels( $stock_updates, $sync_immediately = true ) {
		try {
			// Check permissions
			if ( ! $this->auth_manager->check_permissions( AuthenticationManager::CAPABILITY_MANAGE_INVENTORY ) ) {
								return false;

			}

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

			foreach ( $stock_updates as $product_id => $stock_quantity ) {
				try {
					$success = $this->update_stock_level( $product_id, $stock_quantity, false );

					if ( $success ) {
						$results['successful']++;

						// Queue for sync if requested
						if ( $sync_immediately ) {
							$this->sync_engine->queue_sync( 'product', $product_id, 'update', 'to_sheets', [
								'priority' => 10,
							] );
						}
					} else {
						$results['failed']++;
						$results['errors'][] = "Failed to update stock for product ID: {$product_id}";
					}
				} catch ( \Exception $e ) {
								return false;
				}
			}

			return $results;

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

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

			}

			$search_term = sanitize_text_field( $search_term );

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

			// Add search parameters to filters
			$filters['search'] = $search_term;
			$filters['search_fields'] = [
				'name',
				'sku',
				'description',
			];

			return $this->get_products( $filters );

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

	/**
	 * Get low stock products
	 *
	 * @param int   $threshold Stock threshold
	 * @param array $filters Additional filters
	 * @return array
	 * @throws ShopExplorerException
	 */
	public function get_low_stock_products( $threshold = 5, $filters = [] ) {
		try {
			// Check permissions
			if ( ! $this->auth_manager->check_permissions( AuthenticationManager::CAPABILITY_VIEW_REPORTS ) ) {
								return false;

			}

			$filters['stock_threshold'] = max( 0, (int) $threshold );
			$filters['manage_stock'] = true;

			return $this->get_products( $filters );

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

	/**
	 * Get product statistics
	 *
	 * @param array $filters Filters for statistics
	 * @return array
	 * @throws ShopExplorerException
	 */
	public function get_product_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_product_statistics( $filters );

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

	/**
	 * Handle WooCommerce stock change
	 *
	 * @param \WC_Product $product WooCommerce product
	 */
	public function on_stock_change( $product ) {
		if ( ! $product instanceof \WC_Product ) {
			return;
		}

		$product_id = $product->get_id();

		// Queue immediate sync for stock changes
		$this->sync_engine->queue_sync( 'product', $product_id, 'update', 'to_sheets', [
			'priority' => 15, // Urgent priority for stock changes
		] );
	}

	/**
	 * Handle product update
	 *
	 * @param int $product_id Product ID
	 */
	public function on_product_update( $product_id ) {
		// Clear cache
		unset( $this->cache[ 'product_' . $product_id ] );

		// Queue sync
		$this->sync_engine->queue_sync( 'product', $product_id, 'update' );
	}

	/**
	 * Handle product creation
	 *
	 * @param int $product_id Product ID
	 */
	public function on_product_create( $product_id ) {
		// Queue sync for new product
		$this->sync_engine->queue_sync( 'product', $product_id, 'create' );
	}

	/**
	 * Track stock level changes
	 *
	 * @param int $product_id Product ID
	 * @param int $old_stock Old stock level
	 * @param int $new_stock New stock level
	 */
	private function track_stock_change( $product_id, $old_stock, $new_stock ) {
		$this->stock_changes[ $product_id ] = [
			'old_stock' => $old_stock,
			'new_stock' => $new_stock,
			'timestamp' => time(),
		];

		// Store in database for reporting
		global $wpdb;
		$table_name = $wpdb->prefix . 'shopex_stock_changes';

		$wpdb->insert(
			$table_name,
			[
				'product_id' => $product_id,
				'old_stock' => $old_stock,
				'new_stock' => $new_stock,
				'change_amount' => $new_stock - $old_stock,
				'user_id' => get_current_user_id(),
				'created_at' => current_time( 'mysql' ),
			],
			[ '%d', '%d', '%d', '%d', '%d', '%s' ]
		);
	}

	/**
	 * Sanitize product 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'] ) : 'name',
			'order' => isset( $filters['order'] ) && in_array( strtoupper( $filters['order'] ), [ 'ASC', 'DESC' ] ) ? strtoupper( $filters['order'] ) : 'ASC',
		];

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

		// Stock status filter
		if ( ! empty( $filters['stock_status'] ) ) {
			$valid_stock_statuses = ProductDataModel::get_valid_stock_statuses();
			if ( is_array( $filters['stock_status'] ) ) {
				$sanitized['stock_status'] = array_intersect( $filters['stock_status'], $valid_stock_statuses );
			} else {
				$stock_status = sanitize_text_field( $filters['stock_status'] );
				if ( in_array( $stock_status, $valid_stock_statuses, true ) ) {
					$sanitized['stock_status'] = [ $stock_status ];
				}
			}
		}

		// Product type filter
		if ( ! empty( $filters['type'] ) ) {
			$valid_types = ProductDataModel::get_valid_types();
			if ( is_array( $filters['type'] ) ) {
				$sanitized['type'] = array_intersect( $filters['type'], $valid_types );
			} else {
				$type = sanitize_text_field( $filters['type'] );
				if ( in_array( $type, $valid_types, true ) ) {
					$sanitized['type'] = [ $type ];
				}
			}
		}

		// Stock threshold filter
		if ( isset( $filters['stock_threshold'] ) ) {
			$sanitized['stock_threshold'] = max( 0, (int) $filters['stock_threshold'] );
		}

		// Manage stock filter
		if ( isset( $filters['manage_stock'] ) ) {
			$sanitized['manage_stock'] = (bool) $filters['manage_stock'];
		}

		// 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 product
	 *
	 * @param ProductDataModel $product Product data model
	 * @return bool
	 */
	private function can_access_product( $product ) {
		if ( ! $this->auth_manager->is_vendor_user() ) {
			return true; // Admin users can access all products
		}

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

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

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

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

		$allowed_fields = [
			'name' => 'sanitize_text_field',
			'sku' => 'sanitize_text_field',
			'stock_quantity' => 'intval',
			'price' => 'floatval',
			'regular_price' => 'floatval',
			'sale_price' => 'floatval',
			'stock_status' => 'sanitize_text_field',
			'manage_stock' => 'boolval',
			'type' => 'sanitize_text_field',
			'status' => 'sanitize_text_field',
		];

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

		return $sanitized;
	}

	/**
	 * Validate product data
	 *
	 * @param array $data Product data
	 * @param int   $product_id Product ID (for updates)
	 * @return array Validation errors
	 */
	private function validate_product_data( $data, $product_id = 0 ) {
		$errors = [];

		if ( isset( $data['name'] ) && empty( $data['name'] ) ) {
			$errors[] = 'Product name is required';
		}

		if ( isset( $data['sku'] ) && ! empty( $data['sku'] ) ) {
			// Check SKU uniqueness
			if ( $this->is_sku_duplicate( $data['sku'], $product_id ) ) {
				$errors[] = 'SKU is already in use by another product';
			}
		}

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

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

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

		if ( isset( $data['sale_price'] ) && $data['sale_price'] !== null && $data['sale_price'] < 0 ) {
			$errors[] = 'Sale price cannot be negative';
		}

		if ( isset( $data['type'] ) && ! ProductDataModel::is_valid_type( $data['type'] ) ) {
			$errors[] = 'Invalid product type';
		}

		if ( isset( $data['status'] ) && ! ProductDataModel::is_valid_status( $data['status'] ) ) {
			$errors[] = 'Invalid product status';
		}

		if ( isset( $data['stock_status'] ) && ! ProductDataModel::is_valid_stock_status( $data['stock_status'] ) ) {
			$errors[] = 'Invalid stock status';
		}

		return $errors;
	}

	/**
	 * Check if SKU is duplicate
	 *
	 * @param string $sku SKU to check
	 * @param int    $exclude_product_id Product ID to exclude from check
	 * @return bool
	 */
	private function is_sku_duplicate( $sku, $exclude_product_id = 0 ) {
		global $wpdb;

		$query = $wpdb->prepare(
			"SELECT post_id FROM {$wpdb->postmeta} 
			 WHERE meta_key = '_sku' 
			 AND meta_value = %s 
			 AND post_id != %d",
			$sku,
			$exclude_product_id
		);

		return (bool) $wpdb->get_var( $query );
	}

	/**
	 * Update WooCommerce product
	 *
	 * @param \WC_Product $wc_product WooCommerce product
	 * @param array       $data Update data
	 * @return bool
	 */
	private function update_wc_product( $wc_product, $data ) {
		try {
			foreach ( $data as $field => $value ) {
				switch ( $field ) {
					case 'name':
						$wc_product->set_name( $value );
						break;
					case 'sku':
						$wc_product->set_sku( $value );
						break;
					case 'stock_quantity':
						$wc_product->set_stock_quantity( $value );
						break;
					case 'price':
						$wc_product->set_price( $value );
						break;
					case 'regular_price':
						$wc_product->set_regular_price( $value );
						break;
					case 'sale_price':
						$wc_product->set_sale_price( $value );
						break;
					case 'stock_status':
						$wc_product->set_stock_status( $value );
						break;
					case 'manage_stock':
						$wc_product->set_manage_stock( $value );
						break;
					case 'status':
						$wc_product->set_status( $value );
						break;
				}
			}

			$wc_product->save();
			return true;

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

	/**
	 * Get stock change history
	 *
	 * @param int $product_id Product ID
	 * @param int $limit Limit
	 * @return array
	 */
	public function get_stock_change_history( $product_id, $limit = 50 ) {
		global $wpdb;
		$table_name = $wpdb->prefix . 'shopex_stock_changes';

		$query = $wpdb->prepare(
			"SELECT * FROM {$table_name} 
			 WHERE product_id = %d 
			 ORDER BY created_at DESC 
			 LIMIT %d",
			$product_id,
			$limit
		);

		return $wpdb->get_results( $query, ARRAY_A );
	}

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