<?php
/**
 * PeachPay Square utility functions
 *
 * @phpcs:disable WordPress.Security.NonceVerification.Recommended
 *
 * @package PeachPay
 */

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

/**
 * Gets the correct square application id for signup purposes.
 */
function peachpay_square_application_id() {
	$config = peachpay_square_config();

	if ( ! $config ) {
		return '';
	}

	return $config['application_id'];
}

/**
 * Gets the square location id for the signed up store.
 */
function peachpay_square_location_id() {
	$account = peachpay_square_connected();

	if ( ! $account ) {
		return '';
	}

	return $account['location_id'];
}

/**
 * Gets the square country for the signed up store.
 */
function peachpay_square_country() {
	$account = peachpay_square_connected();

	if ( ! $account ) {
		return '';
	}

	return $account['country'];
}

/**
 * Gets the square currency for the signed up store.
 */
function peachpay_square_currency() {
	$account = peachpay_square_connected();

	if ( ! $account ) {
		return '';
	}

	return $account['currency'];
}

/**
 * Determines if Square is connected via client-side credentials.
 *
 * @return array|false Account data array if connected, false otherwise.
 */
function peachpay_square_connected() {
	if ( ! PeachPay_Square_Credentials::is_configured() ) {
		return false;
	}

	$account = PeachPay_Square_Credentials::get_account();
	return ! empty( $account ) ? $account : false;
}

/**
 * Gets Square configuration values (Application ID for frontend SDK).
 *
 * @return array|false Config array or false if not connected.
 */
function peachpay_square_config() {
	if ( ! PeachPay_Square_Credentials::is_configured() ) {
		return false;
	}

	return array(
		'application_id' => PeachPay_Square_Credentials::get_publishable_key(),
		'location_id'    => PeachPay_Square_Credentials::get_location_id(),
	);
}

/**
 * Gets the Square merchant id or returns an empty string if not connected.
 */
function peachpay_square_merchant_id() {
	return PeachPay_Square_Credentials::get_account_id();
}

/**
 * Gets Square Apple Pay domain config.
 */
function peachpay_square_get_apple_pay_config() {

	$suffix = '_' . PeachPay_Square_Credentials::current_mode();

	$config = get_option(
		'peachpay_square_apple_pay_config' . $suffix,
		array(
			'domain'       => wp_parse_url( get_site_url(), PHP_URL_HOST ),
			'registered'   => false,
			'auto_attempt' => false,
		)
	);

	return $config;
}

/**
 * Updates the Apple Pay domain registration config.
 *
 * @param array $config The Apple Pay domain config.
 */
function peachpay_square_update_apple_pay_config( $config ) {
	if ( ! $config || ! is_array( $config ) ) {
		return;
	}

	$suffix      = '_' . PeachPay_Square_Credentials::current_mode();
	$option_name = 'peachpay_square_apple_pay_config' . $suffix;

	update_option( $option_name, $config );

	// Explicitly bust the Redis/persistent object cache on Convesio hosting.
	// update_option() writes to DB and calls wp_cache_set(), but on Convesio the
	// Redis cache layer is not always invalidated in time. The next get_option()
	// call in the same request would still read the stale cached value without this.
	wp_cache_delete( $option_name, 'options' );
	wp_cache_delete( 'alloptions', 'options' );
}

/**
 * Indicates if Square Apple Pay domain is registered or now.
 */
function peachpay_square_apple_pay_domain_registered() {
	$config = peachpay_square_get_apple_pay_config();

	return $config['registered'];
}

