<?php
/**
 * Product Data Model Class
 *
 * @package ShopExplorer\Models
 * @since 1.0.0
 */

namespace SHOPEXPLORER\Models;

use SHOPEXPLORER\Exceptions\ShopExplorerException;

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

/**
 * Product Data Model class
 *
 * Represents product data with validation and transformation methods
 *
 * @since 1.0.0
 */
class SHOPEX_ProductDataModel {

	/**
	 * Product ID
	 *
	 * @var int
	 */
	public $product_id;

	/**
	 * Product name
	 *
	 * @var string
	 */
	public $name;

	/**
	 * Product SKU
	 *
	 * @var string
	 */
	public $sku;

	/**
	 * Stock quantity
	 *
	 * @var int|null
	 */
	public $stock_quantity;

	/**
	 * Product price
	 *
	 * @var float
	 */
	public $price;

	/**
	 * Regular price
	 *
	 * @var float
	 */
	public $regular_price;

	/**
	 * Sale price
	 *
	 * @var float|null
	 */
	public $sale_price;

	/**
	 * Stock status
	 *
	 * @var string
	 */
	public $stock_status;

	/**
	 * Manage stock flag
	 *
	 * @var bool
	 */
	public $manage_stock;

	/**
	 * Product type
	 *
	 * @var string
	 */
	public $type;

	/**
	 * Product status
	 *
	 * @var string
	 */
	public $status;

	/**
	 * Custom fields
	 *
	 * @var array
	 */
	public $custom_fields;

	/**
	 * Vendor ID (for multivendor)
	 *
	 * @var int|null
	 */
	public $vendor_id;

	/**
	 * Sync status
	 *
	 * @var string
	 */
	public $sync_status;

	/**
	 * Last modified timestamp
	 *
	 * @var string
	 */
	public $last_modified;

	/**
	 * Valid product types
	 *
	 * @var array
	 */
	private static $valid_types = [
		'simple',
		'grouped',
		'external',
		'variable',
		'variation',
	];

	/**
	 * Valid product statuses
	 *
	 * @var array
	 */
	private static $valid_statuses = [
		'publish',
		'draft',
		'private',
		'pending',
	];

	/**
	 * Valid stock statuses
	 *
	 * @var array
	 */
	private static $valid_stock_statuses = [
		'instock',
		'outofstock',
		'onbackorder',
	];

	/**
	 * Constructor
	 *
	 * @param array $data Product data
	 */
	public function __construct( $data = [] ) {
		$this->populate( $data );
	}

	/**
	 * Populate model with data
	 *
	 * @param array $data Product data
	 */
	public function populate( $data ) {
		$this->product_id = isset( $data['id'] ) ? (int) $data['id'] : 0;
		$this->name = isset( $data['name'] ) ? sanitize_text_field( $data['name'] ) : '';
		$this->sku = isset( $data['sku'] ) ? sanitize_text_field( $data['sku'] ) : '';
		$this->stock_quantity = isset( $data['stock_quantity'] ) ? (int) $data['stock_quantity'] : null;
		$this->price = isset( $data['price'] ) ? (float) $data['price'] : 0;
		$this->regular_price = isset( $data['regular_price'] ) ? (float) $data['regular_price'] : 0;
		$this->sale_price = isset( $data['sale_price'] ) && $data['sale_price'] !== '' ? (float) $data['sale_price'] : null;
		$this->stock_status = isset( $data['stock_status'] ) ? sanitize_text_field( $data['stock_status'] ) : 'instock';
		$this->manage_stock = isset( $data['manage_stock'] ) ? (bool) $data['manage_stock'] : false;
		$this->type = isset( $data['type'] ) ? sanitize_text_field( $data['type'] ) : 'simple';
		$this->status = isset( $data['status'] ) ? sanitize_text_field( $data['status'] ) : 'publish';
		$this->custom_fields = $this->sanitize_custom_fields( $data['custom_fields'] ?? [] );
		$this->vendor_id = isset( $data['vendor_id'] ) ? (int) $data['vendor_id'] : null;
		$this->sync_status = isset( $data['sync_status'] ) ? sanitize_text_field( $data['sync_status'] ) : 'pending';
		$this->last_modified = isset( $data['last_modified'] ) ? sanitize_text_field( $data['last_modified'] ) : current_time( 'mysql' );
	}

