<?php

class OsStripeConnectHelper {
	public static $default_currency_iso_code = 'usd';
	public static $error                     = false;

	public static $stripe         = false;
	public static $processor_code = 'stripe_connect';


	public static function add_all_payment_methods_to_payment_times( array $payment_times ): array {
		$payment_methods = self::get_supported_payment_methods();
		foreach ( $payment_methods as $payment_method_code => $payment_method_info ) {
			$payment_times[ LATEPOINT_PAYMENT_TIME_NOW ][ $payment_method_code ][ self::$processor_code ] = $payment_method_info;
		}
		return $payment_times;
	}

	public static function add_enabled_payment_methods_to_payment_times( array $payment_times ): array {
		if ( OsPaymentsHelper::is_payment_processor_enabled( self::$processor_code ) ) {
			$payment_times = self::add_all_payment_methods_to_payment_times( $payment_times );
		}
		return $payment_times;
	}


	public static function process_refund( $transaction_refund, OsTransactionModel $transaction, $custom_amount = null ) {
		if ( $transaction->processor != self::$processor_code ) {
			return $transaction_refund;
		}

		if ( ! $transaction->can_refund() ) {
			throw new Exception( 'Invalid Transaction' );
		}

		$refund_data = [
			'payment_intent_id' => $transaction->token,
		];
		if ( $custom_amount ) {
			$refund_data['custom_amount'] = self::convert_amount_to_specs( $custom_amount );
		}

		$response = self::do_account_request( 'refunds', OsSettingsHelper::get_payments_environment(), '', 'POST', $refund_data );

		if ( empty( $response['data'] ) ) {
			throw new Exception( __( 'Error Refunding', 'latepoint' ) );
		}

		$transaction_refund                 = new OsTransactionRefundModel();
		$transaction_refund->transaction_id = $transaction->id;
		$transaction_refund->amount         = self::convert_amount_back_from_specs_to_db_format( $response['data']['amount'] );
		$transaction_refund->token          = $response['data']['id'];
		if ( $transaction_refund->save() ) {
			/**
			 * Transaction refund was issued
			 *
			 * @param {OsTransactionRefundModel} $transaction_refund instance of transaction refund model that was issued
			 *
			 * @since 5.1.0
			 * @hook latepoint_transaction_refund_created
			 *
			 */
			do_action( 'latepoint_transaction_refund_created', $transaction_refund );
			return $transaction_refund;
		} else {
			throw new Exception( implode( ', ', $transaction_refund->get_error_messages() ) );
		}
	}

	public static function output_stripe_link_on_customer_quick_form( OsCustomerModel $customer ) {
		$stripe_customer_id = self::get_stripe_customer_id( $customer );
		if ( $stripe_customer_id ) {
			echo '<div class="payment-processor-customer-link-wrapper">' . esc_html__( 'Stripe Customer', 'latepoint' ) . '<a target="_blank" href="' . esc_url( self::build_customer_profile_link( $stripe_customer_id, OsSettingsHelper::is_env_payments_dev() ) ) . '">' . esc_html__( 'Open in Stripe', 'latepoint' ) . '</a></div>';
		}
	}

	public static function convert_transaction_intent_charge_amount_to_specs( $amount, OsTransactionIntentModel $transaction_intent ) {
		if ( OsPaymentsHelper::should_processor_handle_payment_for_transaction_intent( self::$processor_code, $transaction_intent ) ) {
			$amount = self::convert_amount_to_specs( $amount );
		}
		return $amount;
	}

	public static function process_payment_for_transaction_intent( $result, OsTransactionIntentModel $transaction_intent ) {
		if ( OsPaymentsHelper::should_processor_handle_payment_for_transaction_intent( self::$processor_code, $transaction_intent ) ) {
			switch ( $transaction_intent->get_payment_data_value( 'method' ) ) {
				case 'payment_element':
					if ( $transaction_intent->get_payment_data_value( 'token' ) ) {
						// since the payment is already processed on the frontend - we need to retrieve payment intent and verify if its paid
						$payment_intent_data = self::retrieve_payment_intent( $transaction_intent->get_payment_data_value( 'token' ) );
						if ( in_array( $payment_intent_data['status'], [ 'succeeded', 'requires_capture' ] ) ) {
							if ( ! self::validate_payment_intent_amount( $payment_intent_data, $transaction_intent->charge_amount ) ) {
								$result['status']  = LATEPOINT_STATUS_ERROR;
								$result['message'] = __( 'Payment amount mismatch', 'latepoint' );
								OsDebugHelper::log( 'Stripe PI amount mismatch for transaction intent ' . $transaction_intent->id, 'stripe_connect_error' );
								$transaction_intent->add_error( 'payment_error', $result['message'] );
								break;
							}
							// success
							$result['status']    = LATEPOINT_STATUS_SUCCESS;
							$result['processor'] = self::$processor_code;
							$result['charge_id'] = $payment_intent_data['id'];
							$result['amount']    = $payment_intent_data['total'];
							$result['kind']      = $payment_intent_data['status'] == 'requires_capture' ? LATEPOINT_TRANSACTION_KIND_AUTHORIZATION : LATEPOINT_TRANSACTION_KIND_CAPTURE;
						} else {
							// payment error
							$result['status']  = LATEPOINT_STATUS_ERROR;
							$result['message'] = __( 'Payment Error', 'latepoint' );
							$transaction_intent->add_error( 'send_to_step', $result['message'], 'payment' );
						}
					} else {
						// payment token missing
						$result['status']  = LATEPOINT_STATUS_ERROR;
						$result['message'] = __( 'Payment Error 23JDF38', 'latepoint' );
						$transaction_intent->add_error( 'payment_error', $result['message'] );
					}
					break;
			}
		}

		return $result;
	}


