<?php
/**
 * Contains API calls available for both main and stock accounts.
 *
 * @package northmill-online-shared
 *
 * @noinspection PhpUnused Unused are for external.
 */

declare(strict_types=1);

namespace Northmill_Online_Shared\Abstracts\Hub_API;

use Northmill_Online_Shared\Abstracts\Hub_API\Hub_Accounts\Models\Hub_Account_Model;
use Northmill_Online_Shared\Abstracts\Hub_API\Models\Receipts\Receipt_Model;

defined( 'ABSPATH' ) || exit;

/**
 * Class API
 */
class API extends Abstract_API_Base {

	/**
	 * Construct the API object.
	 *
	 * @param Hub_Account_Model $account The account to use.
	 */
	public function __construct( protected Hub_Account_Model $account ) {
		parent::__construct(
			$account->url,
			$account->user,
			$account->pass
		);
	}

	public const ARTICLES_ENDPOINT = 'articles';

	/**
	 * Get store settings from API.
	 *
	 * @return object|null
	 */
	public function get_store_settings(): ?object {
		return $this->request_object( 'GET', 'settings' );
	}

	/**
	 * Get bookkeeping account codes.
	 *
	 * @param array $args Query parameters.
	 *
	 * @return object|null Decoded JSON object of account codes, or null if request failed.
	 */
	public function get_account_codes( array $args ): ?object {
		return $this->request_object( 'GET', 'accountcodes', $args );
	}

	/**
	 * Get VAT accounts.
	 *
	 * @param array $args Query parameters.
	 *
	 * @return array|null    Decoded JSON array of VAT accounts, or null if request failed.
	 */
	public function get_vat_accounts( array $args ): ?array {
		return $this->request_array( 'GET', 'settings/accounting/vat', $args );
	}

	/**
	 * Get income account codes.
	 *
	 * @param array $args Query parameters.
	 *
	 * @return array|null    Decoded JSON array of income account codes, or null if request failed.
	 */
	public function get_income_account_codes( array $args ): ?object {
		return $this->request_object( 'GET', 'settings/accounting/income', $args );
	}

	/**
	 * Get other account codes.
	 *
	 * @param array $args Query parameters.
	 *
	 * @return array|null    Decoded JSON array of income account codes, or null if request failed.
	 */
	public function get_other_account_codes( array $args ): ?object {
		return $this->request_object( 'GET', 'settings/accounting/other', $args );
	}

	/**
	 * Get article.
	 *
	 * @param string $article_no Article number.
	 *
	 * @return array|null Decoded JSON object of article, or null if request failed.
	 */
	public function get_article( string $article_no ): ?array {
		$article_data = $this->request_array( 'GET', self::ARTICLES_ENDPOINT . '/' . $article_no );

		return $article_data['Article'] ?? null;
	}


	/**
	 * Get article property from API.
	 *
	 * @param string $sku      The article SKU.
	 * @param string $property The article property.
	 *
	 * @return mixed|null The article property value, or null if not found.
	 */
	public function get_article_property( string $sku, string $property ): mixed {

		$article = $this->get_article( $sku );

		if ( ! empty( $article ) && isset( $article[ $property ] ) ) {
			return $article[ $property ];
		}

		return null;
	}

	/**
	 * Get articles from API.
	 *
	 * @param array $args API request parameters.
	 *
	 * @return array|null Decoded JSON object of articles, or null if request failed.
	 */
	public function get_articles( array $args ): ?array {
		return $this->request_array( 'GET', self::ARTICLES_ENDPOINT, $args );
	}

	/**
	 * Get article availabilities from API.
	 *
	 * @param array $args API request parameters.
	 *
	 * @return array|null Decoded JSON object, or null if request failed.
	 */
	public function get_article_availabilities( array $args ): ?array {
		return $this->request_array( 'GET', 'articles-availabilities', $args, 'v3' );
	}

	/**
	 * Get orders.
	 *
	 * @param null|array $params API parameters.
	 *
	 * @return array|null
	 */
	public function get_orders( ?array $params ): ?array {
		return $this->request_array( 'GET', 'orders', $params, 'v3' );
	}

