<?php
/**
 * WPForms admin refunds for Payments Square Connect.
 *
 * @package SHC4WC
 */

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

class SHC4WC_WPForms_Refunds {
	/** @var self|null */
	private static $instance = null;

	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	private function __construct() {
		if ( ! function_exists( 'wpforms' ) ) {
			return;
		}

		add_filter( 'wpforms_admin_strings', array( $this, 'admin_strings' ) );
		add_filter( 'wpforms_admin_payments_views_single_gateway_transaction_link', array( $this, 'gateway_transaction_link' ), 10, 2 );

		if ( wpforms_is_admin_ajax() ) {
			add_action( 'wp_ajax_wpforms_payments-square-connect_payments_refund', array( $this, 'ajax_payment_refund' ) );
		}
	}

	/**
	 * @param array $admin_strings Admin strings.
	 * @return array
	 */
	public function admin_strings( $admin_strings ) {
		$admin_strings = (array) $admin_strings;
		if ( ! isset( $admin_strings['single_payment_button_handlers'] ) || ! is_array( $admin_strings['single_payment_button_handlers'] ) ) {
			$admin_strings['single_payment_button_handlers'] = array();
		}
		$admin_strings['single_payment_button_handlers'][] = 'payments-square-connect';
		return $admin_strings;
	}

	/**
	 * @param string $link    Gateway link.
	 * @param object $payment Payment row.
	 * @return string
	 */
	public function gateway_transaction_link( $link, $payment ) {
		if ( ! is_object( $payment ) || empty( $payment->gateway ) || 'payments-square-connect' !== $payment->gateway ) {
			return $link;
		}

		$payment_id = $this->resolve_square_payment_id( $payment );
		if ( '' === $payment_id ) {
			return $link;
		}

		$test_mode = isset( $payment->mode ) && 'test' === $payment->mode;
		return SHC4WC_Refunds::square_dashboard_transaction_url( $payment_id, $test_mode );
	}

	/**
	 * Refund a WPForms payment via Square API.
	 */
	public function ajax_payment_refund() {
		$payment_db = $this->get_db_payment();
		if ( ! $payment_db || 'payments-square-connect' !== $payment_db->gateway ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Invalid payment gateway.', 'payments-connect-square' ) ) );
		}

		$square_payment_id = $this->resolve_square_payment_id( $payment_db );
		if ( '' === $square_payment_id ) {
			wp_send_json_error(
				array(
					'message' => esc_html__(
						'Square payment ID was not found. Wait for the customer to return from Square, then try again.',
						'payments-connect-square'
					),
				)
			);
		}

		$amount_to_refund = (float) wpforms_sanitize_amount( $payment_db->total_amount, $payment_db->currency );
		if ( 'partrefund' === $payment_db->status && wpforms()->obj( 'payment_meta' ) ) {
			$already_refunded = (float) wpforms()->obj( 'payment_meta' )->get_single( $payment_db->id, 'refunded_amount' );
			$amount_to_refund = max( 0, $amount_to_refund - $already_refunded );
		}

		if ( $amount_to_refund <= 0 ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Nothing left to refund.', 'payments-connect-square' ) ) );
		}

		$result = SHC4WC_Refunds::process_refund(
			$square_payment_id,
			$amount_to_refund,
			$payment_db->currency,
			'wpforms_refund_' . (int) $payment_db->id
		);

		if ( is_wp_error( $result ) ) {
			wp_send_json_error( array( 'message' => esc_html( $result->get_error_message() ) ) );
		}

		$log = sprintf(
			/* translators: %s: refunded amount. */
			__( 'Square payment refunded from WPForms. Refunded amount: %s.', 'payments-connect-square' ),
			wpforms_format_amount( wpforms_sanitize_amount( $amount_to_refund, $payment_db->currency ), true, $payment_db->currency )
		);

		$saved = false;
		if ( class_exists( '\WPForms\Db\Payments\UpdateHelpers' ) ) {
			$saved = \WPForms\Db\Payments\UpdateHelpers::refund_payment( $payment_db, $payment_db->total_amount, $log );
		} elseif ( wpforms()->obj( 'payment' ) ) {
			$status = $amount_to_refund < (float) wpforms_sanitize_amount( $payment_db->total_amount, $payment_db->currency ) ? 'partrefund' : 'refunded';
			$saved  = (bool) wpforms()->obj( 'payment' )->update( $payment_db->id, array( 'status' => $status ) );
			if ( $saved && wpforms()->obj( 'payment_meta' ) ) {
				wpforms()->obj( 'payment_meta' )->update_or_add( $payment_db->id, 'refunded_amount', $payment_db->total_amount );
				wpforms()->obj( 'payment_meta' )->add_log( $payment_db->id, $log );
			}
		}

		if ( $saved ) {
			if ( '' !== $square_payment_id && $square_payment_id !== (string) $payment_db->transaction_id && wpforms()->obj( 'payment' ) ) {
				wpforms()->obj( 'payment' )->update( $payment_db->id, array( 'transaction_id' => $square_payment_id ) );
			}
			wp_send_json_success( array( 'message' => esc_html__( 'Refund successful.', 'payments-connect-square' ) ) );
		}

		wp_send_json_error( array( 'message' => esc_html__( 'Saving refund in the database failed.', 'payments-connect-square' ) ) );
	}

