<?php

namespace CommerceBird\Admin\Connectors;

use CommerceBird\Admin\Actions\Ajax\SettingsAjax;
use CommerceBird\Admin\Traits\LogWriter;
use WP_Error;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Connector class for interacting with the CommerceBird API and Exact Online.
 *
 * Provides methods for retrieving and saving data such as subscriptions, account settings,
 * products, orders, and webhooks, as well as handling API requests and logging.
 */
final class Connector {
	use LogWriter;

	const COST_CENTERS                 = 'customs/exact/cost-centers';
	const COST_UNITS                   = 'customs/exact/cost-units';
	const GL_ACCOUNTS                  = 'customs/exact/gl-accounts';
	const INVOICE_LAYOUTS              = 'customs/exact/invoice-layouts';
	const JOURNAL_LIST                 = 'customs/exact/journal';
	const EXACT_WAREHOUSES             = 'customs/exact/warehouses';
	const EXACT_GENERAL_SETTINGS       = 'customs/exact/gen-settings';
	const ITEM                         = 'customs/exact/bulk-items';
	const CUSTOMER                     = 'customs/exact/bulk-customers';
	const ORDER                        = 'customs/exact/bulk-orders';
	const PAYMENT_STATUS               = 'customs/exact/invoice-payment-status';
	const WEBHOOKS                     = 'customs/exact/webhooks';
	const WOO_WEBHOOKS                 = 'customs/woo/webhooks';
	const CONNECT_EXACT                = 'webapp/exact/auth-url/plugin';
	const EXACT_DIVISIONS              = 'webapp/exact/divisions/plugin';
	const ACCOUNT_SETTINGS             = 'customs/settings';
	const SUBSCRIPTION                 = 'customs/subscriptions';
	const EXACT_TAXMAPPING             = 'customs/exact/settings/taxes';
	const EXACT_VATCODES               = 'customs/exact/settings/vat-codes';
	const EXACT_PAYMENT_CONDITIONS     = 'customs/exact/settings/payment-conditions';
	const EXACT_PAYMENT_STATUS_MAPPING = 'customs/exact/settings/payment-status';
	const EXACT_RESET_CONNECTION       = 'webapp/exact/disconnect/plugin';
	const API                          = 'https://api.commercebird.com';
	// const API = 'https://6c09a9134e1f.ngrok-free.app';

	/**
	 * Get Subscription data from CommerceBird API.
	 *
	 * @param integer $subscription_id
	 * @param string  $store_token
	 * @return array|WP_Error
	 */
	public function get_subscription( $data ) {
		$response = $this->request(
			self::SUBSCRIPTION,
			'POST',
			$data
		);
		if ( is_wp_error( $response ) ) {
			$this->write_log( $response->get_error_message(), 'commercebird-connector' );
			return new WP_Error( 'request_failed', $response->get_error_message() );
		}
		if ( isset( $response['code'] ) && 200 !== $response['code'] ) {
			$this->write_log( $response['message'], 'commercebird-connector' );
			return new WP_Error( 'request_failed', $response['message'] );
		}
		return $response['data'];
	}

	/**
	 * Connect to exact online and get authorization URL.
	 *
	 * @param array $data array ( callback_url, topic )
	 * @return array|WP_Error array ( webhook_id, topic )
	 */
	public function create_woo_webbhook() {
		return $this->request( self::WOO_WEBHOOKS, 'POST' );
	}

	/**
	 * Connect to exact online and get authorization URL.
	 *
	 * @param array $data array ( callback_url, topic )
	 * @return array|WP_Error array ( webhook_id, topic )
	 */
	public function connect_exact( $domain_suffix ) {
		return $this->request( self::CONNECT_EXACT, 'GET', array(), array( 'domain' => $domain_suffix ) );
	}

	public function get_account_settings() {
		return $this->request( self::ACCOUNT_SETTINGS );
	}
	public function save_account_settings( array $data ) {
		return $this->request( self::ACCOUNT_SETTINGS, 'POST', $data );
	}

	public function get_exact_divisions() {
		return $this->request( self::EXACT_DIVISIONS );
	}

	public function cost_centers() {
		return $this->request( self::COST_CENTERS );
	}

	public function gl_accounts() {
		return $this->request( self::GL_ACCOUNTS );
	}

