<?php
/**
 * Stripe payment gateway (automatic recurring).
 *
 * @package Lucrativeit_Subscription_Recurring_Billing
 */

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

/**
 * Stripe gateway. Supports automatic recurring billing: the card is charged
 * automatically each cycle and no invoice email is sent.
 *
 * This implementation performs the Stripe API hand-off via the Checkout/
 * PaymentIntents REST endpoints. Secret keys are stored encrypted-at-rest by
 * WordPress options; live charging requires valid API keys configured in
 * Settings → Payment Gateways.
 */
class LUCRSURE_Stripe_Gateway extends LUCRSURE_Abstract_Gateway {

	/**
	 * Constructor.
	 */
	public function __construct() {
		$this->id                  = 'stripe';
		$this->title               = __( 'Stripe', 'lucrativeit-subscription-recurring-billing' );
		$this->automatic_recurring = true;
	}

	/**
	 * {@inheritDoc}
	 */
	public function is_enabled() {
		$config = $this->config();
		if ( empty( $config['enabled'] ) ) {
			return false;
		}

		$secret_key = isset( $config['secret_key'] ) ? trim( (string) $config['secret_key'] ) : '';

		return '' !== $secret_key;
	}

	/**
	 * Create a Stripe Checkout session for the invoice.
	 *
	 * @param array $invoice Invoice row.
	 * @return array
	 */
	public function create_payment( array $invoice ) {
		$config     = $this->config();
		$secret_key = isset( $config['secret_key'] ) ? $config['secret_key'] : '';

		if ( empty( $secret_key ) ) {
			return array(
				'success'            => false,
				'payment_url'        => '',
				'gateway_payment_id' => '',
				'message'            => __( 'Stripe secret key is not configured.', 'lucrativeit-subscription-recurring-billing' ),
			);
		}

		$amount   = (int) round( (float) $invoice['amount'] * 100 );
		$currency = strtolower( $invoice['currency'] );

		$response = wp_remote_post(
			'https://api.stripe.com/v1/checkout/sessions',
			array(
				'timeout' => 30,
				'headers' => array(
					'Authorization' => 'Bearer ' . $secret_key,
				),
				'body'    => array(
					'mode'                                 => 'payment',
					'success_url'                          => home_url( '/?lucrsure_payment=success&invoice=' . rawurlencode( $invoice['invoice_number'] ) . '&lucrsure_gateway=stripe&session_id={CHECKOUT_SESSION_ID}' ),
					'cancel_url'                           => home_url( '/?lucrsure_payment=cancel&invoice=' . rawurlencode( $invoice['invoice_number'] ) ),
					'client_reference_id'                  => $invoice['invoice_number'],
					'metadata[lucrsure_invoice_number]'         => $invoice['invoice_number'],
					'line_items[0][quantity]'              => 1,
					'line_items[0][price_data][currency]'  => $currency,
					'line_items[0][price_data][unit_amount]' => $amount,
					'line_items[0][price_data][product_data][name]' => 'Invoice ' . $invoice['invoice_number'],
				),
			)
		);

		if ( is_wp_error( $response ) ) {
			return array(
				'success'            => false,
				'payment_url'        => '',
				'gateway_payment_id' => '',
				'message'            => $response->get_error_message(),
			);
		}

		$body = json_decode( wp_remote_retrieve_body( $response ), true );

		if ( empty( $body['url'] ) ) {
			$message = isset( $body['error']['message'] ) ? $body['error']['message'] : __( 'Stripe session could not be created.', 'lucrativeit-subscription-recurring-billing' );
			return array(
				'success'            => false,
				'payment_url'        => '',
				'gateway_payment_id' => '',
				'message'            => $message,
			);
		}

		return array(
			'success'            => true,
			'payment_url'        => $body['url'],
			'gateway_payment_id' => isset( $body['id'] ) ? $body['id'] : '',
			'message'            => __( 'Stripe checkout session created.', 'lucrativeit-subscription-recurring-billing' ),
		);
	}

