<?php
/**
 * FunnelKit Square Integration Middleware Connection Handler
 *
 * @package FunnelKit_Square
 * @subpackage Connection
 * @since 1.0.0
 */

namespace FKWCSQ\Includes\Modules\Connection;

use FKWCSQ\Includes\API;
use FKWCSQ\Includes\Logger;
use FKWCSQ\Includes\Traits\Instance;
use Exception;
use WP_Error;

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

// Import WordPress functions
use function admin_url;
use function wp_remote_post;
use function wp_safe_redirect;
use function add_settings_error;
use function update_option;
use function get_option;
use function delete_option;

/**
 * FKWCSQ_Middleware_Connection Class
 * Handles connection through middleware server
 */
class MiddleWare {
	use Instance;

	/**
	 * Middleware API URL
	 *
	 * @var string
	 */
	private $middleware_url = 'https://secure-auth.funnelkit.com/square/index.php';
	/**
	 * The current connection mode ('sandbox' or 'production').
	 *
	 * @var string
	 */
	public $connect_mode = null;
	/**
	 * Constructor
	 */
	private function __construct() {
	}

	/**
	 * Get middleware connection URL
	 *
	 * @param bool $deauthorize Whether to deauthorize existing connection before reconnecting
	 * @return string
	 */
	public function get_connection_url( $deauthorize = false ) {
		$transient_key = 'fkwcsq_connect_state_' . get_current_user_id();
		$state_token   = get_transient( $transient_key );
		if ( empty( $state_token ) ) {
			$state_token = wp_generate_password( 32, false );
			set_transient( $transient_key, $state_token, 30 * MINUTE_IN_SECONDS );
		}
		$redirect_uri = admin_url( 'admin.php?page=wc-settings&tab=fkwcsq_square_api&fkwcsq-callback=1&fkwcsq_state=' . $state_token );

		$webhook_key = get_transient( 'fkwcsq_pending_webhook_key' );
		if ( empty( $webhook_key ) ) {
			$webhook_key = bin2hex( random_bytes( 32 ) );
			set_transient( 'fkwcsq_pending_webhook_key', $webhook_key, 30 * MINUTE_IN_SECONDS );
		}

		$params = array(
			'site_url'         => trailingslashit( get_home_url( null, '', 'rest' ) ),
			'redirect_uri'     => $redirect_uri,
			'sandbox'          => '0',
			'webhook_auth_key' => $webhook_key,
		);

		// If deauthorizing, include the current access token and deauthorize flag
		if ( $deauthorize ) {
			$tokens = \FKWCSQ\Square::get_tokens();
			if ( ! empty( $tokens['access_token'] ) ) {
				$params['deauthorize']  = '1';
				$params['access_token'] = $tokens['access_token'];
			}
		}

		$get_unique_id = get_option( 'fkwcsq_wp_square', '' );
		if ( ! empty( $get_unique_id ) ) {
			$params['wp_square'] = $get_unique_id;
		}

		return $this->middleware_url . '/connect?' . http_build_query( $params );
	}

	/**
	 * Get sandbox middleware connection URL for OAuth testing
	 *
	 * @return string
	 */
	public function get_sandbox_connection_url() {
		$transient_key = 'fkwcsq_connect_state_' . get_current_user_id();
		$state_token   = get_transient( $transient_key );
		if ( empty( $state_token ) ) {
			$state_token = wp_generate_password( 32, false );
			set_transient( $transient_key, $state_token, 30 * MINUTE_IN_SECONDS );
		}
		$redirect_uri = admin_url( 'admin.php?page=wc-settings&tab=fkwcsq_square_api&fkwcsq_state=' . $state_token );

		$webhook_key = get_transient( 'fkwcsq_pending_webhook_key' );
		if ( empty( $webhook_key ) ) {
			$webhook_key = bin2hex( random_bytes( 32 ) );
			set_transient( 'fkwcsq_pending_webhook_key', $webhook_key, 30 * MINUTE_IN_SECONDS );
		}

		$params = array(
			'site_url'         => site_url( '/' ),
			'redirect_uri'     => $redirect_uri,
			'sandbox'          => '1',
			'webhook_auth_key' => $webhook_key,
		);

		return $this->middleware_url . '/connect?' . http_build_query( $params );
	}