	/**
	 * @param object $payment_db Payment row.
	 * @return string
	 */
	private function resolve_square_payment_id( $payment_db ) {
		$transaction_id  = isset( $payment_db->transaction_id ) ? (string) $payment_db->transaction_id : '';
		$square_order_id = '';
		$payment_link_id = '';
		if ( wpforms()->obj( 'payment_meta' ) ) {
			$square_order_id = (string) wpforms()->obj( 'payment_meta' )->get_single( $payment_db->id, 'shc4wc_square_order_id' );
			$payment_link_id = (string) wpforms()->obj( 'payment_meta' )->get_single( $payment_db->id, 'shc4wc_payment_link_id' );
		}

		if (
			'' !== $transaction_id
			&& ! SHC4WC_Refunds::is_internal_checkout_reference( $transaction_id )
			&& ( '' === $payment_link_id || $transaction_id !== $payment_link_id )
		) {
			return $transaction_id;
		}

		if ( '' === $square_order_id ) {
			return '';
		}

		if ( '' === $payment_link_id && '' !== $transaction_id && ! SHC4WC_Refunds::is_internal_checkout_reference( $transaction_id ) ) {
			$payment_link_id = $transaction_id;
		}

		$settings    = SHC4WC_Plugin::get_settings();
		$location_id = isset( $settings['location_id'] ) ? trim( (string) $settings['location_id'] ) : '';
		$resolved    = SHC4WC_Plugin::instance()->retrieve_square_payment_id_for_hosted_checkout(
			$square_order_id,
			$payment_link_id,
			$location_id,
			time()
		);

		if ( '' !== $resolved && wpforms()->obj( 'payment' ) ) {
			wpforms()->obj( 'payment' )->update( $payment_db->id, array( 'transaction_id' => $resolved ) );
		}

		return $resolved;
	}

	/**
	 * @return object|null
	 */
	private function get_db_payment() {
		if ( ! isset( $_POST['payment_id'] ) || ! function_exists( 'wpforms_current_user_can' ) || ! wpforms_current_user_can( wpforms_get_capability_manage_options() ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'You are not allowed to perform this action.', 'payments-connect-square' ) ) );
		}

		check_ajax_referer( 'wpforms-admin', 'nonce' );

		$payment_id = (int) $_POST['payment_id'];
		$payment_db = wpforms()->obj( 'payment' )->get( $payment_id );

		if ( empty( $payment_db ) ) {
			wp_send_json_error( array( 'message' => esc_html__( 'Payment not found in the database.', 'payments-connect-square' ) ) );
		}

		return $payment_db;
	}
}