	/**
	 * Get the list of journals from Exact Online.
	 *
	 * @return array|WP_Error
	 */
	public function journals() {
		return $this->request( self::JOURNAL_LIST );
	}

	/**
	 * Get the list of invoice layouts from Exact Online.
	 *
	 * @return array|WP_Error
	 */
	public function invoice_layouts() {
		return $this->request( self::INVOICE_LAYOUTS );
	}

	/**
	 * Get the list warehouses from Exact Online.
	 *
	 * @return array|WP_Error
	 */
	public function exact_warehouses() {
		return $this->request( self::EXACT_WAREHOUSES );
	}

	/**
	 * Get mapped general settings for Exact Online.
	 *
	 * @return array|WP_Error
	 */
	public function exact_general_settings() {
		return $this->request( self::EXACT_GENERAL_SETTINGS );
	}

	/**
	 * Save general settings for Exact Online.
	 *
	 * @param array $data mapped general settings data
	 * @return array|WP_Error
	 */
	public function save_exact_general_settings( array $data ) {
		return $this->request( self::EXACT_GENERAL_SETTINGS, 'POST', $data );
	}

	/**
	 * Get exact vat codes.
	 *
	 * @return array|WP_Error
	 */
	public function get_exact_vat_codes() {
		return $this->request( self::EXACT_VATCODES );
	}

	/**
	 * Get mapped taxes for Exact Online.
	 *
	 * @return array|WP_Error
	 */
	public function get_exact_tax_mapping() {
		return $this->request( self::EXACT_TAXMAPPING );
	}

	/**
	 * Save mapped taxes for Exact Online.
	 *
	 * @param array $data mapped taxes data
	 * @return array|WP_Error
	 */
	public function save_exact_tax_mapping( array $data ) {
		return $this->request( self::EXACT_TAXMAPPING, 'POST', $data );
	}

	/**
	 * Get mapped payment conditions for Exact Online.
	 *
	 * @return array|WP_Error
	 */
	public function get_exact_payment_conditions() {
		return $this->request( self::EXACT_PAYMENT_CONDITIONS );
	}

	/**
	 * Get mapped payment staus for Exact Online.
	 *
	 * @return array|WP_Error
	 */
	public function get_exact_payment_status_mapping() {
		return $this->request( self::EXACT_PAYMENT_STATUS_MAPPING );
	}

	/**
	 * Save mapped payment status for Exact Online.
	 *
	 * @param array $data mapped taxes data
	 * @return array|WP_Error
	 */
	public function save_exact_payment_status_mapping( array $data ) {
		return $this->request( self::EXACT_PAYMENT_STATUS_MAPPING, 'POST', $data );
	}

	/**
	 * Suscribe to Exact Online Webhooks. Pass the webhook URL to Exact Online and Topic
	 *
	 * @param array $data array ( callback_url, topic )
	 * @return array|WP_Error array ( webhook_id, topic )
	 */
	public function subscribe_exact_webhooks( array $data ) {
		$response = $this->request( self::WEBHOOKS, 'POST', $data );
		return $response['code'] === 200 ? $response['data'] : $response['message'];
	}

	/**
	 * Collect customer or account id
	 *
	 * @param array $customer array ( customer_email, company_name )
	 *
	 * @return array|WP_Error array ( account_id, company_id )
	 * @throws WP_Error Invalid customer if empty
	 */
	public function customer( bool $reset_sync = false ): array|string {
		$params   = $reset_sync ? array( 'reset_sync' => 'true' ) : array();
		$response = $this->request( self::CUSTOMER, 'GET', array(), $params );
		if ( $response['code'] === 200 ) {
			return $response['data'];
		}
		if ( $response['code'] === 404 ) {
			return array( 'customers' => array() );
		}
		return $response['message'];
	}
	/**
	 * Collect customer or account id
	 *
	 * @param array $customer array ( customer_email, company_name )
	 *
	 * @return array|WP_Error array ( account_id, company_id )
	 * @throws WP_Error Invalid customer if empty
	 */
	public function order( bool $reset_sync = false ): array|string {
		$params   = $reset_sync ? array( 'reset_sync' => 'true' ) : array();
		$response = $this->request( self::ORDER, 'GET', array(), $params );
		if ( $response['code'] === 200 ) {
			return $response['data'];
		}
		if ( $response['code'] === 404 ) {
			return array( 'orders' => array() );
		}
		return $response['message'];
	}

