<?php
/**
 * Creates article model instances
 *
 * @package flo-sync
 */

namespace NMFS\Sync\Items\Articles;

use NMFS\Shared;
use NMFS\Sync\Items\Articles\Models\Article_Model;
use NMFS\Sync\Items\Articles\Models\Variation_Model;
use NMFS\Sync\Items\Articles\Stock\Stock;
use Northmill_Online_Shared_Sync\Northmill_Online_Shared\Abstracts\Hub_API\Models\Hub_API_Properties;
use Northmill_Online_Shared_Sync\Northmill_Online_Shared\Modules\Loggers\Log_Level_Enum;
use Northmill_Online_Shared_Sync\Northmill_Online_Shared\Modules\Sync\Bookkeeping\Article_Account_Codes\Article_Account_Codes;
use WC_Product;
use WC_Product_Variation;

defined( 'ABSPATH' ) || exit;

/**
 * Class Article_Model_Factory
 */
class Article_Model_Factory {

	/**
	 * Create article model from WC product.
	 *
	 * @param WC_Product $wc_product WC product instance.
	 *
	 * @return Article_Model
	 */
	public static function create_from_wc( WC_Product $wc_product ): Article_Model {

		$manages_stock = get_post_meta( $wc_product->get_id(), Articles::CORE_META_KEY_MANAGE_STOCK, true ) === 'yes';

		if ( $wc_product instanceof WC_Product_Variation ) {
			$parent_product = wc_get_product( $wc_product->get_parent_id() );

			$product_title = self::get_variation_name( $parent_product, $wc_product );
		} else {
			$product_title = $wc_product->get_name();
		}

		$tax_clas_slug = $wc_product->get_tax_class( 'edit' );

		// 'parent' means that the product is a variation and is set to inherit the tax class from the parent product.
		if ( 'parent' === $tax_clas_slug ) {
			$parent_product = wc_get_product( $wc_product->get_parent_id() );
			$tax_clas_slug  = $parent_product->get_tax_class( 'edit' );
		}

		$account_code_id = Article_Account_Codes::get_id_by_slug( $tax_clas_slug );

		$description     = $wc_product->get_description();
		$description_raw = esc_html( $description );

		$barcodes = get_post_meta( $wc_product->get_id(), Articles::META_KEY_BARCODE );

		if ( is_array( $barcodes ) ) {
			$main_barcode = array_shift( $barcodes );
		} else {
			$barcodes     = null;
			$main_barcode = null;
		}

		$order_ticket_dialogue = get_post_meta( $wc_product->get_id(), Articles::META_KEY_ORDER_TICKET_DIALOGUE, true );
		$order_ticket_text     = get_post_meta( $wc_product->get_id(), Articles::META_KEY_ORDER_TICKET_TEXT, true );
		if ( empty( $order_ticket_text ) ) {
			$order_ticket_text = array();
		} elseif ( ! is_array( $order_ticket_text ) ) {
			$order_ticket_text = array( $order_ticket_text );
		}

		return new Article_Model(
			$wc_product->get_status(),
			$wc_product->get_sku(),
			Stock::get_stock_quantity_for_main_account( $wc_product ),
			$product_title,
			$manages_stock,
			$wc_product->get_menu_order(),
			$description,
			$description_raw,
			null, // TODO: Implement, get category Hub id.
			floatval( $wc_product->get_regular_price() ),
			$account_code_id,
			$main_barcode,
			$barcodes,
			array(), // TODO: Implement.
			$order_ticket_dialogue,
			$order_ticket_text,
			null,
			null,
			Article_Sync_Meta_Helpers::get_hash( $wc_product->get_id() ),
			$wc_product
		);
	}

	/**
	 * Create article model from WC product variation.
	 *
	 * @param WC_Product $wc_product WC product instance.
	 * @param int        $variation_id WC variation ID.
	 *
	 * @return Variation_Model|null
	 */
	public static function create_from_wc_variation( WC_Product $wc_product, int $variation_id ): ?Variation_Model {
		$variation = wc_get_product( $variation_id );

		if ( ! $variation instanceof WC_Product_Variation ) {
			Shared::instance()->logger->log(
				'sync',
				'This product is not an instance of WC_Product_Variation',
				array(
					'product'    => $wc_product->get_id(),
					'variant_id' => $variation_id,
				),
				Log_Level_Enum::ERROR
			);
			return null;
		}

		return new Variation_Model( self::create_from_wc( $variation ) );
	}

