<?php
/**
 * Square webhook endpoint handler.
 *
 * @package SHC4WC
 */

// phpcs:disable Squiz.Commenting
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class SHC4WC_Webhook {
	public static function handle() {
		if ( 'POST' !== strtoupper( (string) filter_input( INPUT_SERVER, 'REQUEST_METHOD', FILTER_SANITIZE_FULL_SPECIAL_CHARS ) ) ) {
			status_header( 405 );
			exit;
		}

		$settings = SHC4WC_Plugin::get_settings();
		$creds    = SHC4WC_Plugin::get_credentials();
		$api      = new SHC4WC_API( $settings );

		$raw = file_get_contents( 'php://input' ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
		if ( ! is_string( $raw ) ) {
			status_header( 400 );
			exit;
		}

		if ( empty( $creds['webhook_secret'] ) || ! self::verify_signature( $raw, $creds['webhook_secret'] ) ) {
			$api->log( 'Webhook signature validation failed', array(), 'warning' );
			status_header( 401 );
			exit;
		}

		$event = json_decode( $raw, true );
		if ( ! is_array( $event ) ) {
			status_header( 400 );
			exit;
		}

		$type = isset( $event['type'] ) ? sanitize_text_field( $event['type'] ) : '';

		$api->log(
			'Square webhook received',
			array(
				'type' => $type,
			)
		);

		if ( 'inventory.count.updated' === $type ) {
			SHC4WC_Inventory_Sync::handle_webhook_event( $event, $api );
			status_header( 200 );
			exit;
		}

		if ( class_exists( 'SHC4WC_PMPro_Webhook' ) ) {
			SHC4WC_PMPro_Webhook::maybe_handle_event( $type, $event, $api );
		}

		self::handle_payment_event( $event, $api );

		status_header( 200 );
		exit;
	}

	/**
	 * @param array<string, mixed> $event Webhook event.
	 * @param SHC4WC_API           $api   API client/logger.
	 */
	private static function handle_payment_event( array $event, SHC4WC_API $api ) {
		$payment           = isset( $event['data']['object']['payment'] ) && is_array( $event['data']['object']['payment'] ) ? $event['data']['object']['payment'] : array();
		$payment_status    = isset( $payment['status'] ) ? sanitize_text_field( $payment['status'] ) : '';
		$square_order      = isset( $payment['order_id'] ) ? sanitize_text_field( $payment['order_id'] ) : '';
		$square_payment_id = isset( $payment['id'] ) ? sanitize_text_field( (string) $payment['id'] ) : '';

		if ( '' !== $square_order ) {
			$api->log(
				'Square payment webhook payload',
				array(
					'payment_status'    => $payment_status,
					'square_order'      => $square_order,
					'square_payment_id' => $square_payment_id,
				)
			);
		}

		if ( empty( $square_order ) ) {
			return;
		}

		if ( ! function_exists( 'wc_get_orders' ) ) {
			return;
		}

		$orders = wc_get_orders( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key,WordPress.DB.SlowDBQuery.slow_db_query_meta_value
			array(
				'limit'      => 1,
				'meta_key'   => '_shc4wc_square_order_id', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
				'meta_value' => $square_order, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
				'return'     => 'objects',
			)
		);

		if ( empty( $orders ) ) {
			return;
		}

		$order = $orders[0];
		if ( ! $order instanceof WC_Order ) {
			return;
		}

		if ( '' !== $square_payment_id ) {
			$order->update_meta_data( '_shc4wc_square_payment_id', $square_payment_id );
			$order->save();
		}

		if ( 'COMPLETED' === strtoupper( $payment_status ) && $order->has_status( array( 'pending', 'processing', 'on-hold', 'failed' ) ) ) {
			$order->payment_complete( $square_payment_id ? $square_payment_id : '' );
			$note = __( 'Square webhook marked this order as paid.', 'payments-connect-square' );
			if ( '' !== $square_payment_id ) {
				$note .= ' ' . sprintf(
					/* translators: %s: Square Payment API id (transaction / tender id). */
					__( 'Square payment (transaction) ID: %s', 'payments-connect-square' ),
					$square_payment_id
				);
			}
			$order->update_status( 'processing', $note );
			$api->log(
				'Order marked processing from webhook',
				array(
					'order_id'          => $order->get_id(),
					'square_payment_id' => $square_payment_id,
				)
			);
		}
	}

	private static function verify_signature( $raw, $signature_key ) {
		$header = isset( $_SERVER['HTTP_X_SQUARE_HMACSHA256_SIGNATURE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_X_SQUARE_HMACSHA256_SIGNATURE'] ) ) : '';
		if ( empty( $header ) ) {
			return false;
		}

		$url      = SHC4WC_Plugin::public_api_url( 'shc4wc_webhook' );
		$expected = base64_encode( hash_hmac( 'sha256', $url . $raw, $signature_key, true ) ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
		return hash_equals( $expected, $header );
	}
}