	/**
	 * Handle middleware callback
	 */
	public function handle_middleware_callback() {
		// Require WooCommerce management capability for security
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}

		if ( isset( $_GET['page'] ) && 'wc-settings' === $_GET['page'] ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
			// Handle tokens from middleware
			if ( isset( $_GET['fkwcsq_tokens'] ) ) { //phpcs:ignore WordPress.Security.NonceVerification.Recommended
				if ( ! $this->verify_connect_state() ) {
					$this->redirect_to_error_page( __( 'Security check failed. Please try connecting again.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
					return;
				}
				$this->process_middleware_tokens();
			}
		}
	}

	/**
	 * Verify the CSRF state token from the Square Connect OAuth callback.
	 *
	 * @return bool
	 */
	private function verify_connect_state() {
		$state_token = isset( $_GET['fkwcsq_state'] ) ? sanitize_text_field( wp_unslash( $_GET['fkwcsq_state'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		if ( empty( $state_token ) ) {
			return false;
		}
		$transient_key = 'fkwcsq_connect_state_' . get_current_user_id();
		$stored_token  = get_transient( $transient_key );
		if ( empty( $stored_token ) || ! hash_equals( $stored_token, $state_token ) ) {
			return false;
		}
		delete_transient( $transient_key );

		return true;
	}

	/**
	 * Process tokens from middleware
	 *
	 * @return void
	 * @throws \Exception When token processing fails.
	 * @since 1.0.0
	 */
	private function process_middleware_tokens() {
		try {

			// Decode and validate tokens
			$tokens_data = isset( $_GET['fkwcsq_tokens'] ) ? sanitize_text_field( wp_unslash( $_GET['fkwcsq_tokens'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
			$tokens      = json_decode( base64_decode( $tokens_data ), true );

			if ( ! $tokens || ! isset( $tokens['access_token'] ) ) {
				throw new Exception( __( 'Invalid tokens received from middleware.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
			}

			// Process tokens based on environment mode
			$this->save_tokens( $tokens );
			$this->initialize_api_and_process_locations( $tokens );
			$this->save_site_id();
			$this->save_pending_webhook_key();
			$this->redirect_to_success_page();

		} catch ( Exception $e ) {
			$this->redirect_to_error_page( $e->getMessage() );
		}
	}

	private function set_connect_mode() {
		$this->connect_mode = isset( $_GET['sandbox'] ) && $_GET['sandbox'] === '1' ? 'sandbox' : 'production'; //phpcs:ignore WordPress.Security.NonceVerification.Recommended
	}

	/**
	 * Save tokens based on sandbox mode
	 */
	private function save_tokens( array $tokens ) {
		$token_data = array(
			'access_token'  => $tokens['access_token'],
			'refresh_token' => $tokens['refresh_token'],
			'expires_at'    => $tokens['expires_at'],
			'merchant_id'   => $tokens['merchant_id'],
		);

		$this->set_connect_mode();
		if ( $this->connect_mode === 'sandbox' ) {
			$token_data['application_id'] = FKWCSQ_SANDBOX_APPLICATION_ID;
		}
		$option_name = $this->connect_mode === 'sandbox' ? 'fkwcsq_sandbox_tokens' : 'fkwcsq_tokens';
		update_option( $option_name, $token_data );
	}

	/**
	 * Initialize API client and handle location processing
	 */
	private function initialize_api_and_process_locations( array $tokens ) {
		$this->update_production_settings( $tokens, array() );
		$api = API::get_instance();

		$api->maybe_init_client();

		$locations = $api->get_locations();

		// Check if locations is a WP_Error (API call failed)
		if ( is_wp_error( $locations ) ) {
			$locations = array();
		}

		$this->update_production_settings( $tokens, $locations );
		$this->update_sandbox_settings( $locations );
	}

	/**
	 * Update settings for production mode (non-sandbox)
	 */
	private function update_production_settings( array $tokens, array $locations ) {

		if ( ! \FKWCSQ\Square::is_sandbox_mode() ) {
			$settings                      = get_option( 'fkwcsq_settings', array() );
			$settings['connection_status'] = 'connected';
			$settings['environment']       = 'production';
			$settings['merchant_id']       = $tokens['merchant_id'];

			if ( ! empty( $locations ) ) {
				$settings['location_id'] = $locations[0]['id'];
			}

			update_option( 'fkwcsq_settings', $settings );

			// Save connection timestamp for version tracking
			update_option( 'fkwcsq_connection_timestamp', time(), false );

			// Trigger action for gateway management
			do_action( 'fkwcsq_after_connection' );
		}
	}

	/**
	 * Update settings after a successful sandbox OAuth connection.
	 */
	private function update_sandbox_settings( array $locations ) {
		if ( $this->connect_mode !== 'sandbox' ) {
			return;
		}

		$settings                              = get_option( 'fkwcsq_settings', array() );
		$settings['sandbox_connection_status'] = 'connected';

		if ( ! empty( $locations ) ) {
			$settings['sandbox_location_id'] = $locations[0]['id'];
		}

		update_option( 'fkwcsq_settings', $settings );
		update_option( 'fkwcsq_connection_timestamp', time(), false );
		do_action( 'fkwcsq_after_connection' );
	}

	/**
	 * Save site ID from GET parameter
	 */
	private function save_site_id() {
		$site_id = isset( $_GET['site_id'] ) ? sanitize_text_field( wp_unslash( $_GET['site_id'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Recommended

		if ( ! empty( $site_id ) ) {
			update_option( 'fkwcsq_site_id', $site_id, false );
		}
	}

	/**
	 * Promote the pending webhook key transient to a permanent option.
	 * The key was generated in get_connection_url() and already sent to the middleware server.
	 */
	private function save_pending_webhook_key() {
		$key = get_transient( 'fkwcsq_pending_webhook_key' );
		if ( ! empty( $key ) ) {
			update_option( 'fkwcsq_webhook_auth_key', $key, false );
			delete_transient( 'fkwcsq_pending_webhook_key' );
		}
	}

	/**
	 * Redirect to success page
	 */
	private function redirect_to_success_page() {
		wp_safe_redirect( admin_url( 'admin.php?page=wc-settings&tab=fkwcsq_square_api&connection=success' ) );
		exit;
	}

	/**
	 * Redirect to error page with message
	 */
	private function redirect_to_error_page( string $message ) {
		wp_safe_redirect( admin_url( 'admin.php?page=wc-settings&tab=fkwcsq_square_api&connection=error&message=' . rawurlencode( $message ) ) );
		exit;
	}

	/**
	 * Handle disconnect action
	 */
	public function handle_disconnect_action() {
		// Require WooCommerce management capability for security
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}

		$is_valid_page     = isset( $_GET['page'] ) && $_GET['page'] === 'wc-settings';
		$is_disconnect_req = isset( $_GET['fkwcsq_disconnect'] ) && $_GET['fkwcsq_disconnect'] === '1';
		$is_nonce_valid    = isset( $_GET['_wpnonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'fkwcsq_disconnect' );

		if ( $is_valid_page && $is_disconnect_req && $is_nonce_valid ) {
			$this->disconnect();
		} elseif ( $is_valid_page && $is_disconnect_req && ! $is_nonce_valid ) {
			add_settings_error( 'fkwcsq_settings', 'fkwcsq_disconnect_error', esc_html__( 'Security check failed.', 'funnelkit-payment-gateway-square-for-woocommerce' ), 'error' );
		}
	}

	/**
	 * Check if connected through middleware
	 *
	 * @return bool
	 */
	public function is_connected() {
		$settings   = get_option( 'fkwcsq_settings', array() );
		$is_sandbox = \FKWCSQ\Square::is_sandbox_mode();

		if ( $is_sandbox ) {
			$sandbox_tokens = get_option( 'fkwcsq_sandbox_tokens', array() );

			return isset( $settings['sandbox_connection_status'] ) && $settings['sandbox_connection_status'] === 'connected' && ! empty( $sandbox_tokens['access_token'] );
		}

		$tokens = get_option( 'fkwcsq_tokens', array() );

		return isset( $settings['connection_status'] ) && $settings['connection_status'] === 'connected' && ! empty( $tokens['access_token'] );
	}

	/**
	 * Disconnect from Square through middleware
	 */
	public function disconnect() {
		try {
			$settings = get_option( 'fkwcsq_settings', array() );

			delete_option( 'fkwcsq_sandbox_tokens' );
			delete_option( 'fkwcsq_sandbox_locations' );
			unset( $settings['sandbox_location_id'] );
			unset( $settings['sandbox_connection_status'] );

			// Delete production tokens and settings
			delete_option( 'fkwcsq_tokens' );
			delete_option( 'fkwcsq_locations' );
			delete_option( 'fkwcsq_site_id' );
			delete_option( 'fkwcsq_webhook_auth_key' );
			unset( $settings['location_id'] );
			unset( $settings['connection_status'] );
			unset( $settings['merchant_id'] );

			// Clear any transients
			global $wpdb;
			$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_fkwcsq_%'" ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery
			$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '_transient_timeout_fkwcsq_%'" ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery

			update_option( 'fkwcsq_settings', $settings );

			wp_safe_redirect( admin_url( 'admin.php?page=wc-settings&tab=fkwcsq_square_api&disconnect=success' ) );
			exit;
		} catch ( Exception $e ) {
			wp_safe_redirect( admin_url( 'admin.php?page=wc-settings&tab=fkwcsq_square_api&disconnect=error&message=' . rawurlencode( $e->getMessage() ) ) );
			exit;
		}
	}

	/**
	 * Generate a site-specific webhook auth key, persist it locally, and register it with
	 * the relay server so it can embed the key in every forwarded webhook request.
	 *
	 * Called on initial connect and on plugin update (for existing connected sites).
	 *
	 * @return bool Whether the key was successfully pushed to the server.
	 */
	public function generate_and_register_webhook_key(): bool {
		$key = bin2hex( random_bytes( 32 ) );
		update_option( 'fkwcsq_webhook_auth_key', $key, false );
		return $this->push_webhook_key_to_server( $key );
	}

	/**
	 * POST the webhook auth key to the relay server's /update-hash endpoint.
	 *
	 * @param string $key The generated auth key.
	 * @return bool
	 */
	private function push_webhook_key_to_server( string $key ): bool {
		$request_body = array(
			'webhook_auth_key' => $key,
			'site_id'          => get_option( 'fkwcsq_site_id', '' ),
			'sandbox'          => \FKWCSQ\Square::is_sandbox_mode() ? '1' : '0',
		);

		Logger::debug( 'Webhook key push — request: ' . wp_json_encode( $request_body ) );

		$response = wp_remote_post(
			$this->middleware_url . '/update-hash',
			array(
				'timeout' => 15,
				'body'    => $request_body,
			)
		);

		if ( is_wp_error( $response ) ) {
			Logger::error( 'Webhook key push — WP_Error: ' . $response->get_error_message() );
			return false;
		}

		$code = wp_remote_retrieve_response_code( $response );
		$body = wp_remote_retrieve_body( $response );
		Logger::debug( 'Webhook key push — response HTTP ' . $code . ': ' . $body );

		if ( $code < 200 || $code >= 300 ) {
			Logger::error( 'Webhook key push — failed with HTTP ' . $code . ': ' . $body );
			return false;
		}

		return true;
	}

	/**
	 * Refresh access token through middleware
	 *
	 * @return bool
	 */
	public function refresh_access_token_middleware() {
		$tokens = get_option( 'fkwcsq_tokens' );
		if ( ! $tokens || ! isset( $tokens['refresh_token'] ) ) {
			return false;
		}

		try {
			$response = wp_remote_post(
				$this->middleware_url . '/refresh-token',
				array(
					'timeout' => 45,
					'body'    => array(
						'site_url'      => trailingslashit( get_home_url( null, '', 'rest' ) ),
						'refresh_token' => $tokens['refresh_token'],
						'merchant_id'   => $tokens['merchant_id'] ?? '',
						'wp_square'     => '',
					),
				)
			);

			if ( is_wp_error( $response ) ) {
				return false;
			}

			$body   = wp_remote_retrieve_body( $response );
			$result = json_decode( $body, true );

			if ( ! $result || ! isset( $result['access_token'] ) ) {
				return false;
			}

			// Update tokens with new values
			update_option(
				'fkwcsq_tokens',
				array(
					'access_token'  => $result['access_token'],
					'refresh_token' => $result['refresh_token'] ?? $tokens['refresh_token'],
					'expires_at'    => time() + ( $result['expires_in'] ?? 86400 ),
					'merchant_id'   => $tokens['merchant_id'] ?? '',
					'last_refresh'  => current_time( 'mysql' ),
				)
			);

			return true;

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