<?php
/**
 * A1-WooBay - eBay REST API Client
 *
 * @package A1_WooBay
 * @since   0.3.4
 */

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

class A1WooBay_API {

	const BASE             = 'https://api.ebay.com'; // Legacy; use get_base() internally.
	const MARKETPLACE      = 'EBAY_US';
	const CAT_TREE_ID      = '0';
	const LOCATION_KEY     = 'a1woobay-primary';

	private function get_base() {
		return A1WooBay_Auth::is_sandbox()
			? 'https://api.sandbox.ebay.com'
			: 'https://api.ebay.com';
	}

	private function get_apiz_base() {
		return A1WooBay_Auth::is_sandbox()
			? 'https://apiz.sandbox.ebay.com'
			: 'https://apiz.ebay.com';
	}

	private $auth;
	private static $instance = null;

	public static function get_instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	private function __construct() {
		$this->auth = A1WooBay_Auth::get_instance();
	}

	// -------------------------------------------------------------------------
	// Core HTTP helpers
	// -------------------------------------------------------------------------

	private function request( $method, $path, $body = null, $params = array() ) {
		$token = $this->auth->get_access_token();
		if ( ! $token ) {
			return new WP_Error( 'no_token', 'Not connected to eBay. Please reconnect in A1 Marketplace Sync with eBay for WooCommerce Settings.' );
		}

		$url = $this->get_base() . $path;
		if ( $params ) {
			$url .= '?' . http_build_query( $params );
		}

		$args = array(
			'method'  => $method,
			'headers' => array(
				'Authorization'            => 'Bearer ' . $token,
				'Content-Type'             => 'application/json',
				'Content-Language'         => 'en-US',
				'X-EBAY-C-MARKETPLACE-ID'  => self::MARKETPLACE,
				'Accept-Language'          => 'en-US',
				'Accept'                   => 'application/json',
			),
			'timeout' => 30,
		);

		if ( null !== $body ) {
			$args['body'] = wp_json_encode( $body );
		}

		$response = wp_remote_request( $url, $args );
		return $this->parse_response( $response );
	}

	private function get( $path, $params = array() ) {
		return $this->request( 'GET', $path, null, $params );
	}

	private function put( $path, $body ) {
		return $this->request( 'PUT', $path, $body );
	}

	private function post( $path, $body = array() ) {
		return $this->request( 'POST', $path, $body );
	}

	private function delete( $path ) {
		return $this->request( 'DELETE', $path );
	}

	private function parse_response( $response ) {
		if ( is_wp_error( $response ) ) {
			return $response;
		}

		$code = wp_remote_retrieve_response_code( $response );
		$raw  = wp_remote_retrieve_body( $response );
		$body = $raw ? json_decode( $raw, true ) : array();

		// 204 No Content = success with empty body
		if ( 204 === $code ) {
			return array( '_status' => 204 );
		}

		if ( $code >= 400 ) {
			$msg = 'HTTP ' . $code;
			if ( isset( $body['errors'][0]['message'] ) ) {
				$msg = $body['errors'][0]['message'];
				if ( isset( $body['errors'][0]['parameters'] ) ) {
					foreach ( $body['errors'][0]['parameters'] as $p ) {
						$msg .= ' (' . ( $p['name'] ?? '' ) . ': ' . ( $p['value'] ?? '' ) . ')';
					}
				}
			} elseif ( isset( $body['error_description'] ) ) {
				$msg = $body['error_description'];
			}
			return new WP_Error( 'ebay_api_error', $msg, array( 'status' => $code, 'body' => $body ) );
		}

		return $body ?: array( '_status' => $code );
	}

	// -------------------------------------------------------------------------
	// Taxonomy API - category search
	// -------------------------------------------------------------------------

	public function get_item_aspects_for_category( $category_id ) {
		return $this->get(
			'/commerce/taxonomy/v1/category_tree/' . self::CAT_TREE_ID . '/get_item_aspects_for_category',
			array( 'category_id' => $category_id )
		);
	}

	public function search_categories( $query ) {
		return $this->get(
			'/commerce/taxonomy/v1/category_tree/' . self::CAT_TREE_ID . '/get_category_suggestions',
			array( 'q' => $query )
		);
	}

	// -------------------------------------------------------------------------
	// Sell Account API - business policies
	// -------------------------------------------------------------------------

	public function get_fulfillment_policies() {
		return $this->get( '/sell/account/v1/fulfillment_policy', array( 'marketplace_id' => self::MARKETPLACE ) );
	}

