<?php
/**
 * Fetch payment status from ConvesioPay and update order status.
 *
 * Adds a "Fetch payment status" button on WooCommerce edit order for ConvesioPay card, Apple Pay, and crypto.
 * Fetches from ConvesioPay API and updates order status using the same logic as Reconciliation and Webhooks.
 *
 * @package PeachPay
 */

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

/**
 * ConvesioPay Fetch Payment Status Manually Admin class.
 */
class PeachPay_ConvesioPay_Fetch_Payment_Status_Manually {

	/**
	 * ConvesioPay payment methods that show the Fetch payment status button.
	 *
	 * @var array
	 */
	private static $allowed_methods = array( 'peachpay_convesiopay_card', 'peachpay_convesiopay_applepay', 'peachpay_convesiopay_googlepay', 'peachpay_convesiopay_btcpay' );

	/**
	 * ConvesioPay order statuses that trigger order update.
	 *
	 * @var array
	 */
	private static $convesiopay_order_statuses = array( 'Succeeded', 'Failed', 'Blocked', 'Refunded', 'Cancelled', 'Disputed' );

	/**
	 * Constructor.
	 */
	public function __construct() {
		add_action( 'woocommerce_order_item_add_action_buttons', array( $this, 'add_fetch_payment_status_button' ) );
		add_action( 'wp_ajax_peachpay_convesiopay_fetch_payment_status', array( $this, 'handle_ajax_fetch_payment_status' ) );
		add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
	}

	/**
	 * Add "Fetch payment status" button on order edit (ConvesioPay card / Apple Pay / crypto).
	 *
	 * @param WC_Order $order Order object.
	 */
	public function add_fetch_payment_status_button( $order ) {
		if ( ! in_array( $order->get_payment_method(), self::$allowed_methods, true ) ) {
			return;
		}

		$payment_id = $order->get_meta( '_convesiopay_payment_id' );
		if ( empty( $payment_id ) ) {
			return;
		}

		$order_id = $order->get_id();
		echo ' ';
		echo '<button type="button" class="button peachpay-convesiopay-fetch-status-btn" ';
		echo 'data-order-id="' . esc_attr( (string) $order_id ) . '" ';
		echo 'title="' . esc_attr__( 'Fetch current payment status from ConvesioPay and update order if needed', 'peachpay-for-woocommerce' ) . '">';
		echo esc_html__( 'Fetch payment status', 'peachpay-for-woocommerce' );
		echo '</button>';
		echo '<span class="peachpay-convesiopay-fetch-status-loading" style="display: none; margin-left: 10px;">';
		echo '<span class="spinner is-active"></span> ';
		echo esc_html__( 'Fetching...', 'peachpay-for-woocommerce' );
		echo '</span>';
	}

	/**
	 * AJAX handler: fetch payment status from ConvesioPay and update order.
	 */
	public function handle_ajax_fetch_payment_status() {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			wp_send_json_error( array( 'message' => __( 'Unauthorized.', 'peachpay-for-woocommerce' ) ) );
		}

		if ( empty( $_POST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'peachpay_convesiopay_fetch_status_manually' ) ) {
			wp_send_json_error( array( 'message' => __( 'Invalid security check.', 'peachpay-for-woocommerce' ) ) );
		}

		$order_id = isset( $_POST['order_id'] ) ? absint( $_POST['order_id'] ) : 0;
		if ( ! $order_id ) {
			wp_send_json_error( array( 'message' => __( 'Invalid order.', 'peachpay-for-woocommerce' ) ) );
		}

		$result = $this->fetch_and_apply_payment_status( $order_id );

		if ( ! empty( $result['success'] ) ) {
			wp_send_json_success( array(
				'message' => isset( $result['message'] ) ? $result['message'] : '',
				'status'  => isset( $result['status'] ) ? $result['status'] : '',
				'updated' => ! empty( $result['updated'] ),
			) );
		}