	/**
	 * Create a Stripe Checkout session in subscription mode. Stripe saves the
	 * customer's card and charges it automatically on each billing cycle, so
	 * renewals are handled natively by Stripe (confirmed back via webhook).
	 *
	 * @param array $args {
	 *     @type float  $amount            Per-cycle amount.
	 *     @type string $currency          Currency code.
	 *     @type string $interval          day|week|month|year.
	 *     @type int    $interval_count    Interval multiplier.
	 *     @type int    $trial_days        Trial length in days (0 for none).
	 *     @type string $customer_email    Customer email.
	 *     @type string $product_name      Plan name.
	 *     @type int    $subscription_id   Local subscription id (client_reference_id).
	 *     @type string $invoice_number    First invoice number (metadata).
	 * }
	 * @return array { success, payment_url, gateway_payment_id, message }
	 */
	public function create_recurring_checkout( array $args ) {
		$config     = $this->config();
		$secret_key = isset( $config['secret_key'] ) ? $config['secret_key'] : '';

		if ( empty( $secret_key ) ) {
			return array(
				'success'            => false,
				'payment_url'        => '',
				'gateway_payment_id' => '',
				'message'            => __( 'Stripe secret key is not configured.', 'lucrativeit-subscription-recurring-billing' ),
			);
		}

		$amount   = (int) round( (float) $args['amount'] * 100 );
		$currency = strtolower( $args['currency'] );
		$interval = in_array( $args['interval'], array( 'day', 'week', 'month', 'year' ), true ) ? $args['interval'] : 'month';

		$body = array(
			'mode'                => 'subscription',
			'success_url'         => home_url( '/?lucrsure_payment=success&invoice=' . rawurlencode( $args['invoice_number'] ) . '&lucrsure_gateway=stripe&session_id={CHECKOUT_SESSION_ID}' ),
			'cancel_url'          => home_url( '/?lucrsure_payment=cancel&invoice=' . rawurlencode( $args['invoice_number'] ) ),
			'client_reference_id' => (string) $args['subscription_id'],
			'customer_email'      => $args['customer_email'],

			'line_items[0][quantity]'                         => 1,
			'line_items[0][price_data][currency]'             => $currency,
			'line_items[0][price_data][unit_amount]'          => $amount,
			'line_items[0][price_data][product_data][name]'   => $args['product_name'],
			'line_items[0][price_data][recurring][interval]'  => $interval,
			'line_items[0][price_data][recurring][interval_count]' => max( 1, (int) $args['interval_count'] ),

			'subscription_data[metadata][lucrsure_subscription_id]' => (string) $args['subscription_id'],
			'metadata[lucrsure_subscription_id]'                    => (string) $args['subscription_id'],
			'metadata[lucrsure_invoice_number]'                     => $args['invoice_number'],
		);

		if ( ! empty( $args['trial_days'] ) ) {
			$body['subscription_data[trial_period_days]'] = (int) $args['trial_days'];
		}

		$response = wp_remote_post(
			'https://api.stripe.com/v1/checkout/sessions',
			array(
				'timeout' => 30,
				'headers' => array( 'Authorization' => 'Bearer ' . $secret_key ),
				'body'    => $body,
			)
		);

		if ( is_wp_error( $response ) ) {
			return array(
				'success'            => false,
				'payment_url'        => '',
				'gateway_payment_id' => '',
				'message'            => $response->get_error_message(),
			);
		}

		$data = json_decode( wp_remote_retrieve_body( $response ), true );

		if ( empty( $data['url'] ) ) {
			$message = isset( $data['error']['message'] ) ? $data['error']['message'] : __( 'Stripe subscription session could not be created.', 'lucrativeit-subscription-recurring-billing' );
			return array(
				'success'            => false,
				'payment_url'        => '',
				'gateway_payment_id' => '',
				'message'            => $message,
			);
		}

		return array(
			'success'            => true,
			'payment_url'        => $data['url'],
			'gateway_payment_id' => isset( $data['id'] ) ? $data['id'] : '',
			'message'            => __( 'Stripe subscription checkout created.', 'lucrativeit-subscription-recurring-billing' ),
		);
	}