	public static function process_payment( $result, OsOrderIntentModel $order_intent ) {
		if ( OsPaymentsHelper::should_processor_handle_payment_for_order_intent( self::$processor_code, $order_intent ) ) {
			switch ( $order_intent->get_payment_data_value( 'method' ) ) {
				case 'payment_element':
					if ( $order_intent->get_payment_data_value( 'token' ) ) {
						// since the payment is already processed on the frontend - we need to retrieve payment intent and verify if its paid
						$payment_intent_data = self::retrieve_payment_intent( $order_intent->get_payment_data_value( 'token' ) );
						if ( in_array( $payment_intent_data['status'], [ 'succeeded', 'requires_capture' ] ) ) {
							if ( ! self::validate_payment_intent_amount( $payment_intent_data, $order_intent->charge_amount ) ) {
								$result['status']  = LATEPOINT_STATUS_ERROR;
								$result['message'] = __( 'Payment amount mismatch', 'latepoint' );
								OsDebugHelper::log( 'Stripe PI amount mismatch for order intent ' . $order_intent->id, 'stripe_connect_error' );
								$order_intent->add_error( 'payment_error', $result['message'] );
								$order_intent->add_error( 'send_to_step', $result['message'], 'payment' );
								break;
							}
							// success
							$result['status']    = LATEPOINT_STATUS_SUCCESS;
							$result['processor'] = self::$processor_code;
							$result['charge_id'] = $payment_intent_data['id'];
							$result['amount']    = $payment_intent_data['total'];
							$result['kind']      = $payment_intent_data['status'] == 'requires_capture' ? LATEPOINT_TRANSACTION_KIND_AUTHORIZATION : LATEPOINT_TRANSACTION_KIND_CAPTURE;
						} else {
							// payment error
							$result['status']  = LATEPOINT_STATUS_ERROR;
							$result['message'] = __( 'Payment Error', 'latepoint' );
							$order_intent->add_error( 'payment_error', $result['message'] );
							$order_intent->add_error( 'send_to_step', $result['message'], 'payment' );
						}
					} else {
						// payment token missing
						$result['status']  = LATEPOINT_STATUS_ERROR;
						$result['message'] = __( 'Payment Error 23JDF38', 'latepoint' );
						$order_intent->add_error( 'payment_error', $result['message'] );
					}
					break;
			}
		}
		return $result;
	}


	public static function convert_charge_amount_to_requirements( $charge_amount, OsCartModel $cart ) {
		if ( OsPaymentsHelper::should_processor_handle_payment_for_cart( self::$processor_code, $cart ) ) {
			$charge_amount = self::convert_amount_to_specs( $charge_amount );
		}
		return $charge_amount;
	}

	public static function convert_amount_to_specs( $charge_amount ) {
		$iso_code = self::get_currency_iso_code();
		if ( in_array( $iso_code, self::zero_decimal_currencies_list() ) ) {
			$charge_amount = round( $charge_amount );
		} else {
			$number_of_decimals = OsSettingsHelper::get_settings_value( 'number_of_decimals', '2' );
			$charge_amount      = number_format( (float) $charge_amount, $number_of_decimals, '.', '' ) * pow( 10, $number_of_decimals );
		}
		return $charge_amount;
	}

	/**
	 * Converts amount from Stripe to database format
	 *
	 * @param $charge_amount
	 *
	 * @return mixed|string
	 */
	public static function convert_amount_back_from_specs_to_db_format( $charge_amount ) {
		$iso_code           = self::get_currency_iso_code();
		$number_of_decimals = OsSettingsHelper::get_settings_value( 'number_of_decimals', '2' );
		if ( ! in_array( $iso_code, self::zero_decimal_currencies_list() ) && ! empty( $number_of_decimals ) ) {
			$charge_amount = $charge_amount / pow( 10, $number_of_decimals );
			$charge_amount = number_format( (float) $charge_amount, 4, '.', '' );
		} else {
			$charge_amount = OsMoneyHelper::pad_to_db_format( $charge_amount );
		}
		return $charge_amount;
	}