	/**
	 * Validate product data
	 *
	 * @return bool|array True if valid, array of errors if invalid
	 */
	public function validate() {
		$errors = [];

		// Validate product ID
		if ( empty( $this->product_id ) ) {
			$errors[] = __( 'Product ID is required', 'shop-explorer' );
		}

		// Validate name
		if ( empty( $this->name ) ) {
			$errors[] = __( 'Product name is required', 'shop-explorer' );
		}

		// Validate type
		if ( ! in_array( $this->type, self::$valid_types, true ) ) {
			$errors[] = sprintf(
				/* translators: %s: is the product id */
				__( 'Invalid product type: %s', 'shop-explorer' ),
				$this->type
			);
		}

		// Validate status
		if ( ! in_array( $this->status, self::$valid_statuses, true ) ) {
			$errors[] = sprintf(
				/* translators: %s: is the product id */
				__( 'Invalid product status: %s', 'shop-explorer' ),
				$this->status
			);
		}

		// Validate stock status
		if ( ! in_array( $this->stock_status, self::$valid_stock_statuses, true ) ) {
			$errors[] = sprintf(
				/* translators: %s: is the product id */
				__( 'Invalid stock status: %s', 'shop-explorer' ),
				$this->stock_status
			);
		}

		// Validate prices
		if ( $this->price < 0 ) {
			$errors[] = __( 'Product price cannot be negative', 'shop-explorer' );
		}

		if ( $this->regular_price < 0 ) {
			$errors[] = __( 'Regular price cannot be negative', 'shop-explorer' );
		}

		if ( $this->sale_price !== null && $this->sale_price < 0 ) {
			$errors[] = __( 'Sale price cannot be negative', 'shop-explorer' );
		}

		// Validate stock quantity if managing stock
		if ( $this->manage_stock && $this->stock_quantity < 0 ) {
			$errors[] = __( 'Stock quantity cannot be negative', 'shop-explorer' );
		}

		// Validate SKU uniqueness (if provided)
		if ( ! empty( $this->sku ) && $this->is_sku_duplicate() ) {
			$errors[] = sprintf(
				/* translators: %s: is the product id */
				__( 'SKU "%s" is already in use by another product', 'shop-explorer' ),
				$this->sku
			);
		}

		return empty( $errors ) ? true : $errors;
	}

