<?php
/**
 * Google Sheets Service Account Authentication Class
 *
 * @package ShopExplorer\GoogleSheets
 * @since 1.0.0
 */

namespace SHOPEXPLORER\GoogleSheets;

use SHOPEXPLORER\Exceptions\GoogleSheetsException;

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

/**
 * Google Sheets Service Account Authentication class
 *
 * Handles service account authentication for Google Sheets API
 *
 * @since 1.0.0
 */
class SHOPEX_ServiceAccountAuth {

	/**
	 * Credentials option name
	 *
	 * @var string
	 */
	private $credentials_option = 'shopex_service_account_credentials';

	/**
	 * Token option name
	 *
	 * @var string
	 */
	private $token_option = 'shopex_service_account_token';

	/**
	 * Set service account credentials
	 *
	 * @param array $credentials Service account credentials
	 * @return bool
	 * @throws GoogleSheetsException
	 */
	public function set_credentials( $credentials ) {
		try {
			// Validate credentials structure
			$this->validate_service_account_credentials( $credentials );

			// Store credentials securely
			$encrypted_credentials = $this->encrypt_credentials( $credentials );
			update_option( $this->credentials_option, $encrypted_credentials );

			return true;

		} catch ( \Exception $e ) {
						return false;

		}
	}

	/**
	 * Get stored credentials
	 *
	 * @return array|null
	 */
	public function get_credentials() {
		$encrypted_credentials = get_option( $this->credentials_option );

		if ( ! $encrypted_credentials ) {
			return null;
		}

		return $this->decrypt_credentials( $encrypted_credentials );
	}

	/**
	 * Check if credentials are set
	 *
	 * @return bool
	 */
	public function has_credentials() {
		$credentials = $this->get_credentials();
		$has_creds = ! empty( $credentials ) && isset( $credentials['client_email'] );

		if ( $has_creds ) {
			// error_log( 'Shop Explorer: Credentials found for: ' . $credentials['client_email'] );
		} else {
			// error_log( 'Shop Explorer: No valid credentials found' );
		}

		return $has_creds;
	}

	/**
	 * Generate access token using service account
	 *
	 * @return string|false
	 */
	public function get_access_token() {
		$credentials = $this->get_credentials();

		if ( ! $credentials ) {
			return false;
		}

		// Check if we have a cached token that's still valid
		$cached_token = get_transient( $this->token_option );
		if ( $cached_token ) {
			return $cached_token;
		}

		try {
			$client_email = $credentials['client_email'];
			$private_key = $credentials['private_key'];
			$now = time();
			$exp = $now + 3600; // 1 hour

			// Create JWT header
			$header = json_encode( [
				'alg' => 'RS256',
				'typ' => 'JWT',
			] );

			// Create JWT payload - using only Google Sheets scope like order-sync
			$payload = json_encode( [
				'iss' => $client_email,
				'aud' => 'https://oauth2.googleapis.com/token',
				'iat' => $now,
				'exp' => $exp,
				'scope' => 'https://www.googleapis.com/auth/spreadsheets',
			] );

			// Encode header and payload
			$base64_url_header = str_replace( [ '+', '/', '=' ], [ '-', '_', '' ], base64_encode( $header ) );
			$base64_url_payload = str_replace( [ '+', '/', '=' ], [ '-', '_', '' ], base64_encode( $payload ) );

			// Create signature
			$signature = '';
			$sign_result = openssl_sign( $base64_url_header . '.' . $base64_url_payload, $signature, $private_key, 'SHA256' );

			if ( ! $sign_result ) {
				// error_log( 'Shop Explorer: Failed to sign JWT with private key' );
				return false;
			}

			$base64_url_signature = str_replace( [ '+', '/', '=' ], [ '-', '_', '' ], base64_encode( $signature ) );

			// Create JWT
			$jwt = $base64_url_header . '.' . $base64_url_payload . '.' . $base64_url_signature;

			// error_log( 'Shop Explorer: JWT created successfully (length: ' . strlen( $jwt ) . ')' );

			// Request access token
			$response = \wp_remote_post( 'https://oauth2.googleapis.com/token', [
				'body' => [
					'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
					'assertion' => $jwt,
				],
				'timeout' => 30,
			] );

			if ( is_wp_error( $response ) ) {
				// error_log( 'Shop Explorer: Token request failed - WP Error: ' . $response->get_error_message() );
				return false;
			}

			$response_code = \wp_remote_retrieve_response_code( $response );
			$response_body = \wp_remote_retrieve_body( $response );

			// error_log( 'Shop Explorer: Token request response code: ' . $response_code );

			if ( $response_code !== 200 ) {
				// error_log( 'Shop Explorer: Token request failed - Response: ' . $response_body );
				return false;
			}

			$token_data = json_decode( $response_body, true );

			if ( isset( $token_data['access_token'] ) ) {
				$access_token = $token_data['access_token'];

				// Cache the token for 50 minutes (expires in 60)
				set_transient( $this->token_option, $access_token, 3000 );

				return $access_token;
			}

			return false;

		} catch ( \Exception $e ) {

			return false;
		}
	}