	/**
	 * Send Order Ids to Exact Online using the bulk endpoint
	 *
	 * @param array $data array ( order_ids )
	 * @return array|WP_Error array ( order_ids )
	 * @throws WP_Error Invalid order if empty
	 */
	public function send_orders( array $data ) {
		$response = $this->request( self::ORDER, 'POST', $data );
		return $response['code'] === 200 ? $response['data'] : $response['message'];
	}

	/**
	 * Get item ID by product ID
	 *
	 * @param int $id of the item
	 *
	 * @return array|WP_Error The ID of the item or an error object.
	 */
	public function products( bool $reset_sync = false ): array|string {
		$params   = $reset_sync ? array( 'reset_sync' => 'true' ) : array();
		$response = $this->request( self::ITEM, 'GET', array(), $params );
		if ( $response['code'] === 200 ) {
			return $response['data'];
		}
		if ( $response['code'] === 404 ) {
			return array( 'items' => array() );
		}
		return $response['message'];
	}

	public function cost_units() {
		return $this->request( self::COST_UNITS );
	}

	/**
	 * Get payment status
	 *
	 * @param array
	 *
	 * @return array|WP_Error array ( payment_status )
	 */
	public function payment_status( array $data ) {
		$response = $this->request( self::PAYMENT_STATUS, 'POST', $data, array() );
		return $response['code'] === 200 ? $response['data'] : $response['message'];
	}

	/**
	 * Disconnect Exact Online Connection via DELETE call
	 *
	 * @return array|WP_Error
	 */
	public function reset_exact_connection() {
		$response = $this->request( self::EXACT_RESET_CONNECTION, 'DELETE', array() );
		return $response;
	}

	/**
	 * Generate request URL
	 *
	 * @param string $endpoint Endpoint for the API request.
	 * @param string $method HTTP method (GET, POST, DELETE).
	 * @param array  $data Data to be sent in the request body.
	 * @param array  $params Query parameters to be appended to the URL.
	 * @return array|WP_Error
	 */
	public function request( string $endpoint, string $method = 'GET', array $data = array(), array $params = array() ) {
		// $token = ExactOnlineAjax::instance()->get_token();
		$token = SettingsAjax::instance()->get_token();

		$token = ! empty( $token ) ? $token : '';
		$url   = sprintf( '%s/%s?token=%s', self::API, $endpoint, $token );
		if ( ! empty( $params ) ) {
			$url .= '&' . http_build_query( $params );
		}

		// if current site contains localhost, use https://dev.commercebird.com.
		$current_site_url = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_url( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : '';
		$site_url         = empty( $current_site_url ) || str_contains( $current_site_url, 'localhost' ) ? 'https://dev.commercebird.com' : site_url();
		if ( 'POST' === $method ) {
			$response = wp_remote_post(
				$url,
				array(
					'headers'   => array(
						'Accept'       => 'application/json',
						'Content-Type' => 'application/json',
						'zohowooagent' => $site_url,
					),
					'timeout'   => 60,
					'sslverify' => false,
					'body'      => wp_json_encode( $data ),
				)
			);
		} elseif ( 'GET' === $method ) {
			$response = wp_remote_get(
				$url,
				array(
					'headers'   => array(
						'Accept'         => 'application/json',
						'zohowooagent'   => $site_url,
						'x-woozo-module' => $data['module'] ?? '',
					),
					'timeout'   => 60,
					'sslverify' => false,
				)
			);
		} elseif ( 'DELETE' === $method ) {
			$response = wp_remote_request(
				$url,
				array(
					'method'    => 'DELETE',
					'headers'   => array(
						'Accept'       => 'application/json',
						'Content-Type' => 'application/json',
						'zohowooagent' => $site_url,
					),
					'timeout'   => 60,
					'sslverify' => false,
				)
			);
		} else {
			return new WP_Error( 'invalid_method', 'Invalid HTTP method specified.' );
		}

		if ( is_wp_error( $response ) ) {
			$this->write_log( $response->get_error_message(), 'commercebird-connector' );
			return new WP_Error( 'request_failed', $response->get_error_message() );
		}
		$response = wp_remote_retrieve_body( $response );
		return json_decode( $response, true );
	}
}