/**
 * Syncs the Apple Pay domain registration status against Square's actual API state.
 *
 * Called on admin page load to ensure the DB reflects Square's reality.
 * Only fires when the DB says "not registered" — if Square already has the domain
 * verified (e.g. DB was reset or lost), this call is idempotent and returns VERIFIED,
 * which updates the DB so the "Action required" block disappears on refresh.
 *
 * Square's /v2/apple-pay/domains endpoint has no GET/list — registerDomain() is the
 * only way to query status. Square treats re-registration of an already-registered
 * domain as idempotent and returns status=VERIFIED.
 *
 * Not called when registered===true to avoid unnecessary API round-trips on every
 * admin page load once the domain is confirmed.
 *
 * Skipped during AJAX requests — the manual registration handler
 * (peachpay_square_register_apple_pay_domain) performs its own Square API call with
 * force=true. Running the sync here too would make two sequential API calls in the
 * same request and could overwrite the handler's result if Square returns PENDING
 * on the first call but VERIFIED on the second.
 */
function peachpay_square_sync_apple_pay_domain_status() {
	// Skip during AJAX requests: the manual registration handler calls Square directly.
	// Running a sync here too would race with it and may overwrite registered=true with
	// registered=false if Square returns PENDING on the first of the two simultaneous calls.
	if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
		peachpay_log( 'debug', '[Square] Apple Pay sync: skipped during AJAX request' );
		return;
	}

	if ( ! peachpay_square_connected() ) {
		peachpay_log( 'debug', '[Square] Apple Pay sync: Square not connected, skipping' );
		return;
	}

	$config = peachpay_square_get_apple_pay_config();

	// Already registered in DB — nothing to sync.
	if ( $config['registered'] ) {
		peachpay_log( 'debug', '[Square] Apple Pay sync: already registered, skipping' );
		return;
	}

	$current_domain = wp_parse_url( get_site_url(), PHP_URL_HOST );

	// Domain changed — reset config so registration is treated as fresh.
	if ( $current_domain !== $config['domain'] ) {
		peachpay_log( 'debug', '[Square] Apple Pay sync: domain changed from "' . $config['domain'] . '" to "' . $current_domain . '", resetting registration state' );
		$config['domain']       = $current_domain;
		$config['registered']   = false;
		$config['auto_attempt'] = false;
		peachpay_square_update_apple_pay_config( $config );
	}

	$client = PeachPay_Square_Credentials::get_rest_client();
	if ( ! $client ) {
		peachpay_log( 'debug', '[Square] Apple Pay sync: Square client not available, skipping' );
		return;
	}

	update_option( 'peachpay_attempt_applepay', 'square' );

	peachpay_log( 'debug', '[Square] Apple Pay sync: calling registerDomain for "' . $current_domain . '"' );

	try {
		$response = $client->register_apple_pay_domain( $current_domain );

		if ( is_wp_error( $response ) ) {
			peachpay_log( 'error', '[Square] Apple Pay sync: domain registration request failed: ' . $response->get_error_message() );
			return;
		}

		$status = isset( $response['status'] ) ? $response['status'] : '';

		peachpay_log( 'debug', '[Square] Apple Pay sync: got status "' . $status . '" for domain "' . $current_domain . '"' );

		if ( 'VERIFIED' === $status ) {
			$config['registered']   = true;
			$config['auto_attempt'] = true;
			peachpay_square_update_apple_pay_config( $config );
			peachpay_log( 'debug', '[Square] Apple Pay sync: domain verified, registered=true saved' );
		} else {
			// PENDING or unknown — do NOT write to DB. If DB already has registered=true
			// (written by a concurrent AJAX handler), overwriting it here would corrupt state.
			// The sync's only valid write action is confirming VERIFIED.
			peachpay_log( 'warning', '[Square] Apple Pay domain sync: domain not yet verified. Status: ' . $status . '. DB left untouched.' );
		}
	} catch ( \Exception $e ) {
		// Non-fatal — admin page still loads, "Action required" stays visible.
		// Do NOT write to DB: a stale $config read from object cache could overwrite a valid registered=true.
		peachpay_log( 'error', '[Square] Apple Pay domain sync error: ' . $e->getMessage() );
	}
}

/**
 * Handles Square ApplePay domain registration from TS side.
 */
