<?php
/**
 * ACH Bank Transfer Gateway
 *
 * Provides ACH bank transfer payment via Square.
 * Note: ACH is only available in the United States.
 *
 * @package FunnelKit_Square
 * @subpackage Payment
 */

namespace FKWCSQ\Includes\Modules\Payment\Gateways;

use FKWCSQ\Includes\API;
use FKWCSQ\Includes\Logger;
use FKWCSQ\Square;

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

/**
 * ACH Class
 *
 * ACH bank transfer payment gateway.
 * Key features:
 * - US only (USD currency)
 * - Payments take 2-3 business days to settle
 * - Uses Square's Plaid integration for bank verification
 * - Orders set to on-hold until payment clears
 */
class ACH extends \WC_Payment_Gateway {

	/**
	 * Gateway ID.
	 *
	 * @var string
	 */
	public $id = 'fkwcsq_ach';

	/**
	 * API instance for Square integration.
	 *
	 * @var API
	 */
	protected $api;

	/**
	 * Whether logging is enabled.
	 *
	 * @var bool
	 */
	protected $logging_enabled;

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->setup_gateway_properties();
		$this->init_form_fields();
		$this->init_settings();
		$this->load_settings();
		$this->init_hooks();
	}

	/**
	 * Set up basic gateway properties.
	 *
	 * @return void
	 */
	protected function setup_gateway_properties() {
		$this->method_title       = __( 'Square ACH Bank Transfer', 'funnelkit-payment-gateway-square-for-woocommerce' );
		$this->method_description = __( 'Accept ACH bank transfer payments via Square. Only available in the United States.', 'funnelkit-payment-gateway-square-for-woocommerce' );
		$this->has_fields         = true;
		$this->supports           = array(
			'products',
			'refunds',
		);
	}

	/**
	 * Initialize form fields for admin settings.
	 *
	 * @return void
	 */
	public function init_form_fields() {
		$this->form_fields = array(
			'enabled'     => array(
				'title'   => __( 'Enable/Disable', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'type'    => 'checkbox',
				'label'   => __( 'Enable Square ACH Bank Transfer', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'default' => 'no',
			),
			'title'       => array(
				'title'       => __( 'Title', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'type'        => 'text',
				'description' => __( 'Payment method title shown to customers.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'default'     => __( 'Bank Transfer (ACH)', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'desc_tip'    => true,
			),
			'description' => array(
				'title'       => __( 'Description', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'type'        => 'textarea',
				'description' => __( 'Payment method description shown to customers.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'default'     => __( 'Pay directly from your bank account. Payments typically take 2-3 business days to process.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'desc_tip'    => true,
			),
		);
	}

	/**
	 * Load settings from database.
	 *
	 * @return void
	 */
	protected function load_settings() {
		$this->enabled         = $this->get_option( 'enabled', 'no' );
		$this->title           = $this->get_option( 'title', __( 'Bank Transfer (ACH)', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
		$this->description     = $this->get_option( 'description', __( 'Pay directly from your bank account. Payments typically take 2-3 business days to process.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
		$general_settings      = get_option( 'fkwcsq_settings', array() );
		$this->logging_enabled = isset( $general_settings['logging_enabled'] ) && 'yes' === $general_settings['logging_enabled'];
		$this->api             = API::get_instance();
	}

	/**
	 * Initialize hooks.
	 *
	 * @return void
	 */
	protected function init_hooks() {
		add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
		add_action( 'wp_enqueue_scripts', array( $this, 'payment_scripts' ) );
	}

	/**
	 * Check if gateway is available.
	 *
	 * ACH is only available:
	 * - In the United States
	 * - With USD currency
	 * - When Square is properly connected
	 *
	 * @return bool
	 */
	public function is_available() {
		if ( 'yes' !== $this->enabled ) {
			return false;
		}

		// ACH is US only.
		$base_country = WC()->countries->get_base_country();
		if ( 'US' !== $base_country ) {
			return false;
		}

		// ACH is USD only.
		$currency = get_woocommerce_currency();
		if ( 'USD' !== $currency ) {
			return false;
		}

		// Check if Square is connected.
		if ( ! Square::get_application_id() ) {
			return false;
		}

		return true;
	}

	/**
	 * Get localize data for this gateway.
	 *
	 * @return array Localize data.
	 */
	/**
	 * Get gateway-specific localize data.
	 *
	 * Only includes data unique to ACH gateway. Base data (application_id,
	 * location_id, is_sandbox, currency, etc.) is added by Checkout_Scripts.
	 *
	 * @return array
	 */
	public function get_gateway_data() {
		// Generate unique transaction ID for ACH session.
		$transaction_id = wp_generate_uuid4();
		if ( WC()->session ) {
			WC()->session->set( 'fkwcsq_ach_transaction_id', $transaction_id );
		}

		$cart_total = WC()->cart ? WC()->cart->get_total( 'edit' ) : 0;

		return array(
			'redirect_url'    => wc_get_checkout_url(),
			'transaction_id'  => $transaction_id,
			'nonce'           => wp_create_nonce( 'fkwcsq_ach' ),
			'payment_request' => array(
				'total' => array(
					'label'  => get_bloginfo( 'name', 'display' ),
					'amount' => number_format( (float) $cart_total, 2, '.', '' ),
				),
			),
			'i18n'            => array(
				'not_supported'   => __( 'ACH payments are not supported in your region.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'payment_pending' => __( 'Your payment is being processed. This may take 2-3 business days.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'select_bank'     => __( 'Select your bank to continue', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'account_holder'  => __( 'Account Holder Name', 'funnelkit-payment-gateway-square-for-woocommerce' ),
			),
		);
	}

	/**
	 * Enqueue payment scripts.
	 *
	 * @return void
	 */
	public function payment_scripts() {
		if ( ! is_checkout() && ! is_add_payment_method_page() ) {
			return;
		}

		if ( ! $this->is_available() ) {
			return;
		}

		$checkout_scripts = \FKWCSQ\Includes\Checkout_Scripts::get_instance();
		$checkout_scripts->enqueue_checkout_script();
		$checkout_scripts->localize_gateway_data( 'fkwcsq_ach_params', $this->id, $this->get_gateway_data() );

		// Add inline CSS for ACH gateway styling.
		$inline_css = '
			#fkwcsq-ach-container {
				padding: 15px 0;
			}

			#fkwcsq-ach-error {
				color: #dc3545;
				margin-top: 10px;
				display: none;
			}

			#fkwcsq-ach-info {
				background: #f0f9ff;
				border: 1px solid #b3d7f5;
				border-radius: 4px;
				padding: 10px 15px;
				margin-bottom: 15px;
				font-size: 13px;
				color: #0d5aa7;
			}

			.fkwcsq-ach-account-holder {
				margin-bottom: 15px;
			}

			.fkwcsq-ach-account-holder label {
				display: block;
				margin-bottom: 5px;
				font-weight: 600;
			}

			.fkwcsq-ach-account-holder input {
				width: 100%;
				padding: 10px;
				border: 1px solid #ddd;
				border-radius: 4px;
			}

			/* Plaid overlay z-index fix (classic and blocks checkout) */
			.Overlay.Overlay--is-active,
			.wc-block-checkout .Overlay.Overlay--is-active {
				z-index: 100 !important;
			}
		';

		// Register and enqueue inline CSS.
		wp_register_style( 'fkwcsq-ach-inline', false, array(), FKWCSQ_VERSION );
		wp_enqueue_style( 'fkwcsq-ach-inline' );
		wp_add_inline_style( 'fkwcsq-ach-inline', $inline_css );
	}

	/**
	 * Render payment fields on checkout.
	 *
	 * When user clicks Place Order, Plaid modal opens to connect bank account.
	 *
	 * @return void
	 */
	public function payment_fields() {
		if ( $this->description ) {
			echo '<p>' . wp_kses_post( $this->description ) . '</p>';
		}

		?>
		<div id="fkwcsq-ach-container">
			<div id="fkwcsq-ach-info">
				<?php esc_html_e( 'ACH bank transfers typically take 2-3 business days to process. Your order will be held until payment clears.', 'funnelkit-payment-gateway-square-for-woocommerce' ); ?>
			</div>
			<div class="fkwcsq-ach-account-holder">
				<label for="fkwcsq_ach_account_holder"><?php esc_html_e( 'Account Holder Name', 'funnelkit-payment-gateway-square-for-woocommerce' ); ?></label>
				<input type="text" id="fkwcsq_ach_account_holder" name="fkwcsq_ach_account_holder" placeholder="<?php esc_attr_e( 'Enter the name on your bank account', 'funnelkit-payment-gateway-square-for-woocommerce' ); ?>" required />
			</div>
			<div id="fkwcsq-ach-error"></div>
		</div>
		<input type="hidden" name="fkwcsq_ach_nonce" id="fkwcsq_ach_nonce" />
		<input type="hidden" name="fkwcsq_ach_account_details" id="fkwcsq_ach_account_details" />
		<?php wp_nonce_field( 'fkwcsq_ach_payment', 'fkwcsq_ach_wp_nonce' ); ?>
		<?php
	}

	/**
	 * Process the payment.
	 *
	 * @param int $order_id Order ID.
	 * @return array Result array.
	 */
	public function process_payment( $order_id ) {
		$order = wc_get_order( $order_id );

		if ( ! $order ) {
			wc_add_notice( __( 'Order not found.', 'funnelkit-payment-gateway-square-for-woocommerce' ), 'error' );
			return array( 'result' => 'failure' );
		}

		// Verify the classic-checkout WP nonce for CSRF protection. This nonce is only
		// rendered in payment_fields() on the shortcode/classic checkout. On the Blocks
		// (Store API / REST) checkout the React component never submits it, and the Store
		// API enforces its own request nonce before process_payment() is reached — so we
		// only enforce this gateway-level nonce for non-REST requests to avoid breaking
		// the Blocks checkout.
		if ( ! WC()->is_rest_api_request() ) {
			$wp_nonce = isset( $_POST['fkwcsq_ach_wp_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['fkwcsq_ach_wp_nonce'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Missing, FKWCS.CodeAnalysis.FKWCSSpecific.MissingCapabilityCheck -- Checkout gateway, guest users allowed
			if ( ! wp_verify_nonce( $wp_nonce, 'fkwcsq_ach_payment' ) ) {
				wc_add_notice( __( 'Security check failed. Please refresh and try again.', 'funnelkit-payment-gateway-square-for-woocommerce' ), 'error' );
				return array( 'result' => 'failure' );
			}
		}

		// Get the Square payment token from POST.
		$nonce = isset( $_POST['fkwcsq_ach_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['fkwcsq_ach_nonce'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Missing, FKWCS.CodeAnalysis.FKWCSSpecific.MissingCapabilityCheck -- WP nonce verified above, guest checkout allowed

		if ( empty( $nonce ) ) {
			wc_add_notice( __( 'Bank account not verified. Please connect your bank account.', 'funnelkit-payment-gateway-square-for-woocommerce' ), 'error' );
			return array( 'result' => 'failure' );
		}

		// Get account details for order notes (non-sensitive reference only).
		$account_details = isset( $_POST['fkwcsq_ach_account_details'] ) ? sanitize_text_field( wp_unslash( $_POST['fkwcsq_ach_account_details'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Missing, FKWCS.CodeAnalysis.FKWCSSpecific.MissingCapabilityCheck -- WP nonce verified above, guest checkout allowed

		try {
			$result = $this->create_payment( $order, $nonce );

			if ( is_wp_error( $result ) ) {
				throw new \Exception( $result->get_error_message() );
			}

			// API returns array, not object.
			$payment_id     = isset( $result['payment']['id'] ) ? $result['payment']['id'] : '';
			$payment_status = isset( $result['payment']['status'] ) ? $result['payment']['status'] : '';

			if ( empty( $payment_id ) ) {
				throw new \Exception( __( 'Payment failed. No payment ID received.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
			}

			// Store payment info.
			$order->update_meta_data( '_square_payment_id', $payment_id );
			$order->update_meta_data( '_square_payment_status', $payment_status );
			$order->update_meta_data( '_square_payment_source', 'ACH' );

			// Store account details if available.
			if ( ! empty( $account_details ) ) {
				$order->update_meta_data( '_square_ach_account_details', $account_details );
			}

			$order->save();

			// Check payment status.
			if ( 'COMPLETED' === $payment_status ) {
				// Payment completed immediately (rare for ACH).
				$order->payment_complete( $payment_id );
			} elseif ( 'PENDING' === $payment_status ) {
				// Typical for ACH - payment is pending clearance.
				$order->update_status(
					'on-hold',
					sprintf(
						/* translators: %s: Square payment ID */
						__( 'Square ACH payment pending clearance. Payment ID: %s. This typically takes 2-3 business days.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
						$payment_id
					)
				);
			} else {
				// Other status - treat as failure.
				throw new \Exception(
					sprintf(
						/* translators: %s: payment status */
						__( 'Payment status: %s', 'funnelkit-payment-gateway-square-for-woocommerce' ),
						$payment_status
					)
				);
			}

			// Clear session.
			WC()->session->set( 'fkwcsq_ach_transaction_id', null );

			// Empty cart.
			WC()->cart->empty_cart();

			return array(
				'result'   => 'success',
				'redirect' => $this->get_return_url( $order ),
			);

		} catch ( \Throwable $e ) {
			Logger::error( 'ACH payment error: ' . $e->getMessage() );
			wc_add_notice( $e->getMessage(), 'error' );
			return array( 'result' => 'failure' );
		}
	}

	/**
	 * Create payment with Square API.
	 *
	 * @param \WC_Order $order Order object.
	 * @param string    $nonce Payment nonce from tokenization.
	 * @return \Square\Models\CreatePaymentResponse|\WP_Error
	 */
	protected function create_payment( $order, $nonce ) {
		$payment_data = array(
			'source_id'       => $nonce,
			'idempotency_key' => fkwcsq_idempotency_key( 'fkwcsq_ach_' ),
			'amount_money'    => array(
				'amount'   => $this->format_amount( $order->get_total() ),
				'currency' => $order->get_currency(),
			),
			'reference_id'    => $this->api->get_reference_id( $order->get_order_number() ),
			'location_id'     => $this->api->get_location_id(),
			'note'            => sprintf(
				/* translators: 1: blog name, 2: order number */
				__( '%1$s - Order %2$s', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				get_bloginfo( 'name' ),
				$order->get_order_number()
			),
		);

		// Add buyer information.
		$payment_data['buyer_email_address'] = $order->get_billing_email();

		// Add billing address.
		$payment_data['billing_address'] = array(
			'first_name'                      => $order->get_billing_first_name(),
			'last_name'                       => $order->get_billing_last_name(),
			'address_line_1'                  => $order->get_billing_address_1(),
			'locality'                        => $order->get_billing_city(),
			'administrative_district_level_1' => $order->get_billing_state(),
			'postal_code'                     => $order->get_billing_postcode(),
			'country'                         => $order->get_billing_country(),
		);

		$response = $this->api->create_payment( $payment_data );

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

		return $response;
	}

	/**
	 * Format amount for Square API.
	 *
	 * @param float $amount Amount to format.
	 * @return int Amount in smallest currency unit (cents).
	 */
	protected function format_amount( $amount ) {
		return absint( round( $amount * 100 ) );
	}

	/**
	 * Process refund.
	 *
	 * @param int    $order_id Order ID.
	 * @param float  $amount Refund amount.
	 * @param string $reason Refund reason.
	 * @return bool|\WP_Error
	 */
	public function process_refund( $order_id, $amount = null, $reason = '' ) {
		$order = wc_get_order( $order_id );

		if ( ! $order ) {
			return new \WP_Error( 'invalid_order', __( 'Invalid order.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
		}

		$payment_id = $order->get_meta( '_square_payment_id' );

		if ( empty( $payment_id ) ) {
			return new \WP_Error( 'no_payment_id', __( 'No Square payment ID found for this order.', 'funnelkit-payment-gateway-square-for-woocommerce' ) );
		}

		// Check payment status - can only refund COMPLETED payments.
		$payment_status = $order->get_meta( '_square_payment_status' );

		if ( 'COMPLETED' !== $payment_status ) {
			return new \WP_Error(
				'payment_not_completed',
				__( 'ACH payment has not cleared yet. Please wait until payment is completed before issuing a refund.', 'funnelkit-payment-gateway-square-for-woocommerce' )
			);
		}

		// process_refund expects (payment_id, amount) not array.
		$response = $this->api->process_refund( $payment_id, $amount );

		if ( is_wp_error( $response ) ) {
			Logger::error( 'ACH refund error: ' . $response->get_error_message() );
			return $response;
		}

		// API returns array with refund_id key.
		$refund_id = isset( $response['refund_id'] ) ? $response['refund_id'] : 'N/A';

		$order->add_order_note(
			sprintf(
				/* translators: 1: refund amount, 2: Square refund ID */
				__( 'Refunded %1$s via Square ACH. Refund ID: %2$s', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				wc_price( $amount ),
				$refund_id
			)
		);

		return true;
	}
	/**
	 * Get gateway icon.
	 *
	 * @return string Icon HTML.
	 */
	public function get_icon() {
		$icon_url = FKWCSQ_PLUGIN_URL . 'assets/images/ach.svg';
		$icon     = '<img src="' . esc_url( $icon_url ) . '" alt="' . esc_attr( $this->get_title() ) . '" style="max-height: 24px;" />';
		return apply_filters( 'woocommerce_gateway_icon', $icon, $this->id );
	}
}