	/**
	 * Post order to API.
	 *
	 * @param array $order Order data.
	 *
	 * @return object|null JSON encoded api response, or null if failed.
	 */
	public function post_order( array $order ): ?object {
		$body = wp_json_encode( array( $order ) );

		return $this->request_object( 'POST', 'orders', $body, 'v3' );
	}

	/**
	 * Get customer from API
	 *
	 * @param array $params Query parameters.
	 *
	 * @return array|null Decoded JSON array of customers, or null if request failed.
	 */
	public function get_customer( array $params ): ?array {
		// Search type can be one of the following: 'AllFields', 'CustomerNumber', 'Name', 'IdentityNumber', 'Email', 'Mobile'.
		$params = array_merge(
			array(
				'SearchPhrase'         => '',
				'SearchType'           => 'AllFields',
				'PageSize'             => 0,
				'ExactMatch'           => true,
				'OnlyInternalCustomer' => false,
				'OnlyExternalCustomer' => false,
			),
			$params,
		);

		$body = wp_json_encode( $params );
		$body = $body ? $body : '';

		$response = $this->request( 'POST', 'customers/find', $body );

		if ( $response ) {
			$data = json_decode( $response, true );

			if ( is_array( $data ) ) {
				return $data;
			}
		}

		return null;
	}

	/**
	 * Create receipt in API.
	 *
	 * @param Receipt_Model $receipt Receipt data.
	 *
	 * @return false|string JSON encoded api response, or false if failed.
	 */
	public function post_receipt( Receipt_Model $receipt ): false|string {
		$body = wp_json_encode( $receipt );
		$body = $body ? $body : '';

		return $this->request( 'POST', 'receipts', $body );
	}

	/**
	 * Retrieves booking resources from the API.
	 *
	 * @param array $request_args Arguments to include in the request.
	 *
	 * @return object|null Response from API, or WP_Error on error.
	 */
	public function get_booking_resources( array $request_args ): ?object {
		return $this->request_object(
			'GET',
			'bookings/resources',
			$request_args
		);
	}

	/**
	 * Get booking orders from API.
	 *
	 * @param array $request_args Arguments to send to API.
	 *
	 * @return object|null Response from API, or WP_Error on error.
	 */
	public function get_booking_orders( array $request_args ): ?object {
		return $this->request_object(
			'GET',
			'bookingorders',
			$request_args
		);
	}

	/**
	 * Retrieve service orders from the API.
	 *
	 * @param array $request_args Arguments to include in the API request.
	 *
	 * @return object|null Response from the API, or WP_Error on failure.
	 */
	public function get_service_orders( array $request_args ): ?object {
		return $this->request_object(
			'GET',
			'serviceorders',
			$request_args
		);
	}

	/**
	 * Retrieves the booking resource event instances based on the specified request arguments.
	 *
	 * @param array $request_args The arguments to be passed with the request.
	 *
	 * @return object|null The response object containing the requested resource event instances.
	 */
	public function get_booking_resource_event_instances( array $request_args ): ?object {
		return $this->request_object(
			'GET',
			'bookings/resourceeventinsances',
			$request_args
		);
	}

	/**
	 * Retrieve booking settings from API.
	 *
	 * @return object|null Response from API, or WP_Error on error.
	 */
	public function get_booking_settings(): ?object {
		return $this->request_object(
			'GET',
			'bookings/settings'
		);
	}

	/**
	 * Send booking order to API.
	 *
	 * @param string $method      HTTP method to use for the request (e.g., 'POST').
	 * @param array  $body_params Parameters to send to API.
	 *
	 * @return object|null Response from API, or WP_Error on error.
	 */
	public function send_booking_order( string $method, array $body_params ): ?object {
		$body = wp_json_encode( $body_params );
		$body = $body ? $body : '';

		return $this->request_object(
			$method,
			'bookingorders',
			$body
		);
	}

	/**
	 * Send service order to the API.
	 *
	 * @param string $method      HTTP method to use for the request.
	 * @param array  $body_params Parameters to send to the API.
	 *
	 * @return object|null Response from the API, or WP_Error on error.
	 */
	public function send_service_order( string $method, array $body_params ): ?object {
		$body = wp_json_encode( $body_params );
		$body = $body ? $body : '';

		return $this->request_object(
			$method,
			'serviceorders',
			$body
		);
	}
}