	public function get_return_policies() {
		return $this->get( '/sell/account/v1/return_policy', array( 'marketplace_id' => self::MARKETPLACE ) );
	}

	public function get_payment_policies() {
		return $this->get( '/sell/account/v1/payment_policy', array( 'marketplace_id' => self::MARKETPLACE ) );
	}

	// -------------------------------------------------------------------------
	// Sell Inventory API - Merchant Location
	// -------------------------------------------------------------------------

	public function get_merchant_location( $key ) {
		return $this->get( '/sell/inventory/v1/location/' . rawurlencode( $key ) );
	}

	public function create_merchant_location( $key, $city, $state, $postal, $country = 'US' ) {
		$body = array(
			'location'              => array(
				'address' => array(
					'city'            => $city,
					'stateOrProvince' => $state,
					'postalCode'      => $postal,
					'country'         => $country,
				),
			),
			'locationInstructions'  => 'Ships from here',
			'name'                  => 'Primary Ship-From Location',
			'merchantLocationStatus' => 'ENABLED',
			'locationTypes'         => array( 'WAREHOUSE' ),
		);
		return $this->post( '/sell/inventory/v1/location/' . rawurlencode( $key ), $body );
	}

	public function ensure_merchant_location( $location_text, $postal, $country = 'US' ) {
		$city  = $location_text;
		$state = '';
		if ( strpos( $location_text, ',' ) !== false ) {
			$parts = array_map( 'trim', explode( ',', $location_text, 2 ) );
			$city  = $parts[0];
			$state = $parts[1];
		}

		if ( ! $city || ! $postal ) {
			return new WP_Error( 'no_location', 'Profile is missing Item Location or Postal Code. Edit the profile and fill in the Location section.' );
		}

		$existing = $this->get_merchant_location( self::LOCATION_KEY );
		if ( ! is_wp_error( $existing ) ) {
			return true;
		}

		$result = $this->create_merchant_location( self::LOCATION_KEY, $city, $state, $postal, $country );
		if ( is_wp_error( $result ) ) {
			return new WP_Error( 'location_create_failed', 'Could not create ship-from location: ' . $result->get_error_message() );
		}

		return true;
	}

	// -------------------------------------------------------------------------
	// Sell Inventory API - Inventory Items
	// -------------------------------------------------------------------------

	public function create_or_update_inventory_item( $sku, $data ) {
		return $this->put( '/sell/inventory/v1/inventory_item/' . rawurlencode( $sku ), $data );
	}

	/**
	 * Get all inventory items from eBay.
	 * Returns array with 'inventoryItems' key, or WP_Error.
	 */
	public function get_inventory_item( $sku ) {
		return $this->get( '/sell/inventory/v1/inventory_item/' . rawurlencode( $sku ), array() );
	}

	public function get_inventory_items( $limit = 200, $offset = 0 ) {
		return $this->get( '/sell/inventory/v1/inventory_item', array(
			'limit'  => $limit,
			'offset' => $offset,
		) );
	}

	// -------------------------------------------------------------------------
	// Sell Inventory API - Offers
	// -------------------------------------------------------------------------

	public function get_offers_by_sku( $sku ) {
		return $this->get( '/sell/inventory/v1/offer', array( 'sku' => $sku ) );
	}

	public function create_offer( $data ) {
		return $this->post( '/sell/inventory/v1/offer', $data );
	}

	public function update_offer( $offer_id, $data ) {
		return $this->put( '/sell/inventory/v1/offer/' . rawurlencode( $offer_id ), $data );
	}

	public function publish_offer( $offer_id ) {
		return $this->post( '/sell/inventory/v1/offer/' . rawurlencode( $offer_id ) . '/publish', array() );
	}

	public function withdraw_offer( $offer_id ) {
		return $this->post( '/sell/inventory/v1/offer/' . rawurlencode( $offer_id ) . '/withdraw', array() );
	}

	public function create_or_update_offer( $sku, $offer_data ) {
		$existing = $this->get_offers_by_sku( $sku );

		if ( ! is_wp_error( $existing ) && ! empty( $existing['offers'] ) ) {
			$offer_id = $existing['offers'][0]['offerId'];
			$result   = $this->update_offer( $offer_id, $offer_data );
			if ( is_wp_error( $result ) ) {
				return $result;
			}
			return array( 'offerId' => $offer_id, 'action' => 'updated' );
		}

		$result = $this->create_offer( $offer_data );
		if ( is_wp_error( $result ) ) {
			return $result;
		}
		return array( 'offerId' => $result['offerId'], 'action' => 'created' );
	}
	public function get_offer( $offer_id ) {
		return $this->get( '/sell/inventory/v1/offer/' . rawurlencode( $offer_id ) );
	}