	public static function output_order_payment_pay_contents( OsTransactionIntentModel $transaction_intent ) {
		if ( ! OsPaymentsHelper::should_processor_handle_payment_for_transaction_intent( self::$processor_code, $transaction_intent ) ) {
			return;
		}
		echo '<div class="lp-payment-method-content" data-payment-method="payment_element">';
		echo '<div class="lp-payment-method-content-i">';
		echo '<div class="stripe-payment-element"></div>';
		echo '</div>';
		echo '</div>';
	}

	public static function output_payment_step_contents( OsCartModel $cart ) {
		if ( ! OsPaymentsHelper::should_processor_handle_payment_for_cart( self::$processor_code, $cart ) ) {
			return;
		}
		echo '<div class="lp-payment-method-content" data-payment-method="payment_element">';
		echo '<div class="lp-payment-method-content-i">';
		echo '<div class="stripe-payment-element"></div>';
		echo '</div>';
		echo '</div>';
	}


	public static function get_supported_payment_methods(): array {
		return [
			'payment_element' => [
				'name'      => __( 'Payment Element', 'latepoint' ),
				'label'     => __( 'Credit Card', 'latepoint' ),
				'image_url' => LATEPOINT_IMAGES_URL . 'payment_cards.png',
			],
		];
	}

	public static function register_payment_processor( array $payment_processors ): array {
		$payment_processors[ self::$processor_code ] = [
			'code'       => self::$processor_code,
			'name'       => __( 'Stripe Connect', 'latepoint' ),
			'front_name' => __( 'Stripe', 'latepoint' ),
			'image_url'  => LATEPOINT_IMAGES_URL . 'processor-stripe-connect.png',
		];
		return $payment_processors;
	}

	public static function add_settings_fields( $processor_code ) {
		if ( $processor_code != self::$processor_code ) {
			return false;
		} ?>
		<div class="sub-section-row">
			<div class="sub-section-label">
				<h3><?php esc_html_e( 'Connect (Live)', 'latepoint' ); ?></h3>
			</div>
			<div class="sub-section-content">
				<div data-env="<?php echo esc_attr( LATEPOINT_PAYMENTS_ENV_LIVE ); ?>"
					 class="payment-processor-connect-status-wrapper stripe-connect-status-wrapper"
					 data-route-name="<?php echo esc_attr( OsRouterHelper::build_route_name( 'stripe_connect', 'check_connect_status' ) ); ?>">
					<div class="os-loading-spinner"></div>
				</div>
			</div>
		</div>
		<div class="sub-section-row">
			<div class="sub-section-label">
				<h3><?php esc_html_e( 'Connect (Dev)', 'latepoint' ); ?></h3>
			</div>
			<div class="sub-section-content">
				<div data-env="<?php echo esc_attr( LATEPOINT_PAYMENTS_ENV_DEV ); ?>"
					 class="payment-processor-connect-status-wrapper stripe-connect-status-wrapper"
					 data-route-name="<?php echo esc_attr( OsRouterHelper::build_route_name( 'stripe_connect', 'check_connect_status' ) ); ?>">
					<div class="os-loading-spinner"></div>
				</div>
			</div>
		</div>
		<div class="sub-section-row">
			<div class="sub-section-label">
				<h3><?php esc_html_e( 'Other Settings', 'latepoint' ); ?></h3>
			</div>
			<div class="sub-section-content">
				<?php
				$selected_stripe_country_code      = OsSettingsHelper::get_settings_value( 'stripe_connect_country_code', 'US' );
				$selected_stripe_currency_iso_code = OsSettingsHelper::get_settings_value( 'stripe_connect_currency_iso_code', 'usd' ); ?>
				<div class="os-row os-mb-2">
					<div class="os-col-6">
						<?php echo OsFormHelper::select_field( 'settings[stripe_connect_country_code]', __( 'Country', 'latepoint' ), self::load_countries_list(), $selected_stripe_country_code ); ?>
					</div>
					<div class="os-col-6">
						<?php echo OsFormHelper::select_field( 'settings[stripe_connect_currency_iso_code]', __( 'Currency Code', 'latepoint' ), OsStripeConnectHelper::load_all_currencies_list(), $selected_stripe_currency_iso_code ); ?>
					</div>
				</div>
			</div>
		</div>
		<?php
	}

	public static function get_stripe_customer_id( OsCustomerModel $customer ) {
		return $customer->get_meta_by_key( OsSettingsHelper::append_payment_env_key( 'stripe_connect_customer_id' ), '' );
	}