function peachpay_square_handle_applepay_domain_registration() {
	//phpcs:ignore
	if ( ! isset( $_POST['security'] ) || ! wp_verify_nonce( $_POST['security'], 'peachpay-applepay-domain-register' ) ) {
		return wp_send_json(
			array(
				'success' => false,
				'message' => 'Invalid nonce. Please refresh the page and try again.',
			)
		);
	}

	wp_send_json( peachpay_square_register_apple_pay_domain( true ) );
}

/**
 * Attempts to register the domain for Square Apple Pay via the Square REST client.
 *
 * @param boolean $force Whether to force re-registration.
 */
function peachpay_square_register_apple_pay_domain( $force = false ) {
	if ( ! peachpay_square_connected() ) {
		peachpay_log( 'error', '[Square] Apple Pay registration: Square not connected' );
		return array(
			'success' => false,
			'message' => __( 'Square is not connected.', 'peachpay-for-woocommerce' ),
		);
	}

	$current_domain = wp_parse_url( get_site_url(), PHP_URL_HOST );
	$config         = peachpay_square_get_apple_pay_config();

	peachpay_log( 'debug', '[Square] Apple Pay registration: domain="' . $current_domain . '" stored_domain="' . $config['domain'] . '" registered=' . ( $config['registered'] ? 'true' : 'false' ) . ' auto_attempt=' . ( $config['auto_attempt'] ? 'true' : 'false' ) . ' force=' . ( $force ? 'true' : 'false' ) );

	// Domain is different so reset registration.
	if ( $current_domain !== $config['domain'] ) {
		peachpay_log( 'debug', '[Square] Apple Pay registration: domain changed from "' . $config['domain'] . '" to "' . $current_domain . '", resetting' );
		$config['domain']       = $current_domain;
		$config['registered']   = false;
		$config['auto_attempt'] = false;

		peachpay_square_update_apple_pay_config( $config );
	}

	if ( ! $force ) {
		if ( $config['registered'] || $config['auto_attempt'] ) {
			return array(
				'success' => false,
				'message' => __( 'Domain is already registered or the automatic attempt has already occurred. Use force=true to force a registration attempt.', 'peachpay-for-woocommerce' ),
			);
		}
	}

	$client = PeachPay_Square_Credentials::get_rest_client();
	if ( ! $client ) {
		$config['auto_attempt'] = true;
		peachpay_square_update_apple_pay_config( $config );
		peachpay_log( 'error', '[Square] Apple Pay registration: Square client not available' );
		return array(
			'success' => false,
			'message' => __( 'Square client not configured.', 'peachpay-for-woocommerce' ),
		);
	}

	update_option( 'peachpay_attempt_applepay', 'square' );

	peachpay_log( 'debug', '[Square] Apple Pay registration: calling registerDomain for "' . $current_domain . '"' );

	try {
		$response = $client->register_apple_pay_domain( $current_domain );

		if ( is_wp_error( $response ) ) {
			$config['registered']   = false;
			$config['auto_attempt'] = true;
			peachpay_square_update_apple_pay_config( $config );

			$error_data = $response->get_error_data();
			$detail     = is_array( $error_data ) && ! empty( $error_data['detail'] ) ? $error_data['detail'] : $response->get_error_message();

			peachpay_log( 'error', '[Square] Apple Pay domain registration error: ' . $detail );

			return array(
				'success' => false,
				'message' => sprintf( __( 'Square API error: %s', 'peachpay-for-woocommerce' ), $detail ),
			);
		}

		$status = isset( $response['status'] ) ? $response['status'] : '';

		peachpay_log( 'debug', '[Square] Apple Pay registration: got status "' . $status . '" for domain "' . $current_domain . '"' );

		if ( 'VERIFIED' !== $status ) {
			$config['registered']   = false;
			$config['auto_attempt'] = true;
			peachpay_square_update_apple_pay_config( $config );

			peachpay_log( 'error', '[Square] Apple Pay domain registration not verified. Status: ' . $status );

			return array(
				'success' => false,
				// translators: %s: Registration status returned by Square (e.g. PENDING).
				'message' => sprintf( __( 'Apple Pay domain registration not verified. Status: %s', 'peachpay-for-woocommerce' ), $status ),
			);
		}

		$config['registered']   = true;
		$config['auto_attempt'] = true;
		peachpay_square_update_apple_pay_config( $config );

		peachpay_log( 'debug', '[Square] Apple Pay registration: success, registered=true saved for domain "' . $current_domain . '"' );

		return array(
			'success' => true,
			'message' => __( 'Apple Pay domain registered successfully.', 'peachpay-for-woocommerce' ),
		);
	} catch ( \Exception $e ) {
		$config['registered']   = false;
		$config['auto_attempt'] = true;
		peachpay_square_update_apple_pay_config( $config );

		peachpay_log( 'error', '[Square] Apple Pay domain registration error: ' . $e->getMessage() );

		return array(
			'success' => false,
			// translators: %s: Error message.
			'message' => sprintf( __( 'Apple Pay domain registration failed: %s', 'peachpay-for-woocommerce' ), $e->getMessage() ),
		);
	}
}

