<?php
/**
 * Order 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.
}

/**
 * Order Data Model class
 *
 * Represents order data with validation and transformation methods
 *
 * @since 1.0.0
 */
class SHOPEX_OrderDataModel {

	/**
	 * Order ID
	 *
	 * @var int
	 */
	public $order_id;

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

	/**
	 * Customer information
	 *
	 * @var array
	 */
	public $customer_info;

	/**
	 * Order items
	 *
	 * @var array
	 */
	public $items;

	/**
	 * Order totals
	 *
	 * @var array
	 */
	public $totals;

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

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

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

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

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

	/**
	 * Populate model with data
	 *
	 * @param array $data Order data
	 */
	public function populate( $data ) {
		$this->order_id = isset( $data['id'] ) ? (int) $data['id'] : 0;
		$this->status = isset( $data['status'] ) ? sanitize_text_field( $data['status'] ) : 'pending';
		$this->customer_info = $this->sanitize_customer_info( $data['customer_info'] ?? [] );
		$this->items = $this->sanitize_items( $data['items'] ?? [] );
		$this->totals = $this->sanitize_totals( $data['totals'] ?? [] );
		$this->custom_fields = $this->sanitize_custom_fields( $data['custom_fields'] ?? [] );
		$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 order data
	 *
	 * @return bool|array True if valid, array of errors if invalid
	 */
	public function validate() {
		$errors = [];

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

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

		// Validate customer info
		if ( empty( $this->customer_info['email'] ) ) {
			$errors[] = __( 'Customer email is required', 'shop-explorer' );
		} elseif ( ! is_email( $this->customer_info['email'] ) ) {
			$errors[] = __( 'Invalid customer email format', 'shop-explorer' );
		}

		// Validate items
		if ( empty( $this->items ) ) {
			$errors[] = __( 'Order must have at least one item', 'shop-explorer' );
		} else {
			foreach ( $this->items as $index => $item ) {
				if ( empty( $item['product_id'] ) ) {
					$errors[] = sprintf(
						/* translators: %s: is the product id */
						__( 'Item %d: Product ID is required', 'shop-explorer' ),
						$index + 1
					);
				}
				if ( empty( $item['quantity'] ) || $item['quantity'] <= 0 ) {
					$errors[] = sprintf(
						/* translators: %s: is the product id */
						__( 'Item %d: Valid quantity is required', 'shop-explorer' ),
						$index + 1
					);
				}
			}
		}

		// Validate totals
		if ( ! isset( $this->totals['total'] ) || $this->totals['total'] < 0 ) {
			$errors[] = __( 'Valid order total is required', 'shop-explorer' );
		}

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

	/**
	 * Convert to array
	 *
	 * @return array
	 */
	public function to_array() {
		return [
			'order_id' => $this->order_id,
			'status' => $this->status,
			'customer_info' => $this->customer_info,
			'items' => $this->items,
			'totals' => $this->totals,
			'custom_fields' => $this->custom_fields,
			'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 order
	 *
	 * @param \WC_Order $order WooCommerce order object
	 * @return self
	 */
	public static function from_wc_order( $order ) {
		$data = [
			'id' => $order->get_id(),
			'status' => $order->get_status(),
			'customer_info' => [
				'id' => $order->get_customer_id(),
				'email' => $order->get_billing_email(),
				'first_name' => $order->get_billing_first_name(),
				'last_name' => $order->get_billing_last_name(),
				'phone' => $order->get_billing_phone(),
				'company' => $order->get_billing_company(),
				'address_1' => $order->get_billing_address_1(),
				'address_2' => $order->get_billing_address_2(),
				'city' => $order->get_billing_city(),
				'state' => $order->get_billing_state(),
				'postcode' => $order->get_billing_postcode(),
				'country' => $order->get_billing_country(),
			],
			'items' => [],
			'totals' => [
				'subtotal' => $order->get_subtotal(),
				'tax' => $order->get_total_tax(),
				'shipping' => $order->get_shipping_total(),
				'discount' => $order->get_total_discount(),
				'total' => $order->get_total(),
				'currency' => $order->get_currency(),
			],
			'custom_fields' => [],
			'sync_status' => 'synced',
			'last_modified' => $order->get_date_modified()->date( 'Y-m-d H:i:s' ),
		];

		// Get order items
		foreach ( $order->get_items() as $item ) {
			$data['items'][] = [
				'id' => $item->get_id(),
				'product_id' => $item->get_product_id(),
				'variation_id' => $item->get_variation_id(),
				'name' => $item->get_name(),
				'quantity' => $item->get_quantity(),
				'price' => $item->get_total() / $item->get_quantity(),
				'total' => $item->get_total(),
				'sku' => $item->get_product() ? $item->get_product()->get_sku() : '',
			];
		}

		// Get custom fields from meta data
		foreach ( $order->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'];
			}
		}

		return new self( $data );
	}

	/**
	 * Create from database row
	 *
	 * @param array $row Database row data
	 * @return self
	 */
	public static function from_db_row( $row ) {
		$data = [
			'id' => $row['id'] ?? $row['ID'] ?? 0,
			'status' => str_replace( 'wc-', '', $row['status'] ?? $row['post_status'] ?? 'pending' ),
			'customer_info' => [
				'id' => $row['customer_id'] ?? $row['meta_data']['_customer_user'] ?? 0,
				'email' => $row['billing_email'] ?? $row['meta_data']['_billing_email'] ?? '',
				'first_name' => $row['billing_first_name'] ?? $row['meta_data']['_billing_first_name'] ?? '',
				'last_name' => $row['billing_last_name'] ?? $row['meta_data']['_billing_last_name'] ?? '',
			],
			'totals' => [
				'total' => $row['total'] ?? $row['meta_data']['_order_total'] ?? 0,
				'currency' => $row['currency'] ?? $row['meta_data']['_order_currency'] ?? 'USD',
			],
			'custom_fields' => $row['meta_data'] ?? [],
			'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->order_id,
			$this->status,
			$this->customer_info['email'] ?? '',
			$this->customer_info['first_name'] ?? '',
			$this->customer_info['last_name'] ?? '',
			$this->totals['total'] ?? 0,
			$this->totals['currency'] ?? 'USD',
			count( $this->items ),
			$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 'order_id':
					$data['id'] = (int) $value;
					break;
				case 'status':
					$data['status'] = sanitize_text_field( $value );
					break;
				case 'customer_email':
					$data['customer_info']['email'] = sanitize_email( $value );
					break;
				case 'customer_first_name':
					$data['customer_info']['first_name'] = sanitize_text_field( $value );
					break;
				case 'customer_last_name':
					$data['customer_info']['last_name'] = sanitize_text_field( $value );
					break;
				case 'total':
					$data['totals']['total'] = (float) $value;
					break;
				case 'currency':
					$data['totals']['currency'] = sanitize_text_field( $value );
					break;
				default:
					$data['custom_fields'][ $header ] = sanitize_text_field( $value );
					break;
			}
		}

		return new self( $data );
	}

	/**
	 * Sanitize customer info
	 *
	 * @param array $customer_info Customer information
	 * @return array
	 */
	private function sanitize_customer_info( $customer_info ) {
		$sanitized = [];

		$fields = [
			'id' => 'intval',
			'email' => 'sanitize_email',
			'first_name' => 'sanitize_text_field',
			'last_name' => 'sanitize_text_field',
			'phone' => 'sanitize_text_field',
			'company' => 'sanitize_text_field',
			'address_1' => 'sanitize_text_field',
			'address_2' => 'sanitize_text_field',
			'city' => 'sanitize_text_field',
			'state' => 'sanitize_text_field',
			'postcode' => 'sanitize_text_field',
			'country' => 'sanitize_text_field',
		];

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

		return $sanitized;
	}

	/**
	 * Sanitize order items
	 *
	 * @param array $items Order items
	 * @return array
	 */
	private function sanitize_items( $items ) {
		$sanitized = [];

		foreach ( $items as $item ) {
			$sanitized[] = [
				'id' => isset( $item['id'] ) ? (int) $item['id'] : 0,
				'product_id' => isset( $item['product_id'] ) ? (int) $item['product_id'] : 0,
				'variation_id' => isset( $item['variation_id'] ) ? (int) $item['variation_id'] : 0,
				'name' => isset( $item['name'] ) ? sanitize_text_field( $item['name'] ) : '',
				'quantity' => isset( $item['quantity'] ) ? (int) $item['quantity'] : 1,
				'price' => isset( $item['price'] ) ? (float) $item['price'] : 0,
				'total' => isset( $item['total'] ) ? (float) $item['total'] : 0,
				'sku' => isset( $item['sku'] ) ? sanitize_text_field( $item['sku'] ) : '',
			];
		}

		return $sanitized;
	}

	/**
	 * Sanitize order totals
	 *
	 * @param array $totals Order totals
	 * @return array
	 */
	private function sanitize_totals( $totals ) {
		return [
			'subtotal' => isset( $totals['subtotal'] ) ? (float) $totals['subtotal'] : 0,
			'tax' => isset( $totals['tax'] ) ? (float) $totals['tax'] : 0,
			'shipping' => isset( $totals['shipping'] ) ? (float) $totals['shipping'] : 0,
			'discount' => isset( $totals['discount'] ) ? (float) $totals['discount'] : 0,
			'total' => isset( $totals['total'] ) ? (float) $totals['total'] : 0,
			'currency' => isset( $totals['currency'] ) ? sanitize_text_field( $totals['currency'] ) : 'USD',
		];
	}

	/**
	 * 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 ) {
			$sanitized[ sanitize_key( $key ) ] = sanitize_text_field( $value );
		}

		return $sanitized;
	}

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

	/**
	 * 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 );
	}
}