	public static function save_stripe_customer_id( OsCustomerModel $customer, string $stripe_customer_id ) {
		return $customer->save_meta_by_key( OsSettingsHelper::append_payment_env_key( 'stripe_connect_customer_id' ), $stripe_customer_id );
	}


	public static function get_customer( $stripe_customer_id ): \LatePoint\Misc\StripeConnectCustomer {
		$response                    = self::do_account_request( "customers/{$stripe_customer_id}" );
		$stripe_connect_customer     = new \LatePoint\Misc\StripeConnectCustomer();
		$stripe_connect_customer->id = $response['data']['id'];
		return $stripe_connect_customer;
	}

	public static function update_customer( $stripe_customer_id, $customer, $values_to_update = array() ) {
		$stripe_customer = self::get_customer( $stripe_customer_id );
		if ( $stripe_customer && $values_to_update ) {
			foreach ( $values_to_update as $key => $value ) {
				if ( in_array( $key, self::get_properties_allowed_to_update() ) ) {
					$stripe_customer->$key = $value;
				}
			}
			$stripe_customer->save();
		}
		return $stripe_customer;
	}

	public static function create_customer( $customer ) {
		$customer_data = [
			'email' => $customer->email,
			'name'  => $customer->full_name,
		];
		$response      = self::do_account_request( 'customers', OsSettingsHelper::get_payments_environment(), '', 'POST', $customer_data );
		$result        = [ 'id' => $response['data']['customer_id'] ];
		return $result;
	}


	public static function get_currency_iso_code() {
		return OsSettingsHelper::get_settings_value( 'stripe_connect_currency_iso_code', self::$default_currency_iso_code );
	}

	public static function get_server_token( string $force_env = '' ): string {
		$key          = OsSettingsHelper::append_payment_env_key( 'server_token_for_stripe_connect', $force_env );
		$server_token = OsSettingsHelper::get_settings_value( $key, '' );
		if ( empty( $server_token ) ) {
			$server_token = OsUtilHelper::generate_uuid();
			OsSettingsHelper::save_setting_by_name( $key, $server_token );
		}
		return $server_token;
	}

	public static function reset_server_token( string $force_env = '' ): string {
		$key              = OsSettingsHelper::append_payment_env_key( 'server_token_for_stripe_connect', $force_env );
		$new_server_token = OsUtilHelper::generate_uuid();
		OsSettingsHelper::save_setting_by_name( $key, $new_server_token );
		return $new_server_token;
	}

	public static function get_connect_url( string $env = '' ) {
		$url  = LATEPOINT_STRIPE_CONNECT_URL . '/wp/stripe-connection/' . $env . '/start/';
		$url .= self::get_server_token( $env ) . '/' . base64_encode( implode( '|||', [ get_bloginfo( 'name' ), get_site_icon_url(), OsUtilHelper::get_site_url() ] ) );
		return $url;
	}


	public static function do_account_request( string $path, string $env = '', string $connection_data = '', string $method = 'GET', array $vars = [], array $headers = [] ) {
		if ( empty( $env ) ) {
			$env = OsSettingsHelper::get_payments_environment();
		}
		$path = self::get_connect_account_id( $env ) . '/' . $path;
		try {
			return self::do_request( $path, $connection_data, $method, $vars, $headers );
		} catch ( \Exception $e ) {
			OsDebugHelper::log( 'Error processing request to Stripe: ' . $e->getMessage(), 'stripe_connect_error' );
			return [];
		}
	}

	public static function do_request( string $path, string $connection_data = '', string $method = 'GET', array $vars = [], array $headers = [], string $force_env = '' ) {

		$default_vars    = [];
		$default_headers = [
			'latepoint-version'     => LATEPOINT_VERSION,
			'latepoint-domain'      => OsUtilHelper::get_site_url(),
			'latepoint-license-key' => OsLicenseHelper::get_license_key(),
		];

		if ( ! empty( $connection_data ) ) {
			$default_headers['connection-data'] = $connection_data;
		}


		$args = array(
			'timeout'   => 15,
			'headers'   => array_merge( $default_headers, $headers ),
			'body'      => array_merge( $default_vars, $vars ),
			'sslverify' => false,
			'method'    => $method,
		);


		// in our connect server we use test/live, while latepoint plugin uses dev/live
		if ( ! empty( $force_env ) && in_array( $force_env, [ LATEPOINT_PAYMENTS_ENV_DEV, LATEPOINT_PAYMENTS_ENV_LIVE ] ) ) {
			$env = ( $force_env == LATEPOINT_PAYMENTS_ENV_DEV ) ? 'test' : 'live';
		} else {
			$env = ( OsSettingsHelper::is_env_payments_dev() ? 'test' : 'live' );
		}
		$url = LATEPOINT_STRIPE_CONNECT_URL . "/api/wp/v1/stripe-connect/{$env}/{$path}";

		$response = wp_remote_request( $url, $args );

		if ( ! is_wp_error( $response ) ) {
			$data           = json_decode( wp_remote_retrieve_body( $response ), true );
			$data['status'] = $response['response'];
			return $data;
		} else {
			$error_message = $response->get_error_message();
			throw new Exception( $error_message );
		}
	}