	/**
	 * Test authentication by making a simple API call
	 *
	 * @return bool
	 */
	public function test_authentication() {
		$access_token = $this->get_access_token();

		if ( ! $access_token ) {
			// error_log( 'Shop Explorer: Test authentication failed - no access token' );
			return false;
		}

		// error_log( 'Shop Explorer: Testing authentication with access token (length: ' . strlen( $access_token ) . ')' );

		// Simple test - just validate the token by calling the Google OAuth2 tokeninfo endpoint
		// This doesn't require any specific permissions, just validates the token
		$response = \wp_remote_get( 'https://oauth2.googleapis.com/tokeninfo?access_token=' . $access_token, [
			'timeout' => 30,
		] );

		if ( is_wp_error( $response ) ) {
			// error_log( 'Shop Explorer: Test authentication failed - WP Error: ' . $response->get_error_message() );
			return false;
		}

		$response_code = \wp_remote_retrieve_response_code( $response );
		$response_body = \wp_remote_retrieve_body( $response );

		// error_log( 'Shop Explorer: Test authentication response code: ' . $response_code );
		// error_log( 'Shop Explorer: Test authentication response body: ' . substr( $response_body, 0, 200 ) );

		if ( $response_code === 200 ) {
			$response_data = json_decode( $response_body, true );
			if ( isset( $response_data['scope'] ) && strpos( $response_data['scope'], 'spreadsheets' ) !== false ) {
				// error_log( 'Shop Explorer: Test authentication successful - token valid with spreadsheets scope' );
				return true;
			}
		}

		// error_log( 'Shop Explorer: Test authentication failed - Response code: ' . $response_code );
		return false;
	}

	/**
	 * Test access to a specific spreadsheet
	 * Following order-sync approach
	 *
	 * @param string $spreadsheet_id Spreadsheet ID to test
	 * @return bool
	 */
	public function test_spreadsheet_access( $spreadsheet_id ) {
		$access_token = $this->get_access_token();

		if ( ! $access_token ) {
			// error_log( 'Shop Explorer: Test spreadsheet access failed - no access token' );
			return false;
		}

		// error_log( 'Shop Explorer: Testing access to spreadsheet: ' . $spreadsheet_id );

		// Test by trying to get spreadsheet metadata (similar to order-sync get_sheet_tab)
		$api_url = "https://sheets.googleapis.com/v4/spreadsheets/{$spreadsheet_id}";

		$response = \wp_remote_get( $api_url, [
			'headers' => [
				'Authorization' => 'Bearer ' . $access_token,
			],
			'timeout' => 30,
		] );

		if ( is_wp_error( $response ) ) {
			// error_log( 'Shop Explorer: Test spreadsheet access failed - WP Error: ' . $response->get_error_message() );
			return false;
		}

		$response_code = \wp_remote_retrieve_response_code( $response );
		$response_body = \wp_remote_retrieve_body( $response );

		// error_log( 'Shop Explorer: Test spreadsheet access response code: ' . $response_code );

		if ( $response_code === 200 ) {
			$response_data = json_decode( $response_body, true );
			if ( isset( $response_data['sheets'] ) ) {
				// error_log( 'Shop Explorer: Spreadsheet access successful - found ' . count( $response_data['sheets'] ) . ' sheets' );
				return true;
			}
		}

		// error_log( 'Shop Explorer: Test spreadsheet access failed - Response: ' . substr( $response_body, 0, 200 ) );
		return false;
	}