		wp_send_json_error( array( 'message' => isset( $result['message'] ) ? $result['message'] : __( 'Failed to fetch payment status.', 'peachpay-for-woocommerce' ) ) );
	}

	/**
	 * Fetch payment from ConvesioPay API and apply status to order (same logic as reconciliation/webhooks).
	 *
	 * @param int $order_id WC order ID.
	 * @return array{ success: bool, message?: string, status?: string, updated?: bool }
	 */
	private function fetch_and_apply_payment_status( $order_id ) {
		try {
			$order = wc_get_order( $order_id );
			if ( ! $order ) {
				return array( 'success' => false, 'message' => __( 'Order not found.', 'peachpay-for-woocommerce' ) );
			}

			if ( ! in_array( $order->get_payment_method(), self::$allowed_methods, true ) ) {
				return array( 'success' => false, 'message' => __( 'Order is not a ConvesioPay card, Apple Pay, or crypto payment.', 'peachpay-for-woocommerce' ) );
			}

			$payment_id = $order->get_meta( '_convesiopay_payment_id' );
			if ( empty( $payment_id ) ) {
				return array( 'success' => false, 'message' => __( 'No ConvesioPay payment ID on this order.', 'peachpay-for-woocommerce' ) );
			}

			$payment_data = $this->fetch_payment_from_api( $payment_id );
			if ( $payment_data === false ) {
				return array( 'success' => false, 'message' => __( 'Could not fetch payment status from ConvesioPay.', 'peachpay-for-woocommerce' ) );
			}

			$status = isset( $payment_data['status'] ) ? trim( (string) $payment_data['status'] ) : '';
			$status_lower = strtolower( $status );
			$convesiopay_order_statuses_lower = array_map( 'strtolower', self::$convesiopay_order_statuses );

			$updated = false;
			if ( in_array( $status_lower, $convesiopay_order_statuses_lower, true ) ) {
				$order = wc_get_order( $order_id );
				if ( $order ) {
					$this->apply_status_to_order( $order, $status, $payment_data, $payment_id );
					$updated = true;
				}
			}

			$message = $updated
				? sprintf( __( 'Payment status: %s. Order updated accordingly.', 'peachpay-for-woocommerce' ), $status )
				: sprintf( __( 'Payment status: %s.', 'peachpay-for-woocommerce' ), $status );

			return array( 'success' => true, 'status' => $status, 'updated' => $updated, 'message' => $message );
		} catch ( \Throwable $e ) {
			return array( 'success' => false, 'message' => $e->getMessage() );
		}
	}

	/**
	 * Fetch payment from ConvesioPay API (GET /payments/{id}).
	 *
	 * @param string $payment_id Payment ID.
	 * @return array|false Parsed response on success, false on failure.
	 */
	private function fetch_payment_from_api( $payment_id ) {
		try {
			if ( ! class_exists( 'PeachPay_ConvesioPay_Integration' ) ) {
				return false;
			}
			$config = PeachPay_ConvesioPay_Integration::config();
			$api_url = isset( $config['api_url'] ) ? $config['api_url'] : '';
			$secret  = isset( $config['secret_key'] ) ? $config['secret_key'] : '';
			if ( empty( $api_url ) || empty( $secret ) ) {
				return false;
			}

			$url = rtrim( $api_url, '/' ) . '/payments/' . $payment_id;
			$response = wp_remote_get( $url, array(
				'headers' => array(
					'Authorization' => $secret,
					'Content-Type'  => 'application/json',
				),
				'timeout' => 30,
			) );

			if ( is_wp_error( $response ) ) {
				if ( function_exists( 'peachpay_log' ) ) {
					peachpay_log( 'error', 'PeachPay Fetch Status: GET payment failed - ' . $response->get_error_message() . ' (payment ' . $payment_id . ')' );
				}
				return false;
			}
			$code = wp_remote_retrieve_response_code( $response );
			$body = wp_remote_retrieve_body( $response );
			if ( $code !== 200 ) {
				if (function_exists('peachpay_log')) {
					peachpay_log(
						'error',
						'Failed to fetch payment status from ConvesioPay Api',
						array(
							'event'     => 'payments.convesiopay_admin.payment.fetch.failed',
							'component' => 'payments',
							'feature'   => 'convesiopay_admin',
							'operation' => 'payment.fetch',
							'outcome'   => 'failed',
							'method'    => __METHOD__,
							'line'      => __LINE__,
							'data'      => array(
								'details' => '',
								'response_code' => $code,
								'response_body' => json_decode($body, true),
								'payment_id' => $payment_id,
							)
						)
					);
				}
				return false;
			}

			$data = json_decode( $body, true );
			if ( ! is_array( $data ) || empty( $data['status'] ) ) {
				if (function_exists('peachpay_log')) {
					peachpay_log(
						'error',
						'Failed to fetch payment status from ConvesioPay Api',
						array(
							'event'     => 'payments.convesiopay_admin.payment.fetch.failed',
							'component' => 'payments',
							'feature'   => 'convesiopay_admin',
							'operation' => 'payment.fetch',
							'outcome'   => 'failed',
							'method'    => __METHOD__,
							'line'      => __LINE__,
							'data'      => array(
								'details' => 'The response is not a valid JSON or missing status',
								'response_body' => json_decode($body, true),
								'payment_id' => $payment_id,
							)
						)
					);
				}
				return false;
			}
			return $data;
		} catch ( \Throwable $e ) {
			return false;
		}
	}

	/**
	 * Apply ConvesioPay status to WC order (same logic as reconciliation/webhooks).
	 *
	 * @param WC_Order $order        Order.
	 * @param string   $status       ConvesioPay status.
	 * @param array    $payment_data GET /payments response.
	 * @param string   $payment_id   Payment ID.
	 */
	private function apply_status_to_order( $order, $status, $payment_data, $payment_id ) {
		try {
			$order = wc_get_order( $order->get_id() );
			if ( ! $order ) {
				return;
			}

			$payment_method = $this->get_payment_method_from_response( $payment_data );
			$normalized = strtolower( $status );

			switch ( $normalized ) {
				case 'succeeded':
					$this->handle_payment_success( $order, $payment_id, $payment_data, $payment_method );
					break;
				case 'cancelled':
					$this->handle_payment_cancelled( $order, $payment_id );
					break;
				case 'failed':
				case 'blocked':
				case 'disputed':
					$this->handle_payment_failure( $order, $payment_id, $payment_data );
					break;
				case 'refunded':
					$this->handle_payment_refund( $order, $payment_id, $payment_data );
					break;
				default:
					if ( function_exists( 'peachpay_convesiopay_dashboard_url' ) ) {
						$payment_url = peachpay_convesiopay_dashboard_url() . '/payments/' . $payment_id;
						$order->add_order_note( "ConvesioPay: unknown status $status (Payment ID: $payment_id) | <a href=\"$payment_url\" target=\"_blank\">View Payment</a>" );
					}
					break;
			}
		} catch ( \Throwable $e ) {
			// Silent; caller will report generic failure.
		}
	}

	/**
	 * Derive payment method from GET /payments response.
	 *
	 * @param array $payment_data GET /payments response.
	 * @return string
	 */
	private function get_payment_method_from_response( $payment_data ) {
		$details   = $payment_data['paymentMethodDetails'] ?? array();
		$type      = $details['type'] ?? '';
		$brand     = $details['brand'] ?? '';
		$cardholder = $details['cardHolderName'] ?? '';
		$method    = $type;
		if ( $type === 'card' && ! empty( $brand ) ) {
			$method = $brand;
		} elseif ( $type === 'card' && $brand === '' && $cardholder === 'Apple Pay PlaceHolder' ) {
			$method = 'applepay';
		} elseif ( $type === 'card' && $brand === '' && $cardholder === 'Google Pay PlaceHolder' ) {
			$method = 'googlepay';
		}
		return $method;
	}

	/**
	 * Get payment method title for display.
	 *
	 * Resolves `peachpay_convesiopay_unified` to the correct sub-gateway via
	 * order meta before looking up the title from the WC gateway registry.
	 *
	 * @param WC_Order $order Order object.
	 * @return string
	 */
	private function get_payment_method_title( $order ) {
		$gateway_id = $order->get_payment_method();

		if ( empty( $gateway_id ) || 'peachpay_convesiopay_unified' === $gateway_id ) {
			$resolved = $this->resolve_sub_gateway_id( $order );
			if ( ! empty( $resolved ) ) {
				$gateway_id = $resolved;
			}
		}

		$wc = function_exists( 'WC' ) ? WC() : null;
		if ( empty( $gateway_id ) || ! $wc || ! $wc->payment_gateways() ) {
			return $order->get_payment_method_title() ?: 'ConvesioPay';
		}

		$gateways = $wc->payment_gateways()->payment_gateways();

		if ( ! isset( $gateways[ $gateway_id ] ) ) {
			return $order->get_payment_method_title() ?: 'ConvesioPay';
		}

		$gateway = $gateways[ $gateway_id ];
		return $gateway ? $gateway->get_title() : ( $order->get_payment_method_title() ?: 'ConvesioPay' );
	}

	/**
	 * Resolve the actual sub-gateway ID from order meta.
	 *
	 * @param WC_Order $order Order object.
	 * @return string Sub-gateway ID or empty string.
	 */
	private function resolve_sub_gateway_id( $order ) {
		$payment_type = $order->get_meta( '_convesiopay_payment_type' );
		if ( empty( $payment_type ) ) {
			$payment_type = $order->get_meta( '_convesiopay_payment_method' );
		}
		if ( empty( $payment_type ) || ! is_string( $payment_type ) ) {
			return '';
		}

		$normalized = strtolower( trim( $payment_type ) );

		if ( in_array( $normalized, array( 'applepay', 'apple_pay', 'apple-pay', 'apple pay' ), true ) ) {
			return 'peachpay_convesiopay_applepay';
		}
		if ( in_array( $normalized, array( 'btcpay', 'btc_pay', 'btc-pay', 'crypto' ), true ) ) {
			return 'peachpay_convesiopay_btcpay';
		}
		if ( in_array( $normalized, array( 'googlepay', 'google_pay', 'google-pay', 'gpay' ), true ) ) {
			return 'peachpay_convesiopay_googlepay';
		}
		$card_values = array( 'card', 'visa', 'mastercard', 'amex', 'discover', 'mc', 'diners', 'jcb', 'unionpay', 'cup', 'elo', 'hiper', 'hipercard', 'cartesbancaires' );
		if ( in_array( $normalized, $card_values, true ) ) {
			return 'peachpay_convesiopay_card';
		}

		if ( strpos( $normalized, 'peachpay_convesiopay_' ) === 0 ) {
			return $payment_type;
		}

		return '';
	}

	/**
	 * Handle payment success: update order to processing, meta, notes.
	 *
	 * @param WC_Order $order          Order.
	 * @param string   $payment_id     Payment ID.
	 * @param array    $payment_data   Payment data.
	 * @param string   $payment_method Payment method.
	 */
	private function handle_payment_success( $order, $payment_id, $payment_data, $payment_method ) {
		if ( $order->has_status( array( 'processing', 'completed', 'refunded' ) ) ) {
			return;
		}

		$order->update_meta_data( '_convesiopay_payment_status', 'captured' );

		if ( function_exists( 'peachpay_convesiopay_dashboard_url' ) ) {
			$payment_url = peachpay_convesiopay_dashboard_url() . '/payments/' . $payment_id;
			$note = sprintf( 'ConvesioPay payment successful. Payment ID: %s | <a href="%s" target="_blank">View Payment</a>', $payment_id, $payment_url );
			if ( isset( $payment_data['amount'], $payment_data['currency'] ) ) {
				$amount = $payment_data['amount'];
				$formatted = ( is_numeric( $amount ) && $amount >= 50 ) ? number_format( $amount / 100, 2 ) : $amount;
				$note .= sprintf( ' Amount: %s %s', $formatted, $payment_data['currency'] );
			}
			$order->add_order_note( $note );
		}

		if ( empty( $order->get_meta( '_convesiopay_original_payment_id' ) ) ) {
			$order->update_meta_data( '_convesiopay_original_payment_id', $payment_id );
		}
		$order->update_meta_data( '_convesiopay_payment_id', $payment_id );
		if ( ! empty( $payment_method ) ) {
			$order->update_meta_data( '_convesiopay_payment_method', $payment_method );
		}

		$customer_id = $payment_data['customerId'] ?? '';
		$payment_method_details = $payment_data['paymentMethodDetails'] ?? array();
		$stored_payment_method_id = $payment_method_details['storedPaymentMethodId'] ?? '';
		if ( ! empty( $customer_id ) ) {
			$order->update_meta_data( '_convesiopay_customer_id', $customer_id );
			$user_id = $order->get_user_id();
			if ( $user_id ) {
				update_user_meta( $user_id, '_convesiopay_customer_id', $customer_id );
			}
		}
		if ( ! empty( $stored_payment_method_id ) ) {
			$order->update_meta_data( '_convesiopay_stored_payment_method_id', $stored_payment_method_id );
			$user_id = $order->get_user_id();
			if ( $user_id ) {
				update_user_meta( $user_id, '_convesiopay_stored_payment_method_id', $stored_payment_method_id );
				update_user_meta( $user_id, '_convesiopay_payment_method_details', $payment_method_details );
			}
		}

		$order->set_payment_method_title( $this->get_payment_method_title( $order ) );
		$order->set_transaction_id( $payment_id );
		$order->update_status( 'processing', __( 'Payment completed via ConvesioPay (Manually Fetched Status).', 'peachpay-for-woocommerce' ) );
		$order->save();
	}

	/**
	 * Handle cancelled payment.
	 *
	 * @param WC_Order $order      Order.
	 * @param string   $payment_id Payment ID.
	 */
	private function handle_payment_cancelled( $order, $payment_id ) {
		if ( function_exists( 'peachpay_convesiopay_dashboard_url' ) ) {
			$payment_url = peachpay_convesiopay_dashboard_url() . '/payments/' . $payment_id;
			$note = sprintf( 'ConvesioPay payment cancelled. Payment ID: %s | <a href="%s" target="_blank">View Payment</a>', $payment_id, $payment_url );
			$order->add_order_note( $note );
		}
		$order->update_meta_data( '_convesiopay_payment_id', $payment_id );
		$order->set_transaction_id( $payment_id );
		$order->update_status( 'cancelled', __( 'Payment cancelled via ConvesioPay (Fetch payment status).', 'peachpay-for-woocommerce' ) );
		$order->save();
	}

	/**
	 * Handle failed payment.
	 *
	 * @param WC_Order $order        Order.
	 * @param string   $payment_id   Payment ID.
	 * @param array    $payment_data Payment data.
	 */
	private function handle_payment_failure( $order, $payment_id, $payment_data ) {
		$error_message = $payment_data['errorMessage'] ?? $payment_data['failureReason'] ?? $payment_data['reason'] ?? $payment_data['message'] ?? __( 'Payment failed', 'peachpay-for-woocommerce' );
		$error_code = $payment_data['errorCode'] ?? $payment_data['code'] ?? '';

		$payment_status = $order->get_meta( '_convesiopay_payment_status' );
		if ( $payment_status === 'failed' ) {
			return;
		}

		if ( function_exists( 'peachpay_convesiopay_dashboard_url' ) ) {
			$payment_url = peachpay_convesiopay_dashboard_url() . '/payments/' . $payment_id;
			$note = sprintf( 'ConvesioPay payment failed. Payment ID: %s. Error: %s | <a href="%s" target="_blank">View Payment</a>', $payment_id, $error_message, $payment_url );
			if ( $error_code ) {
				$note .= sprintf( ' (Code: %s)', $error_code );
			}
			$order->add_order_note( $note );
		}
		$order->update_meta_data( '_convesiopay_failure_reason', $error_message );
		$order->update_status( 'failed', __( 'Payment failed via ConvesioPay (Manually Fetched Status): ', 'peachpay-for-woocommerce' ) . $error_message );
		$order->save();
	}

	/**
	 * Handle refund: notes, meta, create WC refund if needed, update order status.
	 *
	 * @param WC_Order $order        Order.
	 * @param string   $payment_id   Payment ID (refund transaction ID).
	 * @param array    $payment_data Payment data.
	 */
	private function handle_payment_refund( $order, $payment_id, $payment_data ) {
		try {
			$refund_amount_cents = $payment_data['amount'] ?? 0;
			$currency = $payment_data['currency'] ?? $order->get_currency();
			$refund_amount = $refund_amount_cents / 100;

			$refunds = $order->get_refunds();
			$woocommerce_initiated = false;
			foreach ( $refunds as $existing_refund ) {
				if ( $existing_refund->get_meta( '_convesiopay_refund_id' ) === $payment_id ) {
					$woocommerce_initiated = true;
					break;
				}
				$existing_refund_amount = abs( $existing_refund->get_amount() );
				if ( abs( $existing_refund_amount - $refund_amount ) < 0.01 ) {
					$existing_refund->update_meta_data( '_convesiopay_refund_id', $payment_id );
					$existing_refund->save();
					$woocommerce_initiated = true;
					break;
				}
			}

			if ( $woocommerce_initiated ) {
				$order->update_meta_data( '_convesiopay_payment_id', $payment_id );
				$order->update_meta_data( '_convesiopay_refund_id', $payment_id );
				$order->set_transaction_id( $payment_id );
				$order->save();
				return;
			}

			if ( function_exists( 'peachpay_convesiopay_dashboard_url' ) ) {
				$payment_url = peachpay_convesiopay_dashboard_url() . '/payments/' . $payment_id;
				$order->add_order_note( sprintf(
					'ConvesioPay refund from Dashboard. Refund ID: %s, Amount: %s %s | <a href="%s" target="_blank">View Payment</a>',
					$payment_id,
					number_format( $refund_amount, 2 ),
					$currency,
					$payment_url
				) );
			}

			$order->update_meta_data( '_convesiopay_payment_id', $payment_id );
			$order->update_meta_data( '_convesiopay_refund_id', $payment_id );
			$order->update_meta_data( '_convesiopay_last_refund_amount', $refund_amount );
			$order->set_transaction_id( $payment_id );
			$order->save();

			$wc_refund = wc_create_refund( array(
				'order_id' => $order->get_id(),
				'amount'   => $refund_amount,
				'reason'   => sprintf( 'ConvesioPay Dashboard refund - ID: %s', $payment_id ),
			) );
			if ( $wc_refund && ! is_wp_error( $wc_refund ) ) {
				$wc_refund->update_meta_data( '_convesiopay_refund_id', $payment_id );
				$wc_refund->save();
			}

			$order = wc_get_order( $order->get_id() );
			if ( $order ) {
				$total_refunded = $order->get_total_refunded();
				$order_total = $order->get_total();
				if ( $total_refunded >= $order_total ) {
					$order->update_status( 'refunded', __( 'Order fully refunded via ConvesioPay (Manually Fetched Status).', 'peachpay-for-woocommerce' ) );
				} else {
					$order->add_order_note( sprintf(
						'Partial refund: %s %s of %s %s total',
						number_format( $total_refunded, 2 ),
						$currency,
						number_format( $order_total, 2 ),
						$currency
					) );
				}
				$order->save();
			}
		} catch ( \Throwable $e ) {
			// Silent.
		}
	}

	/**
	 * Enqueue script for Fetch payment status button on order edit.
	 *
	 * @param string $hook Current admin hook.
	 */
	public function enqueue_scripts( $hook ) {
		if ( ! is_admin() ) {
			return;
		}
		$is_order_screen = (
			strpos( $hook, 'wc-orders' ) !== false
			|| $hook === 'post.php'
			|| ( isset( $_GET['page'] ) && $_GET['page'] === 'wc-orders' )
		);
		if ( ! $is_order_screen ) {
			return;
		}

		$script_url = plugin_dir_url( __FILE__ ) . 'assets/js/fetch-payment-status-manually.js';
		wp_enqueue_script(
			'peachpay-convesiopay-fetch-payment-status-manually',
			$script_url,
			array( 'jquery' ),
			'1.0.2',
			true
		);
		wp_localize_script( 'peachpay-convesiopay-fetch-payment-status-manually', 'peachpayConvesiopayFetchStatusManually', array(
			'ajaxUrl' => admin_url( 'admin-ajax.php' ),
			'nonce'   => wp_create_nonce( 'peachpay_convesiopay_fetch_status_manually' ),
		) );
	}
}

new PeachPay_ConvesioPay_Fetch_Payment_Status_Manually();