/**
 * Gets a Square payment capability status.
 *
 * With client-side credentials, capabilities are assumed active when connected.
 * The merchant's Square account determines actual availability.
 *
 * @param string $payment_key The payment capability to check.
 * @return bool True if connected (capability assumed active), false otherwise.
 */
function peachpay_square_capability( $payment_key ) {
	return (bool) PeachPay_Square_Integration::connected();
}

/**
 * Adds the feature flag for enabling Square gateways.
 *
 * @param array $feature_list The list of features.
 */
function peachpay_square_register_feature( $feature_list ) {
	$connected = PeachPay_Square_Integration::connected();

	$feature_list['peachpay_square_gateways'] = array(
		'enabled'  => (bool) $connected && PeachPay_Square_Integration::has_gateway_enabled(),
		'metadata' => array(
			'country'        => $connected ? $connected['country'] : '',
			'location_id'    => $connected ? $connected['location_id'] : '',
			'application_id' => PeachPay_Square_Integration::public_key(),
			'script_src'     => pp_square_script_src(),
		),
	);

	return $feature_list;
}

/**
 * Handles Square settings actions with proper nonce verification.
 * 
 * SECURITY FIX: Added wp_verify_nonce checks to prevent CSRF attacks.
 */
function peachpay_square_handle_admin_actions() {
	// Handle Square connection with nonce verification
	if ( isset( $_GET['connected_square'] ) && isset( $_GET['_wpnonce'] ) ) {
		if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'peachpay_square_connect' ) ) {
			add_settings_error(
				'peachpay_messages',
				'peachpay_message',
				__( 'Security verification failed. Please try again.', 'peachpay-for-woocommerce' ),
				'error'
			);
			return;
		}

		if ( 'true' === $_GET['connected_square'] ) {
			peachpay_set_settings_option( 'peachpay_payment_options', 'square_enable', 1 );

			add_settings_error(
				'peachpay_messages',
				'peachpay_message',
				__( 'You have successfully connected your Square account. You may set up other payment methods in the "Payment methods" tab.', 'peachpay-for-woocommerce' ),
				'success'
			);
		} elseif ( 'false' === $_GET['connected_square'] ) {
			add_settings_error(
				'peachpay_messages',
				'peachpay_message',
				__( 'Square was not connected.', 'peachpay-for-woocommerce' ),
				'success'
			);
		}
	}

	// Handle Square unlink with nonce verification
	if ( isset( $_GET['unlink_square'] ) && isset( $_GET['_wpnonce'] ) ) {
		if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), 'peachpay_square_unlink' ) ) {
			add_settings_error(
				'peachpay_messages',
				'peachpay_message',
				__( 'Security verification failed. Please try again.', 'peachpay-for-woocommerce' ),
				'error'
			);
			return;
		}

		if ( peachpay_unlink_square() ) {
			add_settings_error(
				'peachpay_messages',
				'peachpay_message',
				__( 'You have successfully unlinked your Square account.', 'peachpay-for-woocommerce' ),
				'success'
			);
		} else {
			add_settings_error(
				'peachpay_messages',
				'peachpay_message',
				__( 'An error occurred while unlinking your Square account.', 'peachpay-for-woocommerce' ),
				'error'
			);
		}
	}
}

