<?php

namespace Elementor_Pay_Addons\Stripe;

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

use Elementor_Pay_Addons\Shared\Logger;
use Elementor_Pay_Addons\Shared\Utils;
use Elementor_Pay_Addons\Stripe\Stripe_API;

// Exit if accessed directly
// refer from https://github.com/woocommerce/woocommerce-gateway-stripe/blob/develop/includes/class-wc-stripe-helper.php

class Stripe_Helper
{
  /**
   * Checks Stripe minimum order value authorized per currency
   */
  public static function get_minimum_amount($currency)
  {
    // Check order amount
    switch ($currency) {
      case 'USD':
      case 'CAD':
      case 'EUR':
      case 'CHF':
      case 'AUD':
      case 'SGD':
        $minimum_amount = 50;
        break;
      case 'GBP':
        $minimum_amount = 30;
        break;
      case 'DKK':
        $minimum_amount = 250;
        break;
      case 'NOK':
      case 'SEK':
        $minimum_amount = 300;
        break;
      case 'JPY':
        $minimum_amount = 5000;
        break;
      case 'MXN':
        $minimum_amount = 1000;
        break;
      case 'HKD':
        $minimum_amount = 400;
        break;
      default:
        $minimum_amount = 50;
        break;
    }

    return $minimum_amount;
  }

  /**
   * Gets all the saved setting options from a specific method.
   * If specific setting is passed, only return that.
   *
   * @since 4.0.0
   * @version 4.0.0
   * @param string $method The payment method to get the settings from.
   * @param string $setting The name of the setting to get.
   */
  public static function get_settings($method = null, $setting = null)
  {
    // $all_settings = null === $method ? get_option('woocommerce_stripe_settings', []) : get_option('woocommerce_stripe_' . $method . '_settings', []);

    // if (null === $setting) {
    //   return $all_settings;
    // }

    // return isset($all_settings[$setting]) ? $all_settings[$setting] : '';
  }

  /**
	 * Gets the webhook URL for Stripe triggers. Used mainly for
	 * asyncronous redirect payment methods in which statuses are
	 * not immediately chargeable.
	 *
	 * @since 4.0.0
	 * @version 4.0.0
	 * @return string
	 */
	public static function get_webhook_url() {
		// return add_query_arg( 'wc-api', 'wc_stripe', trailingslashit( get_home_url() ) );
	}

  /**
	 * Sanitize statement descriptor text.
	 *
	 * Stripe requires max of 22 characters and no special characters.
	 *
	 * @since 4.0.0
	 * @param string $statement_descriptor Statement descriptor.
	 * @return string $statement_descriptor Sanitized statement descriptor.
	 */
	public static function clean_statement_descriptor( $statement_descriptor = '' ) {
		$disallowed_characters = [ '<', '>', '\\', '*', '"', "'", '/', '(', ')', '{', '}' ];

		// Strip any tags.
		$statement_descriptor = wp_strip_all_tags( $statement_descriptor );

		// Strip any HTML entities.
		// Props https://stackoverflow.com/questions/657643/how-to-remove-html-special-chars .
		$statement_descriptor = preg_replace( '/&#?[a-z0-9]{2,8};/i', '', $statement_descriptor );

		// Next, remove any remaining disallowed characters.
		$statement_descriptor = str_replace( $disallowed_characters, '', $statement_descriptor );

		// Trim any whitespace at the ends and limit to 22 characters.
		$statement_descriptor = substr( trim( $statement_descriptor ), 0, 22 );

		return $statement_descriptor;
	}