	/**
	 * Retrieve a Checkout Session from Stripe.
	 *
	 * @param string $session_id Checkout session id (cs_...).
	 * @return array|null Decoded session or null on failure.
	 */
	public function retrieve_checkout_session( $session_id ) {
		$session_id = sanitize_text_field( (string) $session_id );
		if ( ! preg_match( '/^cs_[A-Za-z0-9_]+$/', $session_id ) ) {
			return null;
		}

		$config     = $this->config();
		$secret_key = isset( $config['secret_key'] ) ? $config['secret_key'] : '';
		if ( empty( $secret_key ) ) {
			return null;
		}

		$response = wp_remote_get(
			'https://api.stripe.com/v1/checkout/sessions/' . rawurlencode( $session_id ),
			array(
				'timeout' => 30,
				'headers' => array(
					'Authorization' => 'Bearer ' . $secret_key,
				),
			)
		);

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

		$body = json_decode( wp_remote_retrieve_body( $response ), true );
		if ( empty( $body['id'] ) ) {
			return null;
		}

		return $body;
	}

	/**
	 * Complete a Stripe Checkout return: verify the session with Stripe and
	 * mark the local invoice paid (and activate the subscription when needed).
	 *
	 * Safe to call more than once — mark_invoice_paid is idempotent.
	 *
	 * @param string $session_id Checkout session id from the success URL.
	 * @return bool True when the invoice was found and processed (or already paid).
	 */
	public function complete_checkout_return( $session_id ) {
		$session = $this->retrieve_checkout_session( $session_id );
		if ( ! $session ) {
			return false;
		}

		$status         = isset( $session['status'] ) ? $session['status'] : '';
		$payment_status = isset( $session['payment_status'] ) ? $session['payment_status'] : '';

		// Require a completed session. unpaid/no_payment (e.g. free trial) is
		// still a successful checkout for subscription mode.
		if ( 'complete' !== $status ) {
			return false;
		}
		if ( ! in_array( $payment_status, array( 'paid', 'no_payment_required' ), true ) ) {
			return false;
		}

		$invoices = new LUCRSURE_Invoice_Repository();
		$subs     = new LUCRSURE_Subscription_Repository();
		$engine   = LUCRSURE_Billing_Engine::instance();

		$invoice = $invoices->find_by_gateway_payment( isset( $session['id'] ) ? $session['id'] : '' );

		if ( ! $invoice ) {
			$number = '';
			if ( ! empty( $session['metadata']['lucrsure_invoice_number'] ) ) {
				$number = (string) $session['metadata']['lucrsure_invoice_number'];
			} elseif ( ! empty( $session['client_reference_id'] ) && 'payment' === ( $session['mode'] ?? '' ) ) {
				$number = (string) $session['client_reference_id'];
			}
			if ( '' !== $number ) {
				$invoice = $invoices->find_by_number( $number );
			}
		}

		$mode         = isset( $session['mode'] ) ? $session['mode'] : 'payment';
		$local_sub_id = 0;
		$stripe_sub   = isset( $session['subscription'] ) ? (string) $session['subscription'] : '';

		if ( 'subscription' === $mode ) {
			if ( ! empty( $session['client_reference_id'] ) ) {
				$local_sub_id = (int) $session['client_reference_id'];
			} elseif ( ! empty( $session['metadata']['lucrsure_subscription_id'] ) ) {
				$local_sub_id = (int) $session['metadata']['lucrsure_subscription_id'];
			}

			if ( $local_sub_id && $stripe_sub ) {
				$subs->update(
					$local_sub_id,
					array(
						'gateway_subscription_id' => $stripe_sub,
					)
				);
			}

			if ( ! $invoice && $local_sub_id ) {
				$invoice = $invoices->find_latest_for_subscription( $local_sub_id );
			}
		}

		if ( ! $invoice ) {
			return false;
		}

		// Persist the Stripe session id when we matched via metadata/number.
		if ( empty( $invoice['gateway_payment_id'] ) && ! empty( $session['id'] ) ) {
			$invoices->update(
				(int) $invoice['id'],
				array( 'gateway_payment_id' => $session['id'] )
			);
		}

		$engine->mark_invoice_paid( (int) $invoice['id'] );

		return true;
	}
}
