<?php
/**
 * Main code for account code sync.
 *
 * @package northmill-online-shared
 */

declare(strict_types=1);

namespace Northmill_Online_Shared\Modules\Sync\Bookkeeping\Article_Account_Codes;

use Northmill_Online_Shared\Abstracts\Hub_API\Hub_Accounts\Models\Article_Account_Code_Model;
use Northmill_Online_Shared\Abstracts\Hub_API\Hub_Accounts\Models\Hub_Account_Model;
use Northmill_Online_Shared\Abstracts\Hub_API\Hub_Accounts\WP_Repository;
use Northmill_Online_Shared\Abstracts\Hub_API\Models\Hub_API_Properties;
use Northmill_Online_Shared\Helpers\DB_Helpers;
use WC_Product;

defined( 'ABSPATH' ) || exit;

/**
 * Class for Account code sync.
 */
class Article_Account_Codes {

	public const WC_TAX_CLASS_NAME_PREFIX = 'Northmill ';

	/**
	 * All account codes.
	 *
	 * @var Article_Account_Code_Model[]
	 */
	private static array $article_account_codes;

	/**
	 * Get the tax class slug prefix.
	 *
	 * @return string
	 */
	public static function get_tax_class_slug_prefix(): string {
		static $tax_class_slug_prefix = null;
		if ( is_null( $tax_class_slug_prefix ) ) {
			$tax_class_slug_prefix = sanitize_title( self::WC_TAX_CLASS_NAME_PREFIX );
		}

		return $tax_class_slug_prefix;
	}

	/**
	 * Get all account codes.
	 *
	 * @return Article_Account_Code_Model[]
	 *
	 * @used Northmill Sync
	 */
	public static function get_all(): array {
		if ( ! isset( self::$article_account_codes ) ) {
			self::$article_account_codes = WP_Repository::get_current_main_account()->get_article_account_codes();
		}
		return self::$article_account_codes;
	}

	/**
	 * Get account code model by ID.
	 *
	 * @param string $hub_id Account code Hub ID.
	 *
	 * @return Article_Account_Code_Model|null
	 *
	 * @used Northmill Sync.
	 */
	public static function get_model_by_id( string $hub_id ): ?Article_Account_Code_Model {
		$account_codes = self::get_all();

		foreach ( $account_codes as $account_code ) {
			if ( $account_code->get_id() === $hub_id ) {
				return $account_code;
			}
		}

		return null;
	}

	/**
	 * Get account code slug by Hub ID.
	 *
	 * @param string $id Account code Hub ID.
	 *
	 * @return string
	 *
	 * @used Northmill Sync.
	 */
	public static function get_slug_by_id( string $id ): string {
		$account_code = self::get_model_by_id( $id );
		return ! empty( $account_code ) ? $account_code->get_slug() : '';
	}

	/**
	 * Get VAT rate by Hub ID.
	 *
	 * @param string $id Account code Hub ID.
	 *
	 * @return float|null
	 *
	 * @used Northmill Sync.
	 */
	public static function get_vat_rate_by_id( string $id ): float|null {
		$account_code = self::get_model_by_id( $id );
		return ! empty( $account_code ) ? $account_code->get_vat_rate() : null;
	}

	/**
	 * Get account Hub ID by slug.
	 *
	 * @param string $slug Account WC slug.
	 *
	 * @return string
	 *
	 * @used Northmill Sync.
	 */
	public static function get_id_by_slug( string $slug ): string {
		$account_codes = self::get_all();

		foreach ( $account_codes as $account_code ) {
			if ( $account_code->get_slug() === $slug ) {
				return $account_code->get_id();
			}
		}

		return '';
	}

	/**
	 * Get account codes, mainly to use in select input.
	 *
	 * @param bool $include_empty_option Whether to include an empty option with select text.
	 *
	 * @used Northmill Sync
	 *
	 * @return array
	 */
	public static function get_select_options( bool $include_empty_option = true ): array {
		$return                = array();
		$article_account_codes = self::get_all();

		if ( $include_empty_option ) {
			$return['0'] = __( 'Please select an account code.', 'northmill-online-shared' );
		}

		if ( empty( $article_account_codes ) ) {
			return $return;
		}

		foreach ( $article_account_codes as $article_account_code ) {
			if (
				! empty( $article_account_code->get_id() ) &&
				! empty( $article_account_code->get_name() )
			) {
				$return[ $article_account_code->get_id() ] = $article_account_code->get_name();
			}
		}

		return $return;
	}

	/**
	 * Get bookkeeping article account number in Hub from a product.
	 *
	 * @param WC_Product        $product       Product to get account code for.
	 * @param Hub_Account_Model $backoffice_account Hub account to get account code from.
	 *
	 * @return int|false The account code, false if not found.
	 */
	public static function get_article_account_code_by_product(
		WC_Product $product,
		Hub_Account_Model $backoffice_account
	): false|int {
		$account_codes = $backoffice_account->get_article_account_codes();

		if ( empty( $account_codes ) ) {
			return false;
		}

		if ( is_a( $product, 'WC_Product_Variation' ) ) {
			$product_sku = wc_get_product( $product->get_parent_id() )->get_sku();
		} else {
			$product_sku = $product->get_sku();
		}

		$product_account_code_id = $backoffice_account->api->get_article_property(
			$product_sku,
			Hub_API_Properties::ARTICLE_ACCOUNT_CODE_ID
		);

		if ( ! $product_account_code_id ) {
			return false;
		}

		foreach ( $account_codes as $account_code ) {
			if ( $account_code->get_id() !== $product_account_code_id ) {
				continue;
			}

			return $account_code->get_account_code();
		}

		return false;
	}

	/**
	 * Truncate tax rates table.
	 *
	 * @return bool
	 */
	public static function truncate_tax_rates_table(): bool {
		return DB_Helpers::truncate_table( 'woocommerce_tax_rates' );
	}

	/**
	 * Delete tax rates by slug prefix.
	 *
	 * @param null|string $prefix Tax rates with a slug prefixed with this will be deleted. Null means the default prefix.
	 *
	 * @return bool|int
	 *
	 * @used Northmill Sync
	 */
	public static function remove_prefixed_tax_rates( ?string $prefix = null ): bool|int {
		global $wpdb;

		if ( empty( $prefix ) ) {
			$prefix = self::get_tax_class_slug_prefix();
		}

		$table = $wpdb->prefix . 'woocommerce_tax_rates';

		return $wpdb->query(
			// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $table is safe.
			$wpdb->prepare( "DELETE FROM $table WHERE tax_rate_class LIKE %s", $prefix . '%' )
		);
	}

	/**
	 * Delete tax rates by slug prefix.
	 *
	 * @param null|string $prefix Tax rates with a slug prefixed with this will be deleted. Null means the default prefix.
	 *
	 * @return bool|int
	 *
	 * @used Northmill Sync
	 */
	public static function remove_prefixed_tax_classes( ?string $prefix = null ): bool|int {
		global $wpdb;

		if ( empty( $prefix ) ) {
			$prefix = self::get_tax_class_slug_prefix();
		}

		$table = $wpdb->prefix . 'wc_tax_rate_classes';

		return $wpdb->query(
			// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $table is safe.
			$wpdb->prepare( "DELETE FROM $table WHERE slug LIKE %s", $prefix . '%' )
		);
	}
}