  public static function convert_locale_to_stripe_locale( $wc_locale ) {
		// List copied from: https://stripe.com/docs/js/appendix/supported_locales.
		$supported = [
			'ar',     // Arabic.
			'bg',     // Bulgarian (Bulgaria).
			'cs',     // Czech (Czech Republic).
			'da',     // Danish.
			'de',     // German (Germany).
			'el',     // Greek (Greece).
			'en',     // English.
			'en-GB',  // English (United Kingdom).
			'es',     // Spanish (Spain).
			'es-419', // Spanish (Latin America).
			'et',     // Estonian (Estonia).
			'fi',     // Finnish (Finland).
			'fr',     // French (France).
			'fr-CA',  // French (Canada).
			'he',     // Hebrew (Israel).
			'hu',     // Hungarian (Hungary).
			'id',     // Indonesian (Indonesia).
			'it',     // Italian (Italy).
			'ja',     // Japanese.
			'lt',     // Lithuanian (Lithuania).
			'lv',     // Latvian (Latvia).
			'ms',     // Malay (Malaysia).
			'mt',     // Maltese (Malta).
			'nb',     // Norwegian Bokmål.
			'nl',     // Dutch (Netherlands).
			'pl',     // Polish (Poland).
			'pt-BR',  // Portuguese (Brazil).
			'pt',     // Portuguese (Brazil).
			'ro',     // Romanian (Romania).
			'ru',     // Russian (Russia).
			'sk',     // Slovak (Slovakia).
			'sl',     // Slovenian (Slovenia).
			'sv',     // Swedish (Sweden).
			'th',     // Thai.
			'tr',     // Turkish (Turkey).
			'zh',     // Chinese Simplified (China).
			'zh-HK',  // Chinese Traditional (Hong Kong).
			'zh-TW',  // Chinese Traditional (Taiwan).
		];

		// Stripe uses '-' instead of '_' (used in WordPress).
		$locale = str_replace( '_', '-', $wc_locale );

		if ( in_array( $locale, $supported, true ) ) {
			return $locale;
		}

		// The plugin has been fully translated for Spanish (Ecuador), Spanish (Mexico), and
		// Spanish(Venezuela), and partially (88% at 2021-05-14) for Spanish (Colombia).
		// We need to map these locales to Stripe's Spanish (Latin America) 'es-419' locale.
		// This list should be updated if more localized versions of Latin American Spanish are
		// made available.
		$lowercase_locale                  = strtolower( $wc_locale );
		$translated_latin_american_locales = [
			'es_co', // Spanish (Colombia).
			'es_ec', // Spanish (Ecuador).
			'es_mx', // Spanish (Mexico).
			'es_ve', // Spanish (Venezuela).
		];
		if ( in_array( $lowercase_locale, $translated_latin_american_locales, true ) ) {
			return 'es-419';
		}

		// Finally, we check if the "base locale" is available.
		$base_locale = substr( $wc_locale, 0, 2 );
		if ( in_array( $base_locale, $supported, true ) ) {
			return $base_locale;
		}

		// Default to 'auto' so Stripe.js uses the browser locale.
		return 'auto';
	}

	/**
   * Full whitelist of placeholder keys supported by the email system.
   * Any key listed here that has no registered value will be replaced with an empty string.
   *
   * @return string[]
   */
  public static function get_supported_placeholder_keys()
  {
    return [
      // Customer
      'customer.email',
      'customer.name',
      'customer.phone',
      'customer.address.country',
      'customer.address.state',
      'customer.address.city',
      'customer.address.line1',
      'customer.address.line2',
      'customer.address.postal_code',
      // Payment intent
      'payment_intent_id',
      'description',
      'currency',
      'amount',
      'created',
      'format_date',
      'format_time',
      'amount_currency',
      // Billing detail
      'billing_detail.email',
      'billing_detail.name',
      'billing_detail.phone',
      'billing_detail.address.country',
      'billing_detail.address.state',
      'billing_detail.address.city',
      'billing_detail.address.line1',
      'billing_detail.address.line2',
      'billing_detail.address.postal_code',
      'billing_detail.address.formatted',
      // Shipping detail
      'shipping_detail.name',
      'shipping_detail.phone',
      'shipping_detail.address.country',
      'shipping_detail.address.state',
      'shipping_detail.address.city',
      'shipping_detail.address.line1',
      'shipping_detail.address.line2',
      'shipping_detail.address.postal_code',
      'shipping_detail.address.formatted',
      // Payment method
      'payment_method.type',
      'payment_method.card.brand',
      'payment_method.card.last4',
      // Misc
      'receipt.url',
      'error.message',
    ];
  }

