<?php
/**
 * Google Merchant Center API integration.
 *
 * @package InformatiqSmartPricing
 */

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Google API class.
 */
class Informatiq_SP_Google_API {
	/**
	 * Google Client instance.
	 *
	 * @var Google_Client
	 */
	private $client;

	/**
	 * Google Shopping Content service.
	 *
	 * @var Google_Service_ShoppingContent
	 */
	private $service;

	/**
	 * Merchant ID.
	 *
	 * @var string
	 */
	private $merchant_id;

	/**
	 * Logger instance.
	 *
	 * @var Informatiq_SP_Logger
	 */
	private $logger;

	/**
	 * Constructor.
	 *
	 * @param string               $merchant_id      Google Merchant ID.
	 * @param string               $service_account  Service account JSON.
	 * @param Informatiq_SP_Logger $logger           Logger instance.
	 * @throws Exception If authentication fails.
	 */
	public function __construct( $merchant_id, $service_account, $logger ) {
		$this->merchant_id = $merchant_id;
		$this->logger      = $logger;

		try {
			$this->authenticate( $service_account );
		} catch ( Exception $e ) {
			$this->logger->error( 'Google API authentication failed: ' . $e->getMessage() );
			throw $e;
		}
	}

	/**
	 * Authenticate with Google API.
	 *
	 * @param string $service_account Service account JSON.
	 * @throws Exception If authentication fails.
	 */
	private function authenticate( $service_account ) {
		// Decode service account JSON.
		$credentials = json_decode( $service_account, true );

		if ( json_last_error() !== JSON_ERROR_NONE ) {
			throw new Exception( 'Invalid service account JSON: ' . json_last_error_msg() );
		}

		// Initialize Google Client.
		$this->client = new Google_Client();
		$this->client->setApplicationName( 'Informatiq Smart Pricing' );
		$this->client->setScopes( array( 'https://www.googleapis.com/auth/content' ) );
		$this->client->setAuthConfig( $credentials );

		// Initialize Shopping Content service.
		$this->service = new Google_Service_ShoppingContent( $this->client );
	}

	/**
	 * Get competitive pricing for a product.
	 *
	 * @param string $sku  Product SKU.
	 * @param string $gtin Product GTIN (optional).
	 * @return float|null Lowest competitor price or null if not found.
	 */
	public function get_competitive_price( $sku, $gtin = '' ) {
		try {
			// Search for the product using SKU or GTIN.
			$product_id = $this->find_product_by_identifier( $sku, $gtin );

			if ( ! $product_id ) {
				$this->logger->warning( "Product not found in Google Merchant Center: SKU={$sku}, GTIN={$gtin}" );
				return null;
			}

			// Get competitive pricing data.
			$competitive_price = $this->fetch_competitive_price( $product_id );

			return $competitive_price;

		} catch ( Exception $e ) {
			$this->logger->error( 'Error fetching competitive price: ' . $e->getMessage() );
			return null;
		}
	}

	/**
	 * Find product by SKU or GTIN.
	 *
	 * @param string $sku  Product SKU.
	 * @param string $gtin Product GTIN.
	 * @return string|null Product ID or null if not found.
	 */
	private function find_product_by_identifier( $sku, $gtin ) {
		try {
			// List products from merchant center.
			$parameters = array();

			// Add pagination support.
			$max_results = 250;
			$parameters['maxResults'] = $max_results;

			$products = $this->service->products->listProducts( $this->merchant_id, $parameters );

			foreach ( $products->getResources() as $product ) {
				// Check if SKU or GTIN matches.
				$product_data = $product->toSimpleObject();

				if ( isset( $product_data->offerId ) && $product_data->offerId === $sku ) {
					return $product->getId();
				}

				if ( ! empty( $gtin ) && isset( $product_data->gtin ) && $product_data->gtin === $gtin ) {
					return $product->getId();
				}
			}

			return null;

		} catch ( Exception $e ) {
			$this->logger->error( 'Error finding product: ' . $e->getMessage() );
			return null;
		}
	}

	/**
	 * Fetch competitive price for a product.
	 *
	 * @param string $product_id Product ID.
	 * @return float|null Lowest competitor price or null if not available.
	 */
	private function fetch_competitive_price( $product_id ) {
		try {
			// Get product status which includes competitive pricing data.
			$product_status = $this->service->productstatuses->get( $this->merchant_id, $product_id );

			// Extract competitive pricing data.
			$price_insights = $product_status->getItemLevelIssues();

			// Try to get the product to access price competitiveness.
			$product = $this->service->products->get( $this->merchant_id, $product_id );

			// Check if we have access to competitive visibility data via Reports API.
			// Note: This requires the Merchant Center account to have competitor data enabled.
			$lowest_price = $this->get_lowest_price_from_competitivevisibility( $product_id );

			if ( $lowest_price ) {
				return $lowest_price;
			}

			// Fallback: If competitive visibility is not available, we'll need to use
			// the product's own price as reference (this happens when no competitor data exists).
			$product_data = $product->toSimpleObject();

			if ( isset( $product_data->price->value ) ) {
				$this->logger->warning( "No competitive data available for product {$product_id}, using own price as reference" );
				return (float) $product_data->price->value;
			}

			return null;

		} catch ( Exception $e ) {
			$this->logger->error( 'Error fetching competitive price: ' . $e->getMessage() );
			return null;
		}
	}

	/**
	 * Get lowest price from competitive visibility data.
	 *
	 * @param string $product_id Product ID.
	 * @return float|null Lowest competitor price or null.
	 */
	private function get_lowest_price_from_competitivevisibility( $product_id ) {
		try {
			// Use the Reports API to get competitive pricing data.
			// This requires the account to have access to competitive pricing insights.
			$service = new Google_Service_ShoppingContent_Reports( $this->client );

			// Note: The actual implementation depends on the specific API endpoints available.
			// For this implementation, we'll use a simplified approach.

			// The competitive visibility API may not be directly accessible via standard API.
			// In production, you might need to:
			// 1. Enable Merchant Center competitive visibility
			// 2. Use the Shopping Ads API
			// 3. Or scrape data from Google Merchant Center dashboard (not recommended)

			// For now, return null to indicate no competitive data found.
			// The calling code will handle this gracefully.
			return null;

		} catch ( Exception $e ) {
			$this->logger->error( 'Error accessing competitive visibility data: ' . $e->getMessage() );
			return null;
		}
	}

	/**
	 * Test API connection.
	 *
	 * @return bool True if connection successful.
	 */
	public function test_connection() {
		try {
			// Try to list products to test connection.
			$parameters = array( 'maxResults' => 1 );
			$this->service->products->listProducts( $this->merchant_id, $parameters );

			$this->logger->info( 'Google API connection test successful' );
			return true;

		} catch ( Exception $e ) {
			$this->logger->error( 'Google API connection test failed: ' . $e->getMessage() );
			return false;
		}
	}

	/**
	 * Get all products from Merchant Center.
	 *
	 * @return array Array of products.
	 */
	public function get_all_products() {
		try {
			$all_products = array();
			$page_token   = null;

			do {
				$parameters = array(
					'maxResults' => 250,
				);

				if ( $page_token ) {
					$parameters['pageToken'] = $page_token;
				}

				$response = $this->service->products->listProducts( $this->merchant_id, $parameters );
				$products = $response->getResources();

				if ( $products ) {
					$all_products = array_merge( $all_products, $products );
				}

				$page_token = $response->getNextPageToken();

			} while ( $page_token );

			return $all_products;

		} catch ( Exception $e ) {
			$this->logger->error( 'Error fetching products: ' . $e->getMessage() );
			return array();
		}
	}
}