	/**
	 * Check if SKU is duplicate
	 *
	 * @return bool
	 */
	private function is_sku_duplicate() {
		global $wpdb;

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

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

	/**
	 * Convert to array
	 *
	 * @return array
	 */
	public function to_array() {
		return [
			'product_id' => $this->product_id,
			'name' => $this->name,
			'sku' => $this->sku,
			'stock_quantity' => $this->stock_quantity,
			'price' => $this->price,
			'regular_price' => $this->regular_price,
			'sale_price' => $this->sale_price,
			'stock_status' => $this->stock_status,
			'manage_stock' => $this->manage_stock,
			'type' => $this->type,
			'status' => $this->status,
			'custom_fields' => $this->custom_fields,
			'vendor_id' => $this->vendor_id,
			'sync_status' => $this->sync_status,
			'last_modified' => $this->last_modified,
		];
	}

	/**
	 * Convert to JSON
	 *
	 * @return string
	 */
	public function to_json() {
		return wp_json_encode( $this->to_array() );
	}

	/**
	 * Create from WooCommerce product
	 *
	 * @param \WC_Product $product WooCommerce product object
	 * @return self
	 */
	public static function from_wc_product( $product ) {
		$data = [
			'id' => $product->get_id(),
			'name' => $product->get_name(),
			'sku' => $product->get_sku(),
			'stock_quantity' => $product->get_stock_quantity(),
			'price' => $product->get_price(),
			'regular_price' => $product->get_regular_price(),
			'sale_price' => $product->get_sale_price(),
			'stock_status' => $product->get_stock_status(),
			'manage_stock' => $product->get_manage_stock(),
			'type' => $product->get_type(),
			'status' => $product->get_status(),
			'custom_fields' => [],
			'sync_status' => 'synced',
			'last_modified' => $product->get_date_modified()->date( 'Y-m-d H:i:s' ),
		];

		// Get custom fields from meta data
		foreach ( $product->get_meta_data() as $meta ) {
			$meta_data = $meta->get_data();
			if ( ! empty( $meta_data['key'] ) && strpos( $meta_data['key'], '_' ) !== 0 ) {
				$data['custom_fields'][ $meta_data['key'] ] = $meta_data['value'];
			}
		}

		// Check for vendor ID (multivendor support)
		$vendor_id = $product->get_meta( '_vendor_id' );
		if ( $vendor_id ) {
			$data['vendor_id'] = (int) $vendor_id;
		}

		return new self( $data );
	}

	/**
	 * Create from database row
	 *
	 * @param array $row Database row data
	 * @return self
	 */
	public static function from_db_row( $row ) {
		$meta_data = $row['meta_data'] ?? [];

		$data = [
			'id' => $row['id'] ?? $row['ID'] ?? 0,
			'name' => $row['name'] ?? $row['post_title'] ?? '',
			'sku' => $meta_data['_sku'] ?? '',
			'stock_quantity' => isset( $meta_data['_stock'] ) ? (int) $meta_data['_stock'] : null,
			'price' => isset( $meta_data['_price'] ) ? (float) $meta_data['_price'] : 0,
			'regular_price' => isset( $meta_data['_regular_price'] ) ? (float) $meta_data['_regular_price'] : 0,
			'sale_price' => isset( $meta_data['_sale_price'] ) && $meta_data['_sale_price'] !== '' ? (float) $meta_data['_sale_price'] : null,
			'stock_status' => $meta_data['_stock_status'] ?? 'instock',
			'manage_stock' => ( $meta_data['_manage_stock'] ?? 'no' ) === 'yes',
			'type' => $meta_data['_product_type'] ?? 'simple',
			'status' => $row['status'] ?? $row['post_status'] ?? 'publish',
			'custom_fields' => $meta_data,
			'vendor_id' => isset( $meta_data['_vendor_id'] ) ? (int) $meta_data['_vendor_id'] : null,
			'sync_status' => 'pending',
			'last_modified' => $row['date_created'] ?? $row['post_date'] ?? current_time( 'mysql' ),
		];

		return new self( $data );
	}

	/**
	 * Get Google Sheets row data
	 *
	 * @return array
	 */
	public function to_sheets_row() {
		$row = [
			$this->product_id,
			$this->name,
			$this->sku,
			$this->stock_quantity ?? '',
			$this->price,
			$this->regular_price,
			$this->sale_price ?? '',
			$this->stock_status,
			$this->manage_stock ? 'yes' : 'no',
			$this->type,
			$this->status,
			$this->vendor_id ?? '',
			$this->last_modified,
		];

		// Add custom fields
		foreach ( $this->custom_fields as $value ) {
			$row[] = $value;
		}

		return $row;
	}

	/**
	 * Create from Google Sheets row
	 *
	 * @param array $row Sheets row data
	 * @param array $headers Column headers
	 * @return self
	 */
	public static function from_sheets_row( $row, $headers ) {
		$data = [];

		foreach ( $headers as $index => $header ) {
			$value = $row[ $index ] ?? '';

			switch ( $header ) {
				case 'product_id':
					$data['id'] = (int) $value;
					break;
				case 'name':
					$data['name'] = sanitize_text_field( $value );
					break;
				case 'sku':
					$data['sku'] = sanitize_text_field( $value );
					break;
				case 'stock_quantity':
					$data['stock_quantity'] = $value !== '' ? (int) $value : null;
					break;
				case 'price':
					$data['price'] = (float) $value;
					break;
				case 'regular_price':
					$data['regular_price'] = (float) $value;
					break;
				case 'sale_price':
					$data['sale_price'] = $value !== '' ? (float) $value : null;
					break;
				case 'stock_status':
					$data['stock_status'] = sanitize_text_field( $value );
					break;
				case 'manage_stock':
					$data['manage_stock'] = strtolower( $value ) === 'yes';
					break;
				case 'type':
					$data['type'] = sanitize_text_field( $value );
					break;
				case 'status':
					$data['status'] = sanitize_text_field( $value );
					break;
				case 'vendor_id':
					$data['vendor_id'] = $value !== '' ? (int) $value : null;
					break;
				default:
					$data['custom_fields'][ $header ] = sanitize_text_field( $value );
					break;
			}
		}

		return new self( $data );
	}

	/**
	 * Update stock quantity
	 *
	 * @param int $quantity New stock quantity
	 * @return self
	 */
	public function update_stock( $quantity ) {
		$this->stock_quantity = (int) $quantity;
		$this->stock_status = $quantity > 0 ? 'instock' : 'outofstock';
		$this->last_modified = current_time( 'mysql' );
		$this->sync_status = 'pending';

		return $this;
	}

	/**
	 * Update price
	 *
	 * @param float      $price New price
	 * @param float|null $sale_price New sale price
	 * @return self
	 */
	public function update_price( $price, $sale_price = null ) {
		$this->regular_price = (float) $price;
		$this->sale_price = $sale_price !== null ? (float) $sale_price : null;
		$this->price = $sale_price !== null ? (float) $sale_price : (float) $price;
		$this->last_modified = current_time( 'mysql' );
		$this->sync_status = 'pending';

		return $this;
	}

	/**
	 * Check if product is in stock
	 *
	 * @return bool
	 */
	public function is_in_stock() {
		if ( ! $this->manage_stock ) {
			return $this->stock_status === 'instock';
		}

		return $this->stock_quantity > 0;
	}

	/**
	 * Check if product is on sale
	 *
	 * @return bool
	 */
	public function is_on_sale() {
		return $this->sale_price !== null && $this->sale_price < $this->regular_price;
	}

	/**
	 * Get display price
	 *
	 * @return float
	 */
	public function get_display_price() {
		return $this->is_on_sale() ? $this->sale_price : $this->regular_price;
	}

	/**
	 * Sanitize custom fields
	 *
	 * @param array $custom_fields Custom fields
	 * @return array
	 */
	private function sanitize_custom_fields( $custom_fields ) {
		$sanitized = [];

		foreach ( $custom_fields as $key => $value ) {
			// Skip WooCommerce internal meta keys
			if ( strpos( $key, '_' ) === 0 ) {
				continue;
			}

			$sanitized[ sanitize_key( $key ) ] = sanitize_text_field( $value );
		}

		return $sanitized;
	}

	/**
	 * Get valid types
	 *
	 * @return array
	 */
	public static function get_valid_types() {
		return self::$valid_types;
	}

	/**
	 * Get valid statuses
	 *
	 * @return array
	 */
	public static function get_valid_statuses() {
		return self::$valid_statuses;
	}

	/**
	 * Get valid stock statuses
	 *
	 * @return array
	 */
	public static function get_valid_stock_statuses() {
		return self::$valid_stock_statuses;
	}

	/**
	 * Check if type is valid
	 *
	 * @param string $type Type to check
	 * @return bool
	 */
	public static function is_valid_type( $type ) {
		return in_array( $type, self::$valid_types, true );
	}

	/**
	 * Check if status is valid
	 *
	 * @param string $status Status to check
	 * @return bool
	 */
	public static function is_valid_status( $status ) {
		return in_array( $status, self::$valid_statuses, true );
	}

	/**
	 * Check if stock status is valid
	 *
	 * @param string $stock_status Stock status to check
	 * @return bool
	 */
	public static function is_valid_stock_status( $stock_status ) {
		return in_array( $stock_status, self::$valid_stock_statuses, true );
	}
}