	public static function get_default_placeholders() {
		$placeholders = [];
		foreach (self::get_supported_placeholder_keys() as $key) {
			$placeholders[$key] = '';
		}
		return $placeholders;
	}

  public static function get_receipt_placeholders_sample() {
    $placeholder = [
      'format_date' => Utils::format_stripe_date(1614418416),
      'customer.email' => 'jenny@example.com',
      'amount_currency' => '$20',
      'payment_method.type'  => 'card',
      'payment_method.card.brand' => 'visa',
      'payment_method.card.last4' => '3212',
      'billing_detail.address.city' => 'Allendale',
      'billing_detail.address.country' => 'US',
      'billing_detail.address.line1' => '3811  Kimberly Way',
      'billing_detail.address.line2' => '',
      'billing_detail.address.postal_code' => '49401',
      'billing_detail.address.state' => 'MI',
      'billing_detail.name' => 'Jenny Rosen',
      'billing_detail.email' => 'jenny@example.com',
      'billing_detail.phone' => '619-419-9408',
    ];
    return $placeholder;
  }

  /**
   * Retrieve a Checkout Session and return its resolved payment intent,
   * falling back to invoice.payment_intent for subscription-based sessions.
   *
   * @param string $session_id Stripe Checkout Session ID.
   * @param array  $extra_expand Additional expand paths merged with the defaults.
   * @return array The expanded payment_intent object.
   */
  public static function get_payment_intent_from_session($session_id, $extra_expand = []) {
    $default_expand = [
      'customer',
      'payment_intent.payment_method',
      'payment_intent.latest_charge',
      'invoice.payment_intent.payment_method',
      'invoice.payment_intent.latest_charge',
    ];

    $session = Stripe_API::retrieve_checkout_session(
      $session_id,
      ['expand' => array_unique(array_merge($default_expand, $extra_expand))]
    );

    $payment_intent = $session['payment_intent'];

    if (empty($payment_intent)) {
      $payment_intent = $session['invoice']['payment_intent'];
    }

    return $payment_intent;
  }

  public static function get_receipt_placeholders_by_session($session_id) {
    $session = Stripe_API::retrieve_checkout_session(
      $session_id,
      [
        'expand' => [
          'customer',
          'payment_intent.payment_method',
          'payment_intent.latest_charge',
          'invoice.payment_intent.payment_method',
          'invoice.payment_intent.latest_charge',
        ]
      ]
    );

    $payment_intent = $session['payment_intent'];

    if(empty($payment_intent)) {
      $payment_intent = $session['invoice']['payment_intent'];
    }

    $placeholders = self::get_receipt_placeholders_by_payment_intent($payment_intent['id']);
    return $placeholders;
  }

