<?php

class RPSync_WooCommerce {

	public function __construct() {
		add_action( 'rpsync_process_product_data', array( $this, 'process_product_data' ), 1 );
		add_action( 'rpsync_process_product_changes', array( $this, 'log_product_changes' ), 10, 3 );
		add_action( 'delete_post', array( $this, 'delete_post' ), 10, 2 );
		add_action( 'wc_merge_after', array( $this, 'wc_merge_after' ) );
	}

	/**
	 * Process extracted product_data for WooCommerce
	 *
	 * @param $data
	 *
	 * @return void
	 */
	public function process_product_data( $numref ) {
		// Load product data from RPSync database
		if ( empty( $product_data = RPSync::get_instance()->database->load_product_data( $numref ) ) ) {
			return;
		}

		// Process associated WooCommerce products
		foreach ( $product_data['skus'] as $sku => &$product ) {
			// Skip empty / invalid product_id
			if ( empty( $product['product_id'] ) ) {
				continue;
			}
			// Update product meta
			$changes = $this->update_product( $product['product_id'], $product );
			if ( ! empty( $changes ) ) {
				do_action( 'rpsync_process_product_changes', $changes, $sku, $product_data );
			}
		}
	}

	/**
	 * Update WooCommerce product postmeta / wc_product_meta_lookup
	 *
	 * @param $product_id
	 * @param $metas
	 *
	 * @return array
	 */
	public function update_product( $product_id, $metas ) {
		$changes = array();
		if ( empty( $wc_product = wc_get_product( $product_id ) ) ) {
			return $changes;
		}
		foreach ( $metas as $key => $value ) {
			switch ( $key ) {
				// SKU (only update if previously empty)
				case 'sku':
					if ( empty( $wc_product->get_sku() ) ) {
						try {
							$wc_product->set_sku( $value );
							$changes['sku'] = array( 'before' => '', 'after' => $value );
						} catch ( Exception $exception ) {
						}
					}
					break;

				// Stock
				case 'stock':
					if ( $value !== $wc_product->get_stock_quantity() ) {
						$wc_product->set_stock_quantity( $value );
						$changes['stock'] = array( 'before' => $wc_product->get_stock_quantity(), 'after' => $value );
					}
					break;

				// Prices
				case 'regular_price':
					if ( $value !== $wc_product->get_regular_price() ) {
						$wc_product->set_regular_price( $value );
						$changes['regular_price'] = array( 'before' => $wc_product->get_regular_price(), 'after' => $value );
					}
					break;
				case 'sale_price':
					if ( $value !== $wc_product->get_sale_price() ) {
						$wc_product->set_sale_price( $value );
						$changes['sale_price'] = array( 'before' => $wc_product->get_sale_price(), 'after' => $value );
					}
					break;
			}
		}
		$wc_product->save();
		return $changes;
	}

	/**
	 * Log product changes
	 *
	 * @param $changes
	 * @param $sku
	 * @param $product_data
	 *
	 * @return void
	 */
	public function log_product_changes( $changes, $sku, $product_data ) {
		if ( empty( $product = $product_data['skus'][ $sku ] ) ) {
			return;
		}
		$changes = implode( "\n", array_map( function ( $key, $value ) {
			return "  $key: ${value['before']} => ${value['after']}";
		}, array_keys( $changes ), $changes ) );
		RPSync::get_instance()->info( sprintf( "%s (Numref %s / SKU %s / ID: %d)\n", $product['title'], $product_data['numref'], $sku, $product['product_id'] ) . $changes );
	}