	/**
	 * Get service account email
	 *
	 * @return string|null
	 */
	public function get_service_account_email() {
		$credentials = $this->get_credentials();
		return $credentials['client_email'] ?? null;
	}

	/**
	 * Revoke authentication
	 *
	 * @return bool
	 */
	public function revoke_authentication() {
		$deleted_creds = delete_option( $this->credentials_option );
		$deleted_token = delete_transient( $this->token_option );
		delete_option( 'shopex_encryption_key' ); // Also clear encryption key

		// error_log( 'Shop Explorer: Revoked authentication - Credentials: ' . ( $deleted_creds ? 'deleted' : 'not found' ) . ', Token: ' . ( $deleted_token ? 'deleted' : 'not found' ) );
		return true;
	}

	/**
	 * Debug method to check credential storage status
	 *
	 * @return array
	 */
	public function debug_credential_status() {
		$encrypted_credentials = get_option( $this->credentials_option );
		$has_encrypted = ! empty( $encrypted_credentials );
		$can_decrypt = false;
		$has_client_email = false;

		if ( $has_encrypted ) {
			$decrypted = $this->decrypt_credentials( $encrypted_credentials );
			$can_decrypt = ! empty( $decrypted );
			$has_client_email = $can_decrypt && isset( $decrypted['client_email'] );
		}

		$status = [
			'has_encrypted_data' => $has_encrypted,
			'can_decrypt' => $can_decrypt,
			'has_client_email' => $has_client_email,
			'option_name' => $this->credentials_option,
		];

		// error_log( 'Shop Explorer: Credential status: ' . json_encode( $status ) );
		return $status;
	}

	/**
	 * Validate service account credentials structure
	 *
	 * @param array $credentials Credentials to validate
	 * @throws GoogleSheetsException
	 */
	private function validate_service_account_credentials( $credentials ) {
		$required_fields = [ 'type', 'client_email', 'private_key', 'project_id' ];

		foreach ( $required_fields as $field ) {
			if ( ! isset( $credentials[ $field ] ) ) {
				return false;
			}
		}

		if ( $credentials['type'] !== 'service_account' ) {
			return false;
		}
	}

	/**
	 * Encrypt credentials for storage
	 *
	 * @param array $credentials Credentials to encrypt
	 * @return string
	 */
	private function encrypt_credentials( $credentials ) {
		$key = $this->get_encryption_key();
		$serialized = serialize( $credentials );
		$encrypted = openssl_encrypt( $serialized, 'AES-256-CBC', $key, 0, substr( $key, 0, 16 ) );
		return base64_encode( $encrypted );
	}

	/**
	 * Decrypt credentials from storage
	 *
	 * @param string $encrypted_credentials Encrypted credentials
	 * @return array|null
	 */
	private function decrypt_credentials( $encrypted_credentials ) {
		try {
			$key = $this->get_encryption_key();
			$encrypted = base64_decode( $encrypted_credentials );
			$decrypted = openssl_decrypt( $encrypted, 'AES-256-CBC', $key, 0, substr( $key, 0, 16 ) );
			return unserialize( $decrypted );
		} catch ( \Exception $e ) {
			return null;
		}
	}

	/**
	 * Get encryption key
	 *
	 * @return string
	 */
	private function get_encryption_key() {
		$key = get_option( 'shopex_encryption_key' );

		if ( ! $key ) {
			$key = wp_generate_password( 32, false );
			update_option( 'shopex_encryption_key', $key );
		}

		return hash( 'sha256', $key . SECURE_AUTH_KEY );
	}
}
