<?php
/**
 * Afterpay/Clearpay Gateway
 *
 * Provides Afterpay/Clearpay buy-now-pay-later payment via Square.
 * Known as "Clearpay" in the UK, "Afterpay" elsewhere.
 *
 * @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;
}

/**
 * Afterpay Class
 *
 * Afterpay/Clearpay payment gateway.
 * Key features:
 * - Supported in US, CA, AU, NZ, UK
 * - Different branding for UK (Clearpay) vs others (Afterpay)
 * - Order amount limits vary by currency
 * - 4 interest-free installments
 */
class Afterpay extends \WC_Payment_Gateway {

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

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

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

	/**
	 * Supported countries.
	 *
	 * @var array
	 */
	protected $supported_countries = array( 'US', 'CA', 'AU', 'NZ', 'GB' );

	/**
	 * Supported currencies.
	 *
	 * @var array
	 */
	protected $supported_currencies = array( 'USD', 'CAD', 'AUD', 'NZD', 'GBP' );

	/**
	 * Order limits by currency (min, max in whole units).
	 *
	 * @var array
	 */
	protected $order_limits = array(
		'USD' => array(
			'min' => 1,
			'max' => 4000,
		),
		'CAD' => array(
			'min' => 1,
			'max' => 4000,
		),
		'AUD' => array(
			'min' => 1,
			'max' => 2000,
		),
		'NZD' => array(
			'min' => 1,
			'max' => 2000,
		),
		'GBP' => array(
			'min' => 1,
			'max' => 1200,
		),
	);

	/**
	 * 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 Afterpay/Clearpay', 'funnelkit-payment-gateway-square-for-woocommerce' );
		$this->method_description = __( 'Accept Afterpay/Clearpay buy-now-pay-later payments via Square. Known as Clearpay in the UK.', '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 Afterpay/Clearpay', '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'     => $this->get_default_title(),
				'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 in 4 interest-free installments.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'desc_tip'    => true,
			),
			'show_messaging' => array(
				'title'       => __( 'Show Installment Messaging', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'type'        => 'checkbox',
				'label'       => __( 'Display installment amount on checkout', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'description' => __( 'Shows customers the installment amount (e.g., "4 payments of $25.00").', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'default'     => 'yes',
				'desc_tip'    => true,
			),
			'button_theme'   => array(
				'title'       => __( 'Button Theme', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'type'        => 'select',
				'description' => __( 'Choose the Afterpay button appearance.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'default'     => 'black_on_mint',
				'options'     => array(
					'black_on_mint'  => __( 'Black on Mint', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					'white_on_black' => __( 'White on Black', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					'black_on_white' => __( 'Black on White', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					'mint_on_black'  => __( 'Mint on Black', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				),
				'desc_tip'    => true,
			),
			'button_type'    => array(
				'title'       => __( 'Button Type', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'type'        => 'select',
				'description' => __( 'Choose the button text.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'default'     => 'buy_now_with_afterpay',
				'options'     => array(
					'buy_now_with_afterpay'     => __( 'Buy now with Afterpay', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					'checkout_with_afterpay'    => __( 'Checkout with Afterpay', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					'pay_now_with_afterpay'     => __( 'Pay now with Afterpay', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					'place_order_with_afterpay' => __( 'Place order with Afterpay', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				),
				'desc_tip'    => true,
			),
		);
	}

	/**
	 * Get default title based on store country.
	 *
	 * @return string
	 */
	protected function get_default_title() {
		return $this->is_clearpay() ? __( 'Clearpay', 'funnelkit-payment-gateway-square-for-woocommerce' ) : __( 'Afterpay', 'funnelkit-payment-gateway-square-for-woocommerce' );
	}

	/**
	 * Check if store is in UK (uses Clearpay branding).
	 *
	 * @return bool
	 */
	public function is_clearpay() {
		$base_country = WC()->countries->get_base_country();
		return 'GB' === $base_country;
	}

	/**
	 * Load settings from database.
	 *
	 * @return void
	 */
	protected function load_settings() {
		$this->enabled         = $this->get_option( 'enabled', 'no' );
		$this->title           = $this->get_option( 'title', $this->get_default_title() );
		$this->description     = $this->get_option( 'description', __( 'Pay in 4 interest-free installments.', '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' ) );
		add_action( 'woocommerce_review_order_after_submit', array( $this, 'render_afterpay_button_wrapper' ) );
		add_action( 'wfacp_woocommerce_review_order_after_submit', array( $this, 'render_afterpay_button_wrapper' ) );
	}