/**
 * Unlinks Square from PeachPay (deletes all credentials and legacy options).
 */
function peachpay_unlink_square() {
	return PeachPay_Square_Credentials::delete_credentials() ? 1 : 0;
}

/**
 * Gets the square script src.
 *
 * @param string $mode The mode to get the script src for.
 */
function pp_square_script_src( $mode = 'detect' ) {
	$script_src = 'https://web.squarecdn.com/v1/square.js';
	if ( PeachPay_Square_Integration::mode( $mode ) === 'test' ) {
		$script_src = 'https://sandbox.web.squarecdn.com/v1/square.js';
	}

	return $script_src;
}

/**
 * Helper function to generate secure URLs with nonces for Square admin actions.
 * 
 * @param string $action The action type ('connect' or 'unlink').
 * @param array  $params Additional URL parameters.
 * @return string Secure URL with nonce.
 */
function peachpay_square_secure_admin_url( $action, $params = array() ) {
	$base_url = admin_url( 'admin.php?page=peachpay&tab=payment#square' );
	
	$nonce_actions = array(
		'connect' => 'peachpay_square_connect',
		'unlink'  => 'peachpay_square_unlink',
	);
	
	if ( ! isset( $nonce_actions[ $action ] ) ) {
		return $base_url;
	}
	
	$params['_wpnonce'] = wp_create_nonce( $nonce_actions[ $action ] );
	
	return add_query_arg( $params, $base_url );
}

/**
 * Get secure Square URLs for admin template usage.
 * 
 * @return array Array of secure URLs for connect and unlink actions.
 */
function peachpay_get_secure_square_urls() {
	return array(
		'connect' => peachpay_square_secure_admin_url( 'connect', array( 'connected_square' => 'true' ) ),
		'unlink'  => peachpay_square_secure_admin_url( 'unlink', array( 'unlink_square' => '1' ) ),
	);
}

/**
 * AJAX handler for saving Square credentials.
 */
function peachpay_square_handle_save_credentials() {
	if ( ! isset( $_POST['security'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['security'] ) ), 'peachpay-square-credentials' ) ) {
		peachpay_log( 'error', '[Square] save_credentials: Invalid nonce' );
		wp_send_json_error(
			array(
				'message' => __( 'Invalid security token. Please refresh the page and try again.', 'peachpay-for-woocommerce' ),
			)
		);
		return;
	}

	if ( ! current_user_can( 'manage_woocommerce' ) ) {
		peachpay_log( 'error', '[Square] save_credentials: Missing manage_woocommerce capability' );
		wp_send_json_error(
			array(
				'message' => __( 'You do not have permission to perform this action.', 'peachpay-for-woocommerce' ),
			)
		);
		return;
	}

	$keys             = array();
	$masked_indicator = '••••••••••••••••';
	$mode             = PeachPay_Square_Credentials::current_mode();
	$is_test_mode     = 'test' === $mode;

	$pk_field = $mode . '_publishable_key';
	$sk_field = $mode . '_secret_key';

	if ( isset( $_POST[ $pk_field ] ) && ! empty( $_POST[ $pk_field ] ) ) {
		$keys[ $pk_field ] = sanitize_text_field( wp_unslash( $_POST[ $pk_field ] ) );
	}

	if ( isset( $_POST[ $sk_field ] ) && ! empty( $_POST[ $sk_field ] ) ) {
		if ( $masked_indicator === $_POST[ $sk_field ] ) {
			$existing_secret = PeachPay_Square_Credentials::get_secret_key( $mode );
			if ( $existing_secret ) {
				$keys[ $sk_field ] = $existing_secret;
			}
		} else {
			$keys[ $sk_field ] = sanitize_text_field( wp_unslash( $_POST[ $sk_field ] ) );
		}
	}

	// Preserve existing secret key when the field is omitted (masked value not posted from UI).
	if ( empty( $keys[ $sk_field ] ) ) {
		$existing_secret = PeachPay_Square_Credentials::get_secret_key( $mode );
		if ( $existing_secret ) {
			$keys[ $sk_field ] = $existing_secret;
		}
	}

	if ( isset( $_POST['webhook_secret'] ) && ! empty( $_POST['webhook_secret'] ) ) {
		if ( $masked_indicator === $_POST['webhook_secret'] ) {
			$existing_webhook = PeachPay_Square_Credentials::get_webhook_secret();
			if ( $existing_webhook ) {
				$keys['webhook_secret'] = $existing_webhook;
			}
		} else {
			$keys['webhook_secret'] = sanitize_text_field( wp_unslash( $_POST['webhook_secret'] ) );
		}
	}

	$result = PeachPay_Square_Credentials::save_credentials( $keys );

	if ( $result['success'] ) {
		wp_send_json_success( $result );
	} else {
		peachpay_log( 'error', '[Square] save_credentials: ' . ( isset( $result['message'] ) ? $result['message'] : 'Invalid credentials' ) );
		wp_send_json_error( $result );
	}
}