	public static function get_connection_buttons_and_status( string $env = '' ) {
		$stripe_connect_account_id   = OsSettingsHelper::get_settings_value( OsSettingsHelper::append_payment_env_key( 'stripe_connect_account_id', $env ), false );
		$html                        = '';
		$duplicate_token_activations = OsSettingsHelper::get_settings_value( OsSettingsHelper::append_payment_env_key( 'stripe_connect_duplicate_token_activations', $env ), '' );
		if ( ! empty( $duplicate_token_activations ) ) {
			$html .= '<div class="latepoint-fix-records-warning"><i class="latepoint-icon latepoint-icon-info"></i><div>';
			$html .= '<div>' . __( 'The following websites are using the same server token. This can happen if a site was cloned from one server to another. To fix this, disconnect each site and reconnect it. When you disconnect a connection, a new token is generated that can then be used safely.', 'latepoint' ) . '</div>';
			$html .= '<div class="latepoint-fix-records-values">' . $duplicate_token_activations . '</div>';
			$html .= '</div></div>';
		}
		$html .= '<div class="payment-processor-connect-status-inner">';
		if ( $stripe_connect_account_id ) {
			$charges_enabled = OsSettingsHelper::is_on( OsSettingsHelper::append_payment_env_key( 'stripe_connect_charges_enabled', $env ) );
			$disconnect_link = '<a class="payment-processor-disconnect-link" href="#"
										data-os-pass-response="yes"
										data-os-pass-this="yes"
		                data-os-before-after="none"
		                data-os-after-call="latepointStripeConnectAdmin.reload_connect_status_wrapper"
		                data-os-params="' . esc_attr( OsUtilHelper::build_os_params( [ 'env' => $env ], 'stripe_disconnect_account' ) ) . '"
										data-os-action="' . OsRouterHelper::build_route_name( 'stripe_connect', 'disconnect_connect_account' ) . '"
										><i class="latepoint-icon latepoint-icon-x"></i><span>' . __( 'disconnect', 'latepoint' ) . '</span></a>';
			if ( $charges_enabled ) {
				$html .= '<div class="payment-processor-status-connected"><i class="latepoint-icon latepoint-icon-check"></i><span>' . __( 'Connected', 'latepoint' ) . '</span></div>';
				$html .= $disconnect_link;
				$html .= '<div class="stripe-connect-account-info">' . __( 'Account: ', 'latepoint' ) . $stripe_connect_account_id . '</div>';
				if ( $env == 'live' && ! empty( OsSettingsHelper::get_settings_value( 'stripe_connect_transaction_fee_info', '' ) ) ) {
					$html .= '<div class="fee-disclosure-wrapper">
                        <div class="fee-disclosure">' . OsSettingsHelper::get_settings_value( 'stripe_connect_transaction_fee_info', '' ) . ' transaction fee. <a target="_blank" href="https://wpdocs.latepoint.com/understanding-payment-processing-fees/"><span>Pricing</span> <i class="latepoint-icon latepoint-icon-external-link"></i></a></div>
                    </div>';
				}
			} else {
				$html .= '<div class="payment-processor-status-charges-disabled"><i class="latepoint-icon latepoint-icon-clock"></i><span>' . __( 'Pending Action', 'latepoint' ) . '</span></div>';
				$html .= '<a data-env="' . $env . '" data-route-name="' . OsRouterHelper::build_route_name( 'stripe_connect', 'start_connect_process' ) . '" href="#" class="payment-start-connecting"><span>' . __( 'Continue Setup', 'latepoint' ) . '</span><i class="latepoint-icon latepoint-icon-arrow-right"></i></a>';
				$html .= '<div class="stripe-connect-account-info">';
				$html .= '<div>' . $stripe_connect_account_id . '</div>';
				$html .= $disconnect_link;
				$html .= '</div>';
			}
		} else {
			$html .= '<a data-env="' . $env . '" data-route-name="' . OsRouterHelper::build_route_name( 'stripe_connect', 'start_connect_process' ) . '" href="#" class="payment-start-connecting"><span>' . __( 'Start Connecting', 'latepoint' ) . '</span><i class="latepoint-icon latepoint-icon-arrow-right"></i></a>';
		}
		$html .= '</div>';
		return $html;
	}