	public static function get_receipt_placeholders_by_payment_intent($payment_intent_id, $last_payment_error = [])
	{
		// invoice doesn't exist for version 2024-06-07, so we use rest api directly.
			$payment_intent = Stripe_API::request([
					'expand' => [
							'customer',
							'payment_method',
							'latest_charge',
							'invoice.subscription',
					]
			], 'payment_intents/' . $payment_intent_id, 'GET');

			if (is_object($payment_intent)) {
					$payment_intent = json_decode(json_encode($payment_intent), true);
			}

			$placeholders = self::get_default_placeholders();
			$billDetail = $payment_intent['payment_method']['billing_details'];
			$shippingDetail = $payment_intent['shipping'];
			$charge = $payment_intent['latest_charge'];
			if (!empty($payment_intent['customer'])) {
					$customer = Stripe_API::retrieve_customer($payment_intent['customer']['id'], []);
					$placeholders['customer.email'] = $customer['email'];
					$placeholders['customer.name'] = $customer['name'];
					$placeholders['customer.phone'] = $customer['phone'];
          if (!empty($customer['address'])) {
              $placeholders['customer.address.country'] = $customer['address']['country'];
              $placeholders['customer.address.state'] = $customer['address']['state'];
              $placeholders['customer.address.city'] = $customer['address']['city'];
              $placeholders['customer.address.line1'] = $customer['address']['line1'];
              $placeholders['customer.address.line2'] = $customer['address']['line2'];
              $placeholders['customer.address.postal_code'] = $customer['address']['postal_code'];
          }
			}
			if (empty($placeholders['customer.name'])) {
					$placeholders['customer.name'] = $billDetail['name'];
			}
			if (empty($placeholders['customer.email'])) {
					$placeholders['customer.email'] = $billDetail['email'];
			}

			$placeholders['payment_intent_id'] = $payment_intent['id'];
			$placeholders['description'] = $payment_intent['description'];
			$placeholders['currency'] = $payment_intent['currency'];
			$placeholders['amount'] = Utils::format_stripe_amount($payment_intent['amount']);
			$placeholders['created'] = Utils::format_stripe_date($payment_intent['created']);
			$placeholders['format_date'] = Utils::format_stripe_date($payment_intent['created']);
			$placeholders['format_time'] = Utils::format_stripe_time($payment_intent['created']);
			$placeholders['amount_currency'] = Utils::format_amount_with_symbol($payment_intent['amount'], $payment_intent['currency']);
		  self::append_metadata_placeholder($payment_intent, $placeholders);
			$placeholders['billing_detail.address.country'] = $billDetail['address']['country'];
			$placeholders['billing_detail.address.state'] = $billDetail['address']['state'];
			$placeholders['billing_detail.address.city'] = $billDetail['address']['city'];
			$placeholders['billing_detail.address.line1'] = $billDetail['address']['line1'];
			$placeholders['billing_detail.address.line2'] = $billDetail['address']['line2'];
			$placeholders['billing_detail.address.postal_code'] = $billDetail['address']['postal_code'];
			$placeholders['billing_detail.address.formatted'] = Utils::get_formatted_address($billDetail['address']);
			$placeholders['billing_detail.email'] = $billDetail['email'];
			$placeholders['billing_detail.name'] = $billDetail['name'];
			$placeholders['billing_detail.phone'] = $billDetail['phone'];
			$placeholders['payment_method.type'] = $payment_intent['payment_method']['type'];
      if (!empty($payment_intent['payment_method']['card'])) {
        $placeholders['payment_method.card.brand'] = $payment_intent['payment_method']['card']['brand'];
        $placeholders['payment_method.card.last4'] = $payment_intent['payment_method']['card']['last4'];
      }

			if (!empty($shippingDetail)) {
					$placeholders['shipping_detail.address.country'] = $shippingDetail['address']['country'];
					$placeholders['shipping_detail.address.state'] = $shippingDetail['address']['state'];
					$placeholders['shipping_detail.address.city'] = $shippingDetail['address']['city'];
					$placeholders['shipping_detail.address.line1'] = $shippingDetail['address']['line1'];
					$placeholders['shipping_detail.address.line2'] = $shippingDetail['address']['line2'];
					$placeholders['shipping_detail.address.postal_code'] = $shippingDetail['address']['postal_code'];
					$placeholders['shipping_detail.address.formatted'] = Utils::get_formatted_address($shippingDetail['address']);
					$placeholders['shipping_detail.name'] = $shippingDetail['name'];
					$placeholders['shipping_detail.phone'] = $shippingDetail['phone'];
			}
			if (!empty($last_payment_error)) {
					$placeholders['error.message'] = $last_payment_error['message'];
			}

			$placeholders['receipt.url'] = $charge['receipt_url'];

			return $placeholders;
	}