/**
 * AJAX handler for disconnecting Square.
 */
function peachpay_square_handle_disconnect() {
	if ( ! isset( $_POST['security'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['security'] ) ), 'peachpay-square-credentials' ) ) {
		peachpay_log( 'error', '[Square] disconnect: Invalid nonce' );
		wp_send_json_error(
			array(
				'message' => __( 'Invalid security token. Please refresh the page and try again.', 'peachpay-for-woocommerce' ),
			)
		);
		return;
	}

	if ( ! current_user_can( 'manage_woocommerce' ) ) {
		peachpay_log( 'error', '[Square] disconnect: Missing manage_woocommerce capability' );
		wp_send_json_error(
			array(
				'message' => __( 'You do not have permission to perform this action.', 'peachpay-for-woocommerce' ),
			)
		);
		return;
	}

	PeachPay_Square_Credentials::delete_credentials();

	wp_send_json_success(
		array(
			'message' => __( 'Square has been disconnected.', 'peachpay-for-woocommerce' ),
		)
	);
}

/**
 * Displays the Square payment details on the order admin page.
 *
 * @param WC_Order $order The WooCommerce order.
 */
function peachpay_square_display_order_transaction_details( $order ) {
	if ( did_action( 'woocommerce_admin_order_data_after_billing_address' ) > 1 ) {
		return;
	}
	if ( ! PeachPay_Square_Integration::is_payment_gateway( $order->get_payment_method() ) ) {
		return;
	}
	$payment_id = PeachPay_Square_Order_Data::get_payment( $order, 'id' );
	if ( null !== $payment_id ) {
		include PeachPay::get_plugin_path() . '/core/payments/square/admin/views/html-square-payment-info.php';
	}
}

/**
 * Displays Square fee and net payout lines on the order totals section.
 *
 * @param int $order_id The WooCommerce order ID.
 */
function peachpay_square_display_transaction_fee_lines( $order_id ) {
	if ( did_action( 'woocommerce_admin_order_totals_after_total' ) > 1 ) {
		return;
	}
	$order    = wc_get_order( $order_id );
	$refunded = floatval( $order->get_total_refunded() );
	if ( ! PeachPay_Square_Integration::is_payment_gateway( $order->get_payment_method() ) || ( ! $order->is_paid() && 0 === $refunded ) ) {
		return;
	}
	$fees        = PeachPay_Square_Order_Data::total_fees( $order );
	$total_money = PeachPay_Square_Order_Data::get_payment( $order, 'total_money' );
	if ( null !== $fees && null !== $total_money ) {
		$currency = strtoupper( $total_money['currency'] );
		include PeachPay::get_plugin_path() . '/core/payments/square/admin/views/html-square-transaction-fees.php';
	}
}