	public static function retrieve_payment_intent( string $payment_intent_id ): array {
		$payment_request_data = self::do_account_request( 'payment-intents/' . $payment_intent_id, OsSettingsHelper::get_payments_environment() );
		$result               = [
			'id'     => $payment_request_data['data']['id'],
			'status' => $payment_request_data['data']['status'],
			'total'  => $payment_request_data['data']['total'],
		];
		return $result;
	}

	public static function validate_payment_intent_amount( array $payment_intent_data, string $expected_charge_amount ): bool {
		$expected_in_specs  = (int) self::convert_amount_to_specs( $expected_charge_amount );
		$actual_from_stripe = (int) $payment_intent_data['total'];
		return abs( $expected_in_specs - $actual_from_stripe ) <= 1;
	}

	private static function get_properties_allowed_to_update( $roles = 'admin' ) {
		return array( 'source', 'email', 'name' );
	}

	public static function get_connect_publishable_key(): string {
		$key = OsSettingsHelper::get_settings_value( OsSettingsHelper::append_payment_env_key( 'stripe_connect_publishable_key' ), '' );
		if ( empty( $key ) ) {
			$response = self::do_request( 'public-key/' );
			$key      = $response['data']['key'];
			OsSettingsHelper::save_setting_by_name( OsSettingsHelper::append_payment_env_key( 'stripe_connect_publishable_key' ), $key );
		}
		return $key;
	}

	public static function zero_decimal_currencies_list() {
		return array( 'bif', 'clp', 'djf', 'gnf', 'jpy', 'kmf', 'krw', 'mga', 'pyg', 'rwf', 'ugx', 'vnd', 'vuv', 'xaf', 'xof', 'xpf' );
	}


	public static function load_countries_list() {
		$country_codes = [
			'AU' => 'Australia',
			'AT' => 'Austria',
			'BE' => 'Belgium',
			'BR' => 'Brazil',
			'BG' => 'Bulgaria',
			'CA' => 'Canada',
			'HR' => 'Croatia',
			'CY' => 'Cyprus',
			'CZ' => 'Czech Republic',
			'DK' => 'Denmark',
			'EE' => 'Estonia',
			'FI' => 'Finland',
			'FR' => 'France',
			'DE' => 'Germany',
			'GI' => 'Gibraltar',
			'GR' => 'Greece',
			'HK' => 'Hong Kong',
			'HU' => 'Hungary',
			'IN' => 'India',
			'IE' => 'Ireland',
			'IT' => 'Italy',
			'JP' => 'Japan',
			'LV' => 'Latvia',
			'LI' => 'Liechtenstein',
			'LT' => 'Lithuania',
			'LU' => 'Luxembourg',
			'MY' => 'Malaysia',
			'MT' => 'Malta',
			'MX' => 'Mexico',
			'NL' => 'Netherlands',
			'NZ' => 'New Zealand',
			'NO' => 'Norway',
			'PL' => 'Poland',
			'PT' => 'Portugal',
			'RO' => 'Romania',
			'SG' => 'Singapore',
			'SK' => 'Slovakia',
			'SI' => 'Slovenia',
			'ES' => 'Spain',
			'SE' => 'Sweden',
			'CH' => 'Switzerland',
			'TH' => 'Thailand',
			'AE' => 'United Arab Emirates',
			'GB' => 'United Kingdom',
			'US' => 'United States',
		];
		return $country_codes;
	}