	/**
	 * Create WooCommerce product by numref
	 *
	 * @param string $numref
	 *
	 * @return bool
	 * @throws WC_Data_Exception
	 */
	public function create_product( string $numref ) {
		// Load Retailpoint product data
		if ( empty( $product_data = RPSync::get_instance()->database->load_product_data( $numref ) ) ) {
			return false;
		}

		// Check if WC product already exists
		if ( ! empty( $product_data['product_id'] ) ) {
			return false;
		}

		// Create simple / variable product
		if ( sizeof( $product_data['skus'] ) === 1 ) {
			// Create simple product with 'draft' status
			$product    = &$product_data['skus'][ array_key_first( $product_data['skus'] ) ];
			$wc_product = new WC_Product_Simple();
			$wc_product->set_status( 'draft' );
			$wc_product->set_name( $product['title'] );
			$wc_product->set_sku( $product['sku'] );
			$wc_product->set_manage_stock( 'yes' );
			if ( ! $wc_product->save() ) {
				return false;
			}
			// Update product_id in RPSync tables
			$product_data['product_id'] = $product['product_id'] = $wc_product->get_id();
			if ( ! RPSync::get_instance()->database->save_product_data( $product_data ) ) {
				return false;
			}
		} else {
			// Create variable product with 'draft' status
			$wc_product = new WC_Product_Variable();
			$wc_product->set_status( 'draft' );
			$wc_product->set_name( reset( $product_data['skus'] )['title'] );
			$wc_product->set_attributes( $this->create_variable_attributes( $product_data ) );
			if ( ! $wc_product->save() ) {
				return false;
			}
			$product_data['product_id'] = $wc_product->get_id();
			foreach ( $product_data['skus'] as &$product ) {
				// Create product variation
				$wc_variation = new WC_Product_Variation();
				$wc_variation->set_parent_id( $wc_product->get_id() );
				$wc_variation->set_status( 'publish' );
				$wc_variation->set_sku( $product['sku'] );
				$wc_variation->set_attributes( $product['attributes'] );
				$wc_variation->set_manage_stock( 'yes' );
				if ( ! $wc_variation->save() ) {
					return false;
				}
				$product['product_id'] = $wc_variation->get_id();
			}
			if ( ! RPSync::get_instance()->database->save_product_data( $product_data ) ) {
				return false;
			}
		}

		// Process newly created product synchronously
		do_action( 'rpsync_process_product_data', $numref );
		return true;
	}

	/**
	 * Create variable product attributes
	 *
	 * @param array $product_data
	 *
	 * @return array
	 */
	public function create_variable_attributes( array $product_data ) {
		$attributes = array();
		foreach ( $product_data['skus'] as $product ) {
			foreach ( $product['attributes'] as $name => $value ) {
				$attributes[ $name ][] = $value;
			}
		}

		return array_map( function ( $name, array $options ) {
			$wc_attribute = new WC_Product_Attribute();
			$wc_attribute->set_name( $name );
			$wc_attribute->set_options( $options );
			$wc_attribute->set_visible( true );
			if ( sizeof( $options ) > 1 ) {
				$wc_attribute->set_variation( true );
			}
			return $wc_attribute;
		}, array_keys( $attributes ), array_map( 'array_unique', $attributes ) );
	}

	/**
	 * Destroy WooCommerce product by numref
	 *
	 * @param string $numref
	 *
	 * @return bool
	 */
	public function destroy_product( string $numref ) {
		if ( empty( $product_data = RPSync::get_instance()->database->load_product_data( $numref ) ) ) {
			return false;
		}
		if ( empty( $product_data['product_id'] ) || ! wp_delete_post( $product_data['product_id'] ) ) {
			return false;
		}
		$product_data['product_id'] = null;
		foreach ( $product_data['skus'] as &$product ) {
			$product['product_id'] = null;
		}

		return RPSync::get_instance()->database->save_product_data( $product_data );
	}

	/**
	 * Delete product association when product is deleted
	 */
	public function delete_post( $post_id, WP_Post $post ) {
		if ( $post->post_type !== 'product' ) {
			return;
		}
		RPSync::get_instance()->database->delete_product_id( $post_id );
	}

	/**
	 * Update product_id in numrefs table after product merge
	 *
	 * @param $product_id
	 *
	 * @return void
	 */
	public function wc_merge_after( $product_id ) {
		$numrefs = RPSync::get_instance()->database->get_numrefs( $product_id );
		foreach ( $numrefs as $numref ) {
			$product_data               = RPSync::get_instance()->database->load_product_data( $numref );
			$product_data['product_id'] = $product_id;
			RPSync::get_instance()->database->save_product_data( $product_data );
			do_action( 'rpsync_process_product_data', $numref );
		}
	}
}