	/**
	 * Check if gateway is available.
	 *
	 * Afterpay is available when:
	 * - Gateway is enabled
	 * - Store country is supported
	 * - Currency is supported
	 * - Order amount is within limits
	 * - Square is connected
	 *
	 * @return bool
	 */
	public function is_available() {
		if ( 'yes' !== $this->enabled ) {
			return false;
		}

		// Check country.
		$base_country = WC()->countries->get_base_country();
		if ( ! in_array( $base_country, $this->supported_countries, true ) ) {
			return false;
		}

		// Check currency.
		$currency = get_woocommerce_currency();
		if ( ! in_array( $currency, $this->supported_currencies, true ) ) {
			return false;
		}

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

		// Check order amount limits.
		if ( WC()->cart ) {
			$total = WC()->cart->get_total( 'edit' );
			if ( ! $this->is_amount_within_limits( $total, $currency ) ) {
				return false;
			}
		}

		return true;
	}

	/**
	 * Check if amount is within Afterpay limits.
	 *
	 * @param float  $amount Amount to check.
	 * @param string $currency Currency code.
	 * @return bool
	 */
	public function is_amount_within_limits( $amount, $currency ) {
		if ( ! isset( $this->order_limits[ $currency ] ) ) {
			return false;
		}

		$limits = $this->order_limits[ $currency ];
		return $amount >= $limits['min'] && $amount <= $limits['max'];
	}

	/**
	 * Get order limits for a currency.
	 *
	 * @param string $currency Currency code.
	 * @return array|null
	 */
	public function get_order_limits( $currency ) {
		return isset( $this->order_limits[ $currency ] ) ? $this->order_limits[ $currency ] : null;
	}