	public static function load_all_currencies_list(): array {
		return [
			'usd' => 'United States Dollar',
			'aed' => 'United Arab Emirates Dirham',
			'afn' => 'Afghan Afghani',
			'all' => 'Albanian Lek',
			'amd' => 'Armenian Dram',
			'ang' => 'Netherlands Antillean Guilder',
			'aoa' => 'Angolan Kwanza',
			'ars' => 'Argentine Peso',
			'aud' => 'Australian Dollar',
			'awg' => 'Aruban Florin',
			'azn' => 'Azerbaijani Manat',
			'bam' => 'Bosnia-Herzegovina Convertible Mark',
			'bbd' => 'Barbadian Dollar',
			'bdt' => 'Bangladeshi Taka',
			'bgn' => 'Bulgarian Lev',
			'bif' => 'Burundian Franc',
			'bmd' => 'Bermudian Dollar',
			'bnd' => 'Brunei Dollar',
			'bob' => 'Bolivian Boliviano',
			'brl' => 'Brazilian Real',
			'bsd' => 'Bahamian Dollar',
			'bwp' => 'Botswana Pula',
			'bzd' => 'Belize Dollar',
			'cad' => 'Canadian Dollar',
			'cdf' => 'Congolese Franc',
			'chf' => 'Swiss Franc',
			'clp' => 'Chilean Peso',
			'cny' => 'Chinese Yuan',
			'cop' => 'Colombian Peso',
			'crc' => 'Costa Rican Colón',
			'cve' => 'Cape Verdean Escudo',
			'czk' => 'Czech Koruna',
			'djf' => 'Djiboutian Franc',
			'dkk' => 'Danish Krone',
			'dop' => 'Dominican Peso',
			'dzd' => 'Algerian Dinar',
			'egp' => 'Egyptian Pound',
			'etb' => 'Ethiopian Birr',
			'eur' => 'Euro',
			'fjd' => 'Fijian Dollar',
			'fkp' => 'Falkland Islands Pound',
			'gbp' => 'British Pound Sterling',
			'gel' => 'Georgian Lari',
			'gip' => 'Gibraltar Pound',
			'gmd' => 'Gambian Dalasi',
			'gnf' => 'Guinean Franc',
			'gtq' => 'Guatemalan Quetzal',
			'gyd' => 'Guyanese Dollar',
			'hkd' => 'Hong Kong Dollar',
			'hnl' => 'Honduran Lempira',
			'hrk' => 'Croatian Kuna',
			'htg' => 'Haitian Gourde',
			'huf' => 'Hungarian Forint',
			'idr' => 'Indonesian Rupiah',
			'ils' => 'Israeli New Shekel',
			'inr' => 'Indian Rupee',
			'isk' => 'Icelandic Króna',
			'jmd' => 'Jamaican Dollar',
			'jpy' => 'Japanese Yen',
			'kes' => 'Kenyan Shilling',
			'kgs' => 'Kyrgyzstani Som',
			'khr' => 'Cambodian Riel',
			'kmf' => 'Comorian Franc',
			'krw' => 'South Korean Won',
			'kyd' => 'Cayman Islands Dollar',
			'kzt' => 'Kazakhstani Tenge',
			'lak' => 'Lao Kip',
			'lbp' => 'Lebanese Pound',
			'lkr' => 'Sri Lankan Rupee',
			'lrd' => 'Liberian Dollar',
			'lsl' => 'Lesotho Loti',
			'mad' => 'Moroccan Dirham',
			'mdl' => 'Moldovan Leu',
			'mga' => 'Malagasy Ariary',
			'mkd' => 'Macedonian Denar',
			'mmk' => 'Myanmar Kyat',
			'mnt' => 'Mongolian Tögrög',
			'mop' => 'Macanese Pataca',
			'mro' => 'Mauritanian Ouguiya (pre-2018)',
			'mur' => 'Mauritian Rupee',
			'mvr' => 'Maldivian Rufiyaa',
			'mwk' => 'Malawian Kwacha',
			'mxn' => 'Mexican Peso',
			'myr' => 'Malaysian Ringgit',
			'mzn' => 'Mozambican Metical',
			'nad' => 'Namibian Dollar',
			'ngn' => 'Nigerian Naira',
			'nio' => 'Nicaraguan Córdoba',
			'nok' => 'Norwegian Krone',
			'npr' => 'Nepalese Rupee',
			'nzd' => 'New Zealand Dollar',
			'pab' => 'Panamanian Balboa',
			'pen' => 'Peruvian Sol',
			'pgk' => 'Papua New Guinean Kina',
			'php' => 'Philippine Peso',
			'pkr' => 'Pakistani Rupee',
			'pln' => 'Polish Złoty',
			'pyg' => 'Paraguayan Guarani',
			'qar' => 'Qatari Riyal',
			'ron' => 'Romanian Leu',
			'rsd' => 'Serbian Dinar',
			'rub' => 'Russian Ruble',
			'rwf' => 'Rwandan Franc',
			'sar' => 'Saudi Riyal',
			'sbd' => 'Solomon Islands Dollar',
			'scr' => 'Seychellois Rupee',
			'sek' => 'Swedish Krona',
			'sgd' => 'Singapore Dollar',
			'shp' => 'Saint Helena Pound',
			'sll' => 'Sierra Leonean Leone',
			'sos' => 'Somali Shilling',
			'srd' => 'Surinamese Dollar',
			'std' => 'São Tomé and Príncipe Dobra (pre-2018)',
			'svc' => 'Salvadoran Colón',
			'szl' => 'Swazi Lilangeni',
			'thb' => 'Thai Baht',
			'tjs' => 'Tajikistani Somoni',
			'top' => 'Tongan Paʻanga',
			'try' => 'Turkish Lira',
			'ttd' => 'Trinidad and Tobago Dollar',
			'twd' => 'New Taiwan Dollar',
			'tzs' => 'Tanzanian Shilling',
			'uah' => 'Ukrainian Hryvnia',
			'ugx' => 'Ugandan Shilling',
			'uyu' => 'Uruguayan Peso',
			'uzs' => 'Uzbekistani Som',
			'vnd' => 'Vietnamese Đồng',
			'vuv' => 'Vanuatu Vatu',
			'wst' => 'Samoan Tālā',
			'xaf' => 'Central African CFA Franc',
			'xcd' => 'East Caribbean Dollar',
			'xof' => 'West African CFA Franc',
			'xpf' => 'CFP Franc',
			'yer' => 'Yemeni Rial',
			'zar' => 'South African Rand',
			'zmw' => 'Zambian Kwacha',
		];
	}