	public function get_item_watch_count( $item_id ) {
		$token = $this->auth->get_access_token();
		if ( ! $token ) {
			return new WP_Error( 'no_token', 'Not connected to eBay.' );
		}

		// Trading API GetItem - returns WatchCount reliably using seller user token.
		$xml = '<?xml version="1.0" encoding="utf-8"?>' .
			'<GetItemRequest xmlns="urn:ebay:apis:eBLBaseComponents">' .
			'<RequesterCredentials><eBayAuthToken>' . esc_attr( $token ) . '</eBayAuthToken></RequesterCredentials>' .
			'<ItemID>' . esc_attr( $item_id ) . '</ItemID>' .
			'<IncludeWatchCount>true</IncludeWatchCount>' .
			'<DetailLevel>ReturnAll</DetailLevel>' .
			'</GetItemRequest>';

		$response = wp_remote_post(
			$this->get_base() . '/ws/api.dll',
			array(
				'headers' => array(
					'X-EBAY-API-COMPATIBILITY-LEVEL' => '967',
					'X-EBAY-API-CALL-NAME'           => 'GetItem',
					'X-EBAY-API-SITEID'              => '0',
					'Content-Type'                   => 'text/xml',
				),
				'body'    => $xml,
				'timeout' => 20,
			)
		);

		if ( is_wp_error( $response ) ) return $response;

		$body = wp_remote_retrieve_body( $response );
		if ( preg_match( '/<WatchCount>(\d+)<\/WatchCount>/', $body, $m ) ) {
			return (int) $m[1];
		}

		return new WP_Error( 'no_watch_count', 'WatchCount not in Trading API response.' );
	}


	// -------------------------------------------------------------------------
	// Sell Fulfillment API - Orders
	// -------------------------------------------------------------------------

	/**
	 * List eBay orders.
	 *
	 * @param array $params  Optional filters: filter, limit, offset, orderIds.
	 */
	public function get_orders( $params = array() ) {
		return $this->get( '/sell/fulfillment/v1/order', $params );
	}

	/**
	 * Get a single eBay order by order ID.
	 */
	public function get_order( $order_id ) {
		return $this->get( '/sell/fulfillment/v1/order/' . rawurlencode( $order_id ) );
	}

	public function create_shipping_fulfillment( $order_id, $data ) {
		return $this->post( '/sell/fulfillment/v1/order/' . rawurlencode( $order_id ) . '/shipping_fulfillment', $data );
	}

	// -------------------------------------------------------------------------
	// Sell Finances API
	// -------------------------------------------------------------------------

	public function get_order_transactions( $order_id ) {
		$token = $this->auth->get_access_token();
		if ( ! $token ) {
			return new WP_Error( 'no_token', 'Not connected to eBay.' );
		}
		// Finances API uses apiz.ebay.com (not api.ebay.com).
		// Build URL manually: eBay filter syntax requires unencoded { } braces.
		// http_build_query() would encode them as %7B%7D, breaking the filter.
		$url  = $this->get_apiz_base() . '/sell/finances/v1/transaction'
			. '?filter=orderId:{' . rawurlencode( $order_id ) . '}&limit=200';
		$args = array(
			'method'  => 'GET',
			'headers' => array(
				'Authorization'           => 'Bearer ' . $token,
				'Content-Type'            => 'application/json',
				'X-EBAY-C-MARKETPLACE-ID' => self::MARKETPLACE,
				'Accept'                  => 'application/json',
			),
			'timeout' => 30,
		);
		$response = wp_remote_request( $url, $args );
		return $this->parse_response( $response );
	}

	public function calculate_order_fees( $order_id ) {
		$response = $this->get_order_transactions( $order_id );
		if ( is_wp_error( $response ) ) {
			return 0.0;
		}
		$transactions = $response['transactions'] ?? array();
		$total_fees   = 0.0;
		$skip_types   = array( 'SALE', 'REFUND', 'CREDIT', 'DISPUTE' );
		foreach ( $transactions as $txn ) {
			$type   = $txn['transactionType'] ?? '';
			$amount = (float) ( $txn['amount']['value'] ?? 0 );
			if ( in_array( $type, $skip_types, true ) ) {
				continue;
			}
			$total_fees += abs( $amount );
		}
		return round( $total_fees, 2 );
	}

}