	/**
	 * Get gateway-specific localize data.
	 *
	 * Only includes data unique to Afterpay gateway. Base data is added by Checkout_Scripts.
	 *
	 * @return array
	 */
	public function get_gateway_data() {
		$currency   = get_woocommerce_currency();
		$limits     = $this->get_order_limits( $currency );
		$cart_total = WC()->cart ? WC()->cart->get_total( 'edit' ) : 0;

		return array(
			'currency_code'   => $currency,
			'is_clearpay'     => $this->is_clearpay(),
			'show_messaging'  => $this->get_option( 'show_messaging', 'yes' ) === 'yes',
			'button_theme'    => $this->get_option( 'button_theme', 'black_on_mint' ),
			'button_type'     => $this->get_option( 'button_type', 'buy_now_with_afterpay' ),
			'min_amount'      => $limits ? $limits['min'] : 1,
			'max_amount'      => $limits ? $limits['max'] : 4000,
			'payment_request' => array(
				'total' => array(
					'label'  => get_bloginfo( 'name', 'display' ),
					'amount' => number_format( (float) $cart_total, 2, '.', '' ),
				),
			),
			'i18n'            => array(
				'not_supported'    => __( 'Afterpay is not available in your region.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				'amount_too_low'   => sprintf(
					/* translators: %s: minimum amount */
					__( 'Order total must be at least %s for Afterpay.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					wc_price( $limits ? $limits['min'] : 1 )
				),
				'amount_too_high'  => sprintf(
					/* translators: %s: maximum amount */
					__( 'Order total must be less than %s for Afterpay.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
					wc_price( $limits ? $limits['max'] : 4000 )
				),
				'installment_info' => __( 'Pay in 4 interest-free installments', '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_afterpay_params', $this->id, $this->get_gateway_data() );

		// Add inline CSS for button visibility toggle (CSS body class approach).
		$inline_css = '
			/* Hide Place Order button when Afterpay is selected (classic and blocks checkout) */
			body.fkwcsq-afterpay-selected #place_order,
			body.fkwcsq-afterpay-selected .wfacp-order-place-btn-wrap,
			body.fkwcsq-afterpay-selected .wc-block-components-checkout-place-order-button {
				display: none !important;
			}

			/* Show Afterpay button wrapper when Afterpay is selected */
			body.fkwcsq-afterpay-selected #fkwcsq-afterpay-button-wrapper {
				display: block !important;
			}

			/* Hide Afterpay button wrapper by default */
			#fkwcsq-afterpay-button-wrapper {
				display: none;
			}

			#fkwcsq-afterpay-button-container {
				margin: 10px 0;
			}

			#fkwcsq-afterpay-messaging-container {
				margin-bottom: 10px;
				font-size: 14px;
			}

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

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

	/**
	 * Render Afterpay button wrapper after Place Order button.
	 * Button appears here when Afterpay is selected (controlled by CSS body class).
	 *
	 * @return void
	 */
	public function render_afterpay_button_wrapper() {

		if ( ! $this->is_available() ) {
			return;
		}
		?>
		<div id="fkwcsq-afterpay-button-wrapper" style="margin-top: 10px;">
			<div id="fkwcsq-afterpay-button-container"></div>
			<div id="fkwcsq-afterpay-error" class="fkwcsq-error" style="display: none; color: #dc3545; margin-top: 10px;"></div>
		</div>
		<?php
	}

	/**
	 * Render payment fields on checkout.
	 *
	 * @return void
	 */
	public function payment_fields() {
		if ( $this->description ) {
			echo '<p>' . wp_kses_post( $this->description ) . '</p>';
		}

		?>
		<div id="fkwcsq-afterpay-container">
			<div id="fkwcsq-afterpay-messaging-container"></div>
		</div>
		<input type="hidden" name="fkwcsq_afterpay_nonce" id="fkwcsq_afterpay_nonce" />
		<?php wp_nonce_field( 'fkwcsq_afterpay_payment', 'fkwcsq_afterpay_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_afterpay_wp_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['fkwcsq_afterpay_wp_nonce'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Missing, FKWCS.CodeAnalysis.FKWCSSpecific.MissingCapabilityCheck -- Checkout gateway, guest users allowed
			if ( ! wp_verify_nonce( $wp_nonce, 'fkwcsq_afterpay_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_afterpay_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['fkwcsq_afterpay_nonce'] ) ) : ''; //phpcs:ignore WordPress.Security.NonceVerification.Missing, FKWCS.CodeAnalysis.FKWCSSpecific.MissingCapabilityCheck -- WP nonce verified above, guest checkout allowed

		if ( empty( $nonce ) ) {
			wc_add_notice( __( 'Payment not completed. Please complete the Afterpay payment process.', 'funnelkit-payment-gateway-square-for-woocommerce' ), 'error' );
			return array( 'result' => 'failure' );
		}

		try {
			// Verify amount is within limits.
			$currency = $order->get_currency();
			$total    = $order->get_total();

			if ( ! $this->is_amount_within_limits( $total, $currency ) ) {
				$limits = $this->get_order_limits( $currency );
				throw new \Exception(
					sprintf(
						/* translators: 1: minimum amount, 2: maximum amount */
						__( 'Order total must be between %1$s and %2$s for Afterpay.', 'funnelkit-payment-gateway-square-for-woocommerce' ),
						wc_price( $limits['min'] ),
						wc_price( $limits['max'] )
					)
				);
			}

			$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', 'AFTERPAY' );
			$order->save();

			// Complete the payment.
			$order->payment_complete( $payment_id );

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

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

		} catch ( \Throwable $e ) {
			Logger::error( 'Afterpay 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_afterpay_' ),
			'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(),
		);

		// Add shipping address if different.
		if ( $order->has_shipping_address() ) {
			$payment_data['shipping_address'] = array(
				'first_name'                      => $order->get_shipping_first_name(),
				'last_name'                       => $order->get_shipping_last_name(),
				'address_line_1'                  => $order->get_shipping_address_1(),
				'locality'                        => $order->get_shipping_city(),
				'administrative_district_level_1' => $order->get_shipping_state(),
				'postal_code'                     => $order->get_shipping_postcode(),
				'country'                         => $order->get_shipping_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/pence).
	 */
	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' ) );
		}

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

		if ( is_wp_error( $response ) ) {
			Logger::error( 'Afterpay 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';

		$brand = $this->is_clearpay() ? 'Clearpay' : 'Afterpay';
		$order->add_order_note(
			sprintf(
				/* translators: 1: refund amount, 2: brand name, 3: Square refund ID */
				__( 'Refunded %1$s via Square %2$s. Refund ID: %3$s', 'funnelkit-payment-gateway-square-for-woocommerce' ),
				wc_price( $amount ),
				$brand,
				$refund_id
			)
		);

		return true;
	}

	/**
	 * Get gateway icon.
	 *
	 * @return string Icon HTML.
	 */
	public function get_icon() {
		$icon_url = $this->is_clearpay()
			? FKWCSQ_PLUGIN_URL . 'assets/images/clearpay.svg'
			: FKWCSQ_PLUGIN_URL . 'assets/images/afterpay.svg';

		$icon_html = '<img src="' . esc_url( $icon_url ) . '" alt="' . esc_attr( $this->get_title() ) . '" style="max-height: 24px; vertical-align: middle;" />';

		return apply_filters( 'woocommerce_gateway_icon', $icon_html, $this->id );
	}
}