	public static function get_connect_account_id( string $env = '' ) {
		if ( empty( $env ) ) {
			$env = OsSettingsHelper::get_payments_environment();
		}
		return OsSettingsHelper::get_settings_value( OsSettingsHelper::append_payment_env_key( 'stripe_connect_account_id', $env ), '' );
	}

	public static function generate_payment_intent_id_and_secret_for_transaction_intent( OsTransactionIntentModel $transaction_intent ): array {
		$order         = new OsOrderModel( $transaction_intent->order_id );
		$customer_data = [
			'name'  => $order->customer->full_name,
			'email' => $order->customer->email,
		];
		$options       = [
			'amount'                  => $transaction_intent->specs_charge_amount,
			'currency'                => self::get_currency_iso_code(),
			'stripe_customer_id'      => self::get_stripe_customer_id( $order->customer ),
			'transaction_description' => esc_html__( 'Payment for Appointment', 'latepoint' ),
			'metadata'                => [
				'transaction_intent_key' => $transaction_intent->intent_key,
			],
		];


		// pass customer data in case it needs to be created
		$result = self::do_account_request(
			'payment-intents',
			OsSettingsHelper::get_payments_environment(),
			'',
			'POST',
			[
				'payment_intent_options' => $options,
				'customer_data'          => $customer_data,
			]
		);
		if ( empty( $result['data'] ) ) {
			// translators: %s is the payment error
			$error_message = ! empty( $result['error'] ) ? sprintf( __( 'Payment Error: %s', 'latepoint' ), esc_html( $result['error'] ) ) : __( 'Error generating payment intent for transaction', 'latepoint' );
			OsDebugHelper::log( $error_message );
			throw new Exception( $error_message );
		} else {
			// make sure we use correct stripe customer id in case the one that was passed is invalid - a valid one will be returned in this call
			if ( $result['data']['stripe_customer_id'] != self::get_stripe_customer_id( $order->customer ) ) {
				self::save_stripe_customer_id( $order->customer, $result['data']['stripe_customer_id'] );
			}

			return [
				'id'            => $result['data']['id'],
				'client_secret' => $result['data']['client_secret'],
			];
		}
	}

	public static function generate_payment_intent_id_and_secret_for_order_intent( OsOrderIntentModel $order_intent ): array {
		$customer_data = [
			'name'  => $order_intent->customer->full_name,
			'email' => $order_intent->customer->email,
		];
		$options       = [
			'amount'                  => $order_intent->specs_charge_amount,
			'currency'                => self::get_currency_iso_code(),
			'stripe_customer_id'      => self::get_stripe_customer_id( $order_intent->customer ),
			'transaction_description' => esc_html__( 'Payment for Appointment', 'latepoint' ),
			'metadata'                => [
				'order_intent_key' => $order_intent->intent_key,
			],
		];


		// pass customer data in case it needs to be created
		$result = self::do_account_request(
			'payment-intents',
			OsSettingsHelper::get_payments_environment(),
			'',
			'POST',
			[
				'payment_intent_options' => $options,
				'customer_data'          => $customer_data,
			]
		);
		if ( empty( $result['data'] ) ) {
			// translators: %s is the payment error
			$error_message = ! empty( $result['error'] ) ? sprintf( __( 'Payment Error: %s', 'latepoint' ), esc_html( $result['error'] ) ) : __( 'Error generating payment intent', 'latepoint' );
			OsDebugHelper::log( $error_message );
			throw new Exception( $error_message );
		} else {
			// make sure we use correct stripe customer id in case the one that was passed is invalid - a valid one will be returned in this call
			if ( $result['data']['stripe_customer_id'] != self::get_stripe_customer_id( $order_intent->customer ) ) {
				self::save_stripe_customer_id( $order_intent->customer, $result['data']['stripe_customer_id'] );
			}

			return [
				'id'            => $result['data']['id'],
				'client_secret' => $result['data']['client_secret'],
			];
		}
	}

	public static function build_customer_profile_link( string $stripe_customer_id, bool $test_env = false ): string {
		return 'https://dashboard.stripe.com/' . ( $test_env ? 'test/' : '' ) . 'customers/' . $stripe_customer_id;
	}


	public static function transaction_is_refund_available( $result, OsTransactionModel $transaction_model ): bool {
		if ( OsPaymentsHelper::is_payment_processor_enabled( self::$processor_code ) && $transaction_model->processor == self::$processor_code ) {
			$result = true;
		}
		return $result;
	}
}