  public static function append_metadata_placeholder($payment_intent, &$placeholders)
  {
      $payment_intent_metadata = $payment_intent['metadata'];
      foreach ($payment_intent_metadata as $k => $v) {
          $placeholders['metadata.' . $k] = $v;
      }
			// Get subscription metadata from invoice
			if(!empty($payment_intent['invoice']) && is_array($payment_intent['invoice'])) {
				if(!empty($payment_intent['invoice']['subscription']) && is_array($payment_intent['invoice']['subscription'])) {
					$subscription = $payment_intent['invoice']['subscription'];
					if(!empty($subscription['metadata'])) {
						$subscription_metadata = $subscription['metadata'];
						foreach ($subscription_metadata as $k => $v) {
								$placeholders['metadata.' . $k] = $v;
						}
					}
				}
			}
  }

  /**
   * Retrieve the Subscription associated with a PaymentIntent, if any.
   *
   * Handles both legacy Stripe API (invoice.subscription) and the newer format
   * (invoice.parent.type === 'subscription_details') introduced in 2025-x.
   * Always returns a plain PHP array (never a Stripe SDK object), or null when
   * the PaymentIntent is not linked to a subscription.
   *
   * @param array|object $intent A Stripe PaymentIntent (array or StripeObject).
   * @return array|null
   */
  public static function get_subscription_from_payment_intent($intent): ?array
  {
      $invoice_id = $intent['invoice'] ?? null;
      if (!$invoice_id) {
          return null;
      }

      // Expand the subscription inline to avoid a second API call.
      $invoice = Stripe_API::retrieve_invoice(
          is_object($invoice_id) ? $invoice_id->id : $invoice_id,
          ['expand' => ['subscription', 'parent.subscription_details.subscription']]
      );

      // New API: invoice.parent.type === 'subscription_details'
      if (($invoice['parent']['type'] ?? null) === 'subscription_details') {
          $sub_field = $invoice['parent']['subscription_details']['subscription'] ?? null;
      } else {
          // Legacy API: subscription was a top-level field on the invoice.
          $sub_field = $invoice['subscription'] ?? null;
      }

      if (!$sub_field) {
          return null;
      }

      // $sub_field may be an expanded StripeObject or a bare ID string.
      $subscription = is_string($sub_field)
          ? Stripe_API::retrieve_subscription($sub_field, [])
          : $sub_field;

      // Normalise to a plain array so callers can safely cast/iterate.
      if (is_object($subscription) && method_exists($subscription, 'toArray')) {
          $subscription = $subscription->toArray();
      }

      return $subscription ?: null;
  }

  public static function format_price($price) {
    if(isset($price['recurring']) && $price['recurring']) {
      $recurring_amount = Utils::format_amount_with_symbol($price['unit_amount'], $price['currency']);
      $recurring_interval = $price['recurring']['interval_count'] == 1 ? $price['recurring']['interval'] : $price['recurring']['interval_count'] . ' '. $price['recurring']['interval'];
      return $recurring_amount . '/' . $recurring_interval; 
    }
    return Utils::format_amount_with_symbol($price['unit_amount'], $price['currency']); 
  }

  public static function get_price_item_list($search_term = '') {
    $prices = get_transient('epa_stripe_price_list');
    if (false === $prices) {
      try {
        $prices = Stripe_API::retrieve_prices();
        set_transient('epa_stripe_price_list', $prices, 15 * MINUTE_IN_SECONDS);
      } catch (\Exception $ex) {
        Logger::error('retrieve_prices ' . $ex->getMessage());
      }
    }

    $results = [];
    if (isset($prices->data)) {
      foreach ($prices->data as $price) {
        $label = $price['product']['name'] . ' - ' . Stripe_Helper::format_price($price);

        // Filter by search term if provided
        if (empty($search_term) || stripos($label, $search_term) !== false) {
          $results[] = [
            'id' => $price['id'],
            'text' => $label
          ];
        }
      }
    }
    return $results;
  }
}