	/**
	 * Create article model from Hub API data.
	 *
	 * @param array $hub_data Data from API.
	 */
	public static function create_from_api( array $hub_data ): Article_Model {
		$sku = $hub_data[ Hub_API_Properties::ARTICLE_NUMBER ];

		$article_type = $hub_data[ Hub_API_Properties::ARTICLE_TYPE ];
		if ( 0 === $article_type ) {
			$article_type = Hub_API_Properties::ARTICLE_TYPE_GOODS;
		}

		$order_ticket_text = str_replace(
			array(
				"\r\n",
				"\r",
			),
			"\n",
			$hub_data[ Hub_API_Properties::ARTICLE_ORDER_TICKET_TEXT ] ?? array()
		);
		$order_ticket      = array_filter( explode( "\n", $order_ticket_text ) );

		$wc_product  = null;
		$product_id  = wc_get_product_id_by_sku( $sku );
		$stored_hash = false;
		if ( ! empty( $product_id ) ) {
			$wc_product  = wc_get_product( $product_id );
			$stored_hash = Article_Sync_Meta_Helpers::get_hash( $product_id );
		}

		return new Article_Model(
			$hub_data[ Hub_API_Properties::ARTICLE_IS_ACTIVE ] ? Articles::PRODUCT_STATUS_PUBLISH : Articles::PRODUCT_STATUS_DRAFT,
			$hub_data[ Hub_API_Properties::ARTICLE_NUMBER ],
			$hub_data[ Hub_API_Properties::ARTICLE_QUANTITY ],
			$hub_data[ Hub_API_Properties::ARTICLE_NAME ],
			$hub_data[ Hub_API_Properties::ARTICLE_IS_STOCK_ITEM ],
			$hub_data[ Hub_API_Properties::ARTICLE_DISPLAY_ORDER ],
			is_null( $hub_data[ Hub_API_Properties::ARTICLE_ARTICLE_TEXT_HTML ] ) ? '' : $hub_data[ Hub_API_Properties::ARTICLE_ARTICLE_TEXT_HTML ],
			$hub_data[ Hub_API_Properties::ARTICLE_DESCRIPTION ],
			$hub_data[ Hub_API_Properties::ARTICLE_GROUP_ID ],
			$hub_data[ Hub_API_Properties::ARTICLE_RETAIL_PRICE ],
			$hub_data[ Hub_API_Properties::ARTICLE_ACCOUNT_CODE_ID ] ?? '',
			$hub_data[ Hub_API_Properties::ARTICLE_BARCODE ],
			$hub_data[ Hub_API_Properties::ARTICLE_BARCODE_ALTERNATIVES ] ?? array(),
			$hub_data[ Hub_API_Properties::ARTICLE_FILES ],
			$hub_data[ Hub_API_Properties::ARTICLE_ORDER_TICKET_DIALOGUE ] ?? false,
			$order_ticket,
			$hub_data[ Hub_API_Properties::ARTICLE_ARTICLE_INFO_UPDATE_TIME ] ?? '',
			$hub_data[ Hub_API_Properties::ARTICLE_QUANTITY_UPDATED_TIME ] ?? '',
			$stored_hash,
			$wc_product,
			$article_type,
			$hub_data[ Hub_API_Properties::ARTICLE_IS_WEB_SHOP_ARTICLE ],
			$hub_data
		);
	}


	/**
	 * Get the variation name. Will cut names longer than 60 characters
	 *
	 * @param WC_Product           $wc_parent_product Variable product.
	 * @param WC_Product_Variation $variation         Product variation to get name of.
	 *
	 * @return string Variation name.
	 */
	private static function get_variation_name( WC_Product $wc_parent_product, WC_Product_Variation $variation ): string {

		$full_name = $wc_parent_product->get_name() . ' - ' . wc_get_formatted_variation( $variation, true, false );

		return mb_substr( $full_name, 0, 60 );
	}
}
