<?php

namespace WPEverest\URMembership\Admin\Services;

use DateTime;
use WPEverest\URM\Mollie\Services\PaymentService as MollieService;
use WPEverest\URMembership\Admin\Repositories\MembershipGroupRepository;
use WPEverest\URMembership\Admin\Repositories\MembershipRepository;
use WPEverest\URMembership\Admin\Repositories\MembersRepository;
use WPEverest\URMembership\Admin\Repositories\MembersOrderRepository;
use WPEverest\URMembership\Admin\Repositories\MembersSubscriptionRepository;
use WPEverest\URMembership\Admin\Repositories\OrdersRepository;
use WPEverest\URMembership\Admin\Repositories\SubscriptionRepository;
use WPEverest\URMembership\Admin\Services\Paypal\PaypalService;
use WPEverest\URMembership\Admin\Services\Stripe\StripeService;
use WPEverest\URMembership\Admin\Services\MembersService;
use WPEverest\URMembership\Admin\Services\UpgradeMembershipService;
use WPEverest\URMembership\Admin\Services\CouponService;

class SubscriptionService {

	protected $members_subscription_repository, $members_orders_repository, $membership_repository, $orders_repository, $subscription_repository;

	public function __construct() {
		$this->members_subscription_repository = new MembersSubscriptionRepository();
		$this->subscription_repository         = new SubscriptionRepository();
		$this->members_orders_repository       = new MembersOrderRepository();
		$this->membership_repository           = new MembershipRepository();
		$this->orders_repository               = new OrdersRepository();
	}

	/**
	 * Prepare data for subscriptions
	 *
	 * @param $data
	 * @param $member
	 *
	 * @return array
	 * @throws \Exception
	 */
	public function prepare_subscription_data( $data, $member ) {

		$current_user    = wp_get_current_user();
		$membership      = get_post( $data['membership_data']['membership'], ARRAY_A );
		$membership_meta = json_decode( wp_unslash( get_post_meta( $membership['ID'], 'ur_membership', true ) ), true );
		$status          = 'pending';

		$is_team_membership   = false;
		$is_team_subscription = false;
		$is_team_one_time     = false;
		$team_duration_value  = null;
		$team_duration_period = null;
		$billing_amount       = $membership_meta['amount'] ?? 0;

		if ( isset( $data['team'] ) && ! empty( $data['team'] ) ) {
			$team_data      = $data['team'];
			$team_plan_type = isset( $team_data['team_plan_type'] ) ? $team_data['team_plan_type'] : null;

			if ( 'subscription' === $team_plan_type || 'one-time' === $team_plan_type ) {
				$is_team_membership      = true;
				$is_team_subscription    = ( 'subscription' === $team_plan_type );
				$is_team_one_time        = ( 'one-time' === $team_plan_type );
				$team_duration_value_raw = isset( $team_data['team_duration_value'] ) ? $team_data['team_duration_value'] : null;
				if ( null !== $team_duration_value_raw && '' !== trim( (string) $team_duration_value_raw ) ) {
					$team_duration_value = absint( $team_duration_value_raw );
					$team_duration_value = ( 0 !== $team_duration_value ) ? $team_duration_value : null;
				} else {
					$team_duration_value = null;
				}
				$team_duration_period = isset( $team_data['team_duration_period'] ) ? sanitize_text_field( $team_data['team_duration_period'] ) : null;

				$seat_model = isset( $team_data['seat_model'] ) ? $team_data['seat_model'] : 'fixed';

				if ( 'fixed' === $seat_model ) {
					$billing_amount = isset( $team_data['team_price'] ) ? floatval( $team_data['team_price'] ) : 0;
				} else {
					$pricing_model = isset( $team_data['pricing_model'] ) ? $team_data['pricing_model'] : 'per_seat';
					$team_seats    = isset( $data['team_seats'] ) ? absint( $data['team_seats'] ) : 0;

					if ( 'per_seat' === $pricing_model ) {
						$per_seat_price = isset( $team_data['per_seat_price'] ) ? floatval( $team_data['per_seat_price'] ) : 0;
						$billing_amount = $team_seats * $per_seat_price;
					} elseif ( 'tier' === $pricing_model ) {
						if ( isset( $data['tier'] ) && isset( $data['tier']['tier_per_seat_price'] ) ) {
							$tier_per_seat_price = floatval( $data['tier']['tier_per_seat_price'] );
							$billing_amount      = $team_seats * $tier_per_seat_price;
						}
					}
				}
			}
		}

		if ( $is_team_subscription && $team_duration_value && $team_duration_period ) {
			$expiry_date = self::get_expiry_date( $data['membership_data']['start_date'], $team_duration_period, $team_duration_value );
			$status      = 'pending';
		} elseif ( $is_team_one_time ) {
			$expiry_date = '';
			$status      = 'pending';
		} elseif ( 'subscription' == $membership_meta['type'] ) { // TODO: calculate with trail date
			$expiry_date = self::get_expiry_date( $data['membership_data']['start_date'], $membership_meta['subscription']['duration'], $membership_meta['subscription']['value'] );
			$status      = 'on' === $membership_meta['trial_status'] ? 'trial' : 'pending';
		}

		if ( $current_user->ID != 0 || 'free' == $membership_meta['type'] ) {
			$status = 'active';
		}

		if ( $current_user->ID != 0 ) {
			$is_purchasing_multiple = isset( $data['is_purchasing_multiple'] ) && ur_string_to_bool( $data['is_purchasing_multiple'] );

			if ( $is_purchasing_multiple && 'free' != $membership_meta['type'] ) {
				$status = 'pending';
			}
		}

		if ( $is_team_subscription && $team_duration_period ) {
			$billing_cycle = $team_duration_period;
		} elseif ( $is_team_one_time ) {
			$billing_cycle = '';
		} else {
			$billing_cycle = ( 'subscription' === $membership_meta['type'] ) ? $membership_meta['subscription']['duration'] : '';
		}

		$subscription_data = array(
			'user_id'           => $member->ID,
			'item_id'           => $membership['ID'],
			'start_date'        => $data['membership_data']['start_date'],
			'expiry_date'       => $expiry_date ?? '',
			'next_billing_date' => $expiry_date ?? '',
			'billing_amount'    => $billing_amount,
			'status'            => $status,
			'cancel_sub'        => $membership_meta['cancel_subscription'] ?? 'immediately',
			'billing_cycle'     => $billing_cycle,
		);

		if ( isset( $data['coupon_data'] ) && ! empty( $data['coupon_data'] ) ) {
			$subscription_data['coupon'] = $data['coupon_data']['coupon_code'];
		}

		if ( isset( $membership_meta['trial_status'] ) && 'on' == $membership_meta['trial_status'] ) {

			$trial_data = array(
				'trial_start_date' => date( 'Y-m-d' ),
				'trial_end_date'   => self::get_expiry_date( date( 'Y-m-d' ), $membership_meta['trial_data']['duration'], $membership_meta['trial_data']['value'] ),
			);

			$subscription_data               = array_merge( $subscription_data, $trial_data );
			$subscription_data['start_date'] = $trial_data['trial_end_date'];

			if ( $is_team_one_time ) {
				$subscription_data['expiry_date'] = '';
			} elseif ( $is_team_subscription && $team_duration_value && $team_duration_period ) {
				$subscription_data['expiry_date'] = self::get_expiry_date( $trial_data['trial_end_date'], $team_duration_period, $team_duration_value );
			} else {
				$subscription_data['expiry_date'] = self::get_expiry_date( $trial_data['trial_end_date'], $membership_meta['subscription']['duration'], $membership_meta['subscription']['value'] );
			}
			$subscription_data['next_billing_date'] = $subscription_data['expiry_date'];
		}

		return $subscription_data;
	}

	/**
	 * Get Expiry date
	 *
	 * @param $start_date
	 * @param $period
	 * @param $value
	 *
	 * @return false|string
	 * @throws \Exception
	 */
	public static function get_expiry_date( $start_date, $period, $value ) {
		$allowedPeriods = array( 'day', 'week', 'month', 'year' );
		if ( ! in_array( $period, $allowedPeriods ) ) {
			return false;
		}
		$start_date   = new \DateTime( $start_date ?? '' );
		$intervalSpec = 'P' . $value . strtoupper( substr( $period, 0, 1 ) );
		$interval     = new \DateInterval( $intervalSpec );
		$start_date->add( $interval );

		return $start_date->format( 'Y-m-d' );
	}

	/**
	 * Cancel subscription
	 *
	 * @param $order
	 * @param $subscription
	 *
	 * @return array|bool[]|void
	 */
	public function cancel_subscription( $order, $subscription ) {
		switch ( $order['payment_method'] ) {
			case 'paypal':
				$paypal_service = new PaypalService();

				return $paypal_service->cancel_subscription( $order, $subscription );

			case 'stripe':
				$stripe_service = new StripeService();

				return $stripe_service->cancel_subscription( $order, $subscription );

			case 'mollie':
				$mollie_service = new MollieService();

				return $mollie_service->cancel_subscription( $order, $subscription );
			case 'bank':
				return array( 'status' => true );
			default:
				return apply_filters( 'user_registration_membership_cancel_subscription', array( 'status' => false ), $order, $subscription );
		}
	}
	public function reactivate_subscription( $order, $subscription ) {
		$logger   = ur_get_logger();
		$response = array( 'status' => false );
		switch ( $order['payment_method'] ) {
			case 'paypal':
				$paypal_service = new PaypalService();
				$logger->notice( 'Paypal reactivation Reached', array( 'source' => 'urm-reactivation-log' ) );
				return $paypal_service->reactivate_subscription( $subscription['subscription_id'] );
				break;
			case 'stripe':
				$stripe_service = new StripeService();
				return $stripe_service->reactivate_subscription( $subscription['subscription_id'] );
				break;
			default:
				return apply_filters( 'urm_reactivate_membership_subscription', $response, $order, $subscription );
		}
	}
	public function daily_membership_renewal_check() {
		$days_before_value = get_option( 'user_registration_membership_renewal_reminder_days_before', 1 );

		if ( $days_before_value <= 0 ) {
			return;
		}
		$period        = get_option( 'user_registration_membership_renewal_reminder_period', 'weeks' );
		$value_in_days = convert_to_days( $days_before_value, $period );
		$date          = new \DateTime( 'today' );
		$check_date    = $date->modify( "+$value_in_days day" )->format( 'Y-m-d H:i:s' );

		$subscriptions = $this->members_subscription_repository->get_about_to_expire_subscriptions( $check_date );
		if ( empty( $subscriptions ) ) {
			return;
		}
		$email_service = new EmailService();
		foreach ( $subscriptions as $subscription ) {
			$user_id      = $subscription['member_id'];
			$checked_date = get_user_meta( $user_id, 'urm_billing_reminder_sent_for_date', true );
			if ( $checked_date === $subscription['next_billing_date'] ) {
				continue;
			}
			$email_service->send_email( $subscription, 'membership_renewal' );
			update_user_meta( $subscription['member_id'], 'urm_billing_reminder_sent_for_date', $subscription['next_billing_date'] );
		}
	}

	/**
	 * send_cancel_emails
	 *
	 * @param $subscription_id
	 *
	 * @return void
	 */
	public function send_cancel_emails( $subscription_id ) {
		$email_service             = new EmailService();
		$current_user_subscription = $this->members_subscription_repository->get_membership_by_subscription_id( $subscription_id, false );

		$member_id = $current_user_subscription['user_id'];

		$latest_order = $this->members_orders_repository->get_member_orders( $member_id );

		$membership = $this->membership_repository->get_single_membership_by_ID( $current_user_subscription['item_id'] );

		$membership_metas          = wp_unslash( json_decode( $membership['meta_value'], true ) );
		$membership_metas['title'] = $membership['post_title'];

		$subscription = $this->members_subscription_repository->get_member_subscription( $member_id );

		$email_data = array(
			'subscription'     => $subscription,
			'order'            => $latest_order,
			'membership_metas' => $membership_metas,
			'member_id'        => $member_id,
		);
		$email_service->send_email( $email_data, 'membership_cancellation_email_user' );
		$email_service->send_email( $email_data, 'membership_cancellation_email_admin' );
	}

	/**
	 * get_membership_plan_details
	 *
	 * @param $data
	 *
	 * @return array
	 */
	public function get_membership_plan_details( $data ) {
		$currencies = ur_payment_integration_get_currencies();
		$currency   = get_option( 'user_registration_payment_currency', 'USD' );
		$symbol     = $currencies[ $currency ]['symbol'];

		$subscription_id = '';

		if ( isset( $data['subscription']['ID'] ) ) {
			$subscription_id = $data['subscription']['ID'] ?? 0;
		} else {
			$members_order_repository = new MembersOrderRepository();
			$last_order               = $members_order_repository->get_member_orders( $data['member_id'] );
			$subscription_id          = ! empty( $last_order ) ? $last_order['subscription_id'] : '';
		}

		$subscription  = $this->members_subscription_repository->get_subscription_by_subscription_id( $subscription_id );
		$membership_id = isset( $data['membership'] ) ? $data['membership'] : $subscription['item_id'];
		$membership    = $this->membership_repository->get_single_membership_by_ID( $membership_id );

		$membership_metas               = wp_unslash( json_decode( $membership['meta_value'], true ) );
		$membership_metas['post_title'] = $membership['post_title'];
		$member_order                   = $this->members_orders_repository->get_member_orders( $data['member_id'] );
		$order                          = $this->orders_repository->get_order_detail( $member_order['ID'] );
		$total                          = $order['total_amount'];
		$membership_tab_url             = esc_url( ur_get_my_account_url() . 'ur-membership' );


		$order_repository = new OrdersRepository();
		$local_currency = $order_repository->get_order_meta_by_order_id_and_meta_key( $order['order_id'], 'local_currency' );

		$currency = ! empty( $local_currency['meta_value'] ) ? $local_currency['meta_value'] : $currency;
		$symbol = ur_get_currency_symbol( $currency );

		if ( ! empty( $data['context'] ) && 'thank_you_page' == $data['context'] ) {
			$data['payment_method'] = ! empty( $member_order['payment_method'] ) ? $member_order['payment_method'] : '';
			$data['transaction_id'] = ! empty( $member_order['transaction_id'] ) ? $member_order['transaction_id'] : '';
		}

		if ( ! empty( $order['coupon'] ) && 'bank' !== $order['payment_method'] && isset( $membership_metas ) && ( 'paid' === $membership_metas['type'] || ( 'subscription' === $membership_metas['type'] && 'off' === $order['trial_status'] ) ) ) {
			$coupon_meta = ur_get_coupon_meta_by_code( $order['coupon'] );

			if ( ! empty( $coupon_meta ) ) {
				$coupon_discount = isset( $coupon_meta->coupon_discount ) ? (float) $coupon_meta->coupon_discount : 0;
				$discount_amount = ( isset( $coupon_meta->coupon_discount_type ) && $coupon_meta->coupon_discount_type === 'fixed' ) ? $coupon_discount : $order['total_amount'] * $coupon_discount / 100;
				$total           = $order['total_amount'] - $discount_amount;
			} else {
				$coupon_discount = isset( $order['coupon_discount'] ) ? (float) $order['coupon_discount'] : 0;
				$discount_amount = ( isset( $order['coupon_discount_type'] ) && $order['coupon_discount_type'] === 'fixed' ) ? $coupon_discount : $order['total_amount'] * $coupon_discount / 100;
				$total           = $order['total_amount'] - $discount_amount;
			}
		}
		$billing_cycle = ( 'subscription' === $membership_metas['type'] ) ? ( ( 'day' === $membership_metas['subscription']['duration'] ) ? esc_html( 'Daily', 'user-registration' ) : ( esc_html( ucfirst( $membership_metas['subscription']['duration'] . 'ly' ) ) ) ) : 'N/A';
		$trial_period  = ( 'subscription' === $membership_metas['type'] && 'on' === $order['trial_status'] ) ? ( $membership_metas['trial_data']['value'] . ' ' . $membership_metas['trial_data']['duration'] . ( $membership_metas['trial_data']['value'] > 1 ? 's' : '' ) ) : 'N/A';

		$next_billing_date = 'subscription' === $membership_metas['type'] && ! empty( $subscription['next_billing_date'] ) ? date( 'Y, F d', strtotime( $subscription['next_billing_date'] ) ) : 'N/A';
		$expiry_date       = 'subscription' === $membership_metas['type'] && ! empty( $subscription['expiry_date'] ) ? date( 'Y, F d', strtotime( $subscription['expiry_date'] ) ) : 'N/A';
		$trial_start_date  = 'subscription' === $membership_metas['type'] && 'on' === $order['trial_status'] && ! empty( $subscription['trial_start_date'] ) ? date( 'Y, F d', strtotime( $subscription['trial_start_date'] ) ) : 'N/A';
		$trial_end_date    = 'subscription' === $membership_metas['type'] && 'on' === $order['trial_status'] && ! empty( $subscription['trial_end_date'] ) ? date( 'Y, F d', strtotime( $subscription['trial_end_date'] ) ) : 'N/A';
		$membership_type   = ucwords( $membership_metas['type'] ) == 'Paid' ? __( 'One-Time Payment', 'user-registration' ) : ucwords( $membership_metas['type'] );

		$team_data  = null;
		$team_seats = null;
		$tier_info  = null;
		if ( ! empty( $member_order['ID'] ) ) {
			$ordermeta_table = $this->orders_repository->wpdb()->prefix . 'ur_membership_ordermeta';
			$team_id         = $this->orders_repository->wpdb()->get_var(
				$this->orders_repository->wpdb()->prepare(
					"SELECT meta_value FROM {$ordermeta_table} WHERE meta_key=%s AND order_id=%d LIMIT 1",
					'urm_team_id',
					$member_order['ID']
				)
			);

			if ( ! empty( $team_id ) ) {
				$team_data  = get_post_meta( $team_id, 'urm_team_data', true );
				$team_seats = get_post_meta( $team_id, 'urm_team_seats', true );
				$tier_info  = get_post_meta( $team_id, 'urm_tier_info', true );
			}
		}

		$return_array = array(
			'username'                          => esc_html( ucwords( isset( $data['username'] ) ? $data['username'] : '' ) ),
			'membership_plan_name'              => esc_html( ucwords( $membership_metas['post_title'] ) ),
			'membership_plan_type'              => esc_html( $membership_type ),
			'membership_plan_payment_method'    => esc_html( ucwords( isset( $data['order']['payment_method'] ) ? $data['order']['payment_method'] : $data['payment_method'] ) ),
			'membership_plan_trial_status'      => esc_html( ucwords( $order['trial_status'] ) ),
			'membership_plan_trial_start_date'  => esc_html( $trial_start_date ),
			'membership_plan_trial_end_date'    => esc_html( $trial_end_date ),
			'membership_plan_trial_period'      => esc_html( $trial_period ),
			'membership_plan_next_billing_date' => esc_html( $next_billing_date ),
			'membership_plan_expiry_date'       => esc_html( $expiry_date ),
			'membership_plan_status'            => isset( $subscription['status'] ) ? esc_html( ucwords( $subscription['status'] ) ) : '',
			'membership_plan_payment_date'      => esc_html( date( 'Y, F d', strtotime( $order['created_at'] ) ) ),
			'membership_plan_billing_cycle'     => esc_html( ucwords( $billing_cycle ) ),
			'membership_plan_payment_amount'    => ( ! empty( $currencies[ $currency ]['symbol_pos'] ) && 'left' === $currencies[ $currency ]['symbol_pos'] ) ? $symbol . number_format( $membership_metas['amount'], 2 ) : number_format( $membership_metas['amount'], 2 ) . $symbol,
			'membership_plan_payment_status'    => esc_html( ucwords( $order['status'] ) ),
			'membership_plan_trial_amount'      => ( ! empty( $currencies[ $currency ]['symbol_pos'] ) && 'left' === $currencies[ $currency ]['symbol_pos'] ) ? $symbol . number_format( ( 'on' === $order['trial_status'] ) ? $order['total_amount'] : 0, 2 ) : number_format( ( 'on' === $order['trial_status'] ) ? $order['total_amount'] : 0, 2 ) . $symbol,
			'membership_plan_coupon_discount'   => (
				isset( $order['coupon_discount'] )
					? (
						( isset( $order['coupon_discount_type'] ) && $order['coupon_discount_type'] == 'percent' )
							? $order['coupon_discount'] . '%'
							: $symbol . $order['coupon_discount']
					)
					: (
						isset( $coupon_meta->coupon_discount )
							? (
								( isset( $coupon_meta->coupon_discount_type ) && $coupon_meta->coupon_discount_type == 'percent' )
									? $coupon_meta->coupon_discount . '%'
									: $symbol . $coupon_meta->coupon_discount
							)
							: ''
					)
			),
			'membership_plan_coupon'            => esc_html( $order['coupon'] ?? '' ),
			'membership_plan_total'             => ( ! empty( $currencies[ $currency ]['symbol_pos'] ) && 'left' === $currencies[ $currency ]['symbol_pos'] ) ? $symbol . number_format( $total, 2 ) : number_format( $total, 2 ) . $symbol,
			'membership_renewal_link'           => "<a href=$membership_tab_url>" . __( 'Renew Now', 'user-registration' ) . '</a>',
			'membership_plan_transaction_id'    => ! empty( $data['transaction_id'] ) ? $data['transaction_id'] : '',
		);

		if ( ! empty( $team_data ) ) {
			$return_array['team'] = $team_data;
		}
		if ( ! empty( $team_seats ) ) {
			$return_array['team_seats'] = $team_seats;
		}
		if ( ! empty( $tier_info ) ) {
			$return_array['tier'] = $tier_info;
		}

		return $return_array;
	}

	/**
	 * Handles the membership upgrade process.
	 *
	 * This function is called when a user chooses to upgrade their membership. It calculates the upgrade cost, cancels the previous subscription,
	 * creates a new order and redirects the user to the payment gateway.
	 *
	 * @param array $data The data passed from the front end.
	 *
	 * @return array The response from the payment gateway.
	 */
	public function upgrade_membership( $data ) {
		$order_service = new OrderService();

		$current_subscription_id                   = $data['current_subscription_id'];
		$subscription                              = $this->subscription_repository->retrieve( $data['current_subscription_id'] );
		$user                                      = get_userdata( $subscription['user_id'] );
		$payment_method                            = $data['selected_pg'];
		$membership                                = $this->membership_repository->get_single_membership_by_ID( $subscription['item_id'] );
		$current_membership_details                = wp_unslash( json_decode( $membership['meta_value'], true ) );
		$current_membership_details['post_title']  = $membership['post_title'];
		$membership                                = $this->membership_repository->get_single_membership_by_ID( $data['selected_membership_id'] );
		$selected_membership_details               = wp_unslash( json_decode( $membership['meta_value'], true ) );
		$selected_membership_details['post_title'] = $membership['post_title'];
		$selected_membership_details['membership'] = $data['selected_membership_id'];

		$selected_membership_details['payment_method'] = $payment_method;
		$membership_process                            = urm_get_membership_process( $user->ID );

		$is_upgrading = ! empty( $membership_process['upgrade'] ) && isset( $membership_process['upgrade'][ $data['current_membership_id'] ] );

		if ( $is_upgrading ) {
			$response['response']['status']  = false;
			$response['response']['message'] = __( 'Membership upgrade process already initiated.', 'user-registration' );

			return $response;
		}

		$membership_process = urm_get_membership_process( $subscription['user_id'] );
		$is_upgrading       = ! empty( $membership_process['upgrade'] ) && isset( $membership_process['upgrade'][ $data['current_membership_id'] ] );

		if ( $is_upgrading ) {
			$response['response']['status']  = false;
			$response['response']['message'] = __( 'Membership upgrade process already initiated.', 'user-registration' );

			return $response;
		}

		$current_membership_details['ID']  = $data['current_membership_id'];
		$selected_membership_details['ID'] = $data['selected_membership_id'];
		$upgrade_details                   = $this->calculate_membership_upgrade_cost( $current_membership_details, $selected_membership_details, $subscription );

		if ( isset( $upgrade_details['status'] ) && ! $upgrade_details['status'] ) {
			return array(
				'response' => $upgrade_details,
			);
		}

		$members_data = array(
			'membership_data' => $selected_membership_details,
		);

		if ( ! empty( $data['coupon'] ) ) {
			$members_data['coupon'] = $data['coupon'];
			$coupon_service         = new CouponService();
			$coupon_data            = array(
				'coupon'         => $data['coupon'],
				'membership_id'  => $data['selected_membership_id'],
				'upgrade_amount' => $upgrade_details['chargeable_amount'],
			);

			$response = $coupon_service->validate( $coupon_data );

			if ( $response['status'] ) {
				$response                             = json_decode( $response['data'], true );
				$upgrade_details['chargeable_amount'] = $response['discounted_amount'];
			}
		}

		$membership_details = ! empty( $data['selected_membership_id'] ) ? json_decode( get_post_meta( $data['selected_membership_id'], 'ur_membership', true ), true ) : array();

		if ( ! empty( $membership_details ) ) {
			$members_data['role'] = ! empty( $membership_details['role'] ) ? $membership_details['role'] : 'subscriber';
		}

		$member_service = new MembersService();
		$member_service->update_user_meta( $members_data, $user->ID );

		if ( isset( $data['upgrade'] ) && $data['upgrade'] && 'subscription' === $current_membership_details['type'] && 'bank' !== $payment_method && 'off' === $selected_membership_details['trial_status'] && ! isset( $upgrade_details['delayed_until'] ) ) {

			$cancel_subscription = $this->subscription_repository->cancel_subscription_by_id( $current_subscription_id, false );

			if ( ! $cancel_subscription['status'] ) {
				$response['status'] = false;

				return $response;
			} else {
				$this->subscription_repository->cancel_subscription_by_id( $current_subscription_id, false );
			}
		}

		// save previous order
		$latest_order = $this->members_orders_repository->get_member_orders( $user->ID );
		update_user_meta( $user->ID, 'urm_previous_order_data', json_encode( $latest_order ) );

		$orders_data = $order_service->prepare_orders_data( $members_data, $user->ID, $subscription, $upgrade_details ); // prepare data for orders table.
		$order       = $this->orders_repository->create( $orders_data );

		$payment_service       = new PaymentService( $payment_method, $data['selected_membership_id'], $user->data->user_email );
		$ur_authorize_net_data = isset( $data['ur_authorize_net'] ) ? $data['ur_authorize_net'] : array();
		$coupon                = isset( $data['coupon'] ) ? $data['coupon'] : '';

		$data = array(
			'membership'             => $data['selected_membership_id'],
			'subscription_id'        => $subscription['ID'],
			'member_id'              => $user->ID,
			'email'                  => $user->user_email,
			'transaction_id'         => $orders_data['orders_data']['transaction_id'],
			'upgrade'                => true,
			'subscription_data'      => $subscription,
			'ur_authorize_net'       => $ur_authorize_net_data,
			'selected_membership_id' => $data['selected_membership_id'],
			'current_membership_id'  => $data['current_membership_id'],
		);

		if ( ! empty( $coupon ) ) {
			$data['coupon'] = $coupon;
		}

		$data               = $data + $upgrade_details;
		$response           = $payment_service->build_response( $data );
		$response['status'] = false;

		if ( isset( $response['payment_url'] ) || isset( $response['data'] ) || 'stripe' === $payment_method || 'free' === $payment_method ) {
			$response['status'] = true;

		} else {
			$this->orders_repository->delete( $order['ID'] );
		}

		return array(
			'extra'    => array(
				'member_id'                => $user->ID,
				'username'                 => $user->user_login,
				'transaction_id'           => $orders_data['orders_data']['transaction_id'],
				'order_id'                 => $order['ID'],
				'updated_membership_title' => $selected_membership_details['post_title'],
			),
			'response' => $response,
		);
	}

	/**
	 * Calculate upgrade cost and details between memberships.
	 *
	 * Determines the chargeable amount for upgrading from a current to a selected membership.
	 * Considers subscription duration, trial periods, and subscription status.
	 *
	 * @param array $current_membership_details Current membership details.
	 * @param array $selected_membership_details Selected membership details.
	 * @param array $subscription Subscription details.
	 *
	 * @return array Upgrade calculation results.
	 */
	public function calculate_membership_upgrade_cost( $current_membership_details, $selected_membership_details, $subscription ) {
		$upgrade_type               = $current_membership_details['type'] . '->' . $selected_membership_details['type'];
		$upgrade_membership_service = new UpgradeMembershipService();

		$result['status'] = true;

		if ( isset( $selected_membership_details['trial_status'] ) && 'on' === $selected_membership_details['trial_status'] && ! empty( $subscription['trial_end_date'] ) ) {
			$is_trial = $subscription['trial_end_date'] > date( 'Y-m-d H:i:s' );
		} else {
			$is_trial = isset( $selected_membership_details['trial_status'] ) && 'on' === $selected_membership_details['trial_status'];
		}

		switch ( $upgrade_type ) {
			case 'free->free':
			case 'paid->free':
				$result['chargeable_amount'] = 0;
				break;
			case 'subscription->free':
				$result['chargeable_amount'] = 0;
				$result['delayed_until']     = $subscription['expiry_date'];
				break;
			case 'free->paid':
				$result['chargeable_amount'] = $selected_membership_details['amount'];
				break;
			case 'free->subscription':
				$result['chargeable_amount']            = $selected_membership_details['amount'];
				$result['remaining_subscription_value'] = $selected_membership_details['subscription']['value'];
				break;
			case 'paid->paid':
				$result = $upgrade_membership_service->handle_paid_to_paid_membership_upgrade( $current_membership_details, $selected_membership_details, $subscription );
				break;
			case 'paid->subscription':
				$result = $upgrade_membership_service->handle_paid_to_subscription_membership_upgrade( $current_membership_details, $selected_membership_details, $subscription );
				break;
			case 'subscription->subscription':
			case 'subscription->paid':
				$result = $upgrade_membership_service->handle_subscription_to_paid_or_subscription_membership_upgrade( $current_membership_details, $selected_membership_details, $subscription, $is_trial );
				break;
		}

		if ( ! $result['status'] ) {
			return $result;
		}

		return array(
			'trial_status'                 => $is_trial ? 'on' : 'off',
			'chargeable_amount'            => ! empty( $result['chargeable_amount'] ) ? $result['chargeable_amount'] : 0,
			'remaining_subscription_value' => ! empty( $result['remaining_subscription_value'] ) ? $result['remaining_subscription_value'] : 0,
			'delayed_until'                => ! empty( $result['delayed_until'] ) ? $result['delayed_until'] : '',
		);
	}

	/**
	 * validate if a membership can validate from current to another
	 *
	 * @param $data
	 *
	 * @return array
	 */
	public function can_upgrade( $data ) {
		$membership_service       = new MembershipService();
		$upgrade_service          = new UpgradeMembershipService();
		$membership_details       = $membership_service->get_membership_details( $data['current_membership_id'] );
		$membership_details['ID'] = $data['current_membership_id'];

		$upgrade_details = $upgrade_service->get_upgrade_details( $membership_details );
		$status          = true;
		if ( empty( $upgrade_details['upgrade_path'] ) ) {
			return array(
				'status'  => false,
				'message' => __( 'Sorry, you cannot upgrade to the selected plan.', 'user-registration' ),
			);
		}

		if ( is_array( $upgrade_details['upgrade_path'] ) && isset( $upgrade_details['upgrade_path'][ $data['current_membership_id'] ] ) ) {
			$current_upgrade_path   = $upgrade_details['upgrade_path'][ $data['current_membership_id'] ];
			$selected_membership_id = $data['selected_membership_id'];
			$status                 = array_filter(
				$current_upgrade_path,
				function ( $item ) use ( $selected_membership_id ) {
					return $item['membership_id'] === $selected_membership_id;
				}
			);

		} else {
			$upgradable_memberships = explode( ',', $upgrade_details['upgrade_path'] );
			$status                 = in_array( $data['selected_membership_id'], $upgradable_memberships );
		}

		if ( ! $status ) {
			return array(
				'status'  => false,
				'message' => __( 'Sorry, you cannot upgrade to the selected plan.', 'user-registration' ),
			);
		}

		$subscription                = $this->subscription_repository->retrieve( $data['current_subscription_id'] );
		$membership                  = $this->membership_repository->get_single_membership_by_ID( $data['selected_membership_id'] );
		$selected_membership_details = wp_unslash( json_decode( $membership['meta_value'], true ) );

		if ( isset( $selected_membership_details['trial_status'] ) && 'on' === $selected_membership_details['trial_status'] && ! empty( $subscription['trial_end_date'] ) && $subscription['trial_end_date'] < date( 'Y-m-d H:i:s' ) ) {
			return array(
				'status'  => false,
				'message' => __( 'Sorry, You’re not eligible for another trial. Please choose a regular membership plan.', 'user-registration' ),
			);
		}

		return array(
			'status' => true,
		);
	}

	/**
	 * Validate if a user with a membership can purchase another.
	 *
	 * @param $data
	 *
	 * @return array
	 */
	public function can_purchase_multiple( $data ) {
		$membership_service                = new MembershipService();
		$membership_group_repository       = new MembershipGroupRepository();
		$members_repository                = new MembersRepository();
		$membership_group_service          = new MembershipGroupService();
		$multiple_purchasable_with_current = array();
		$multiple_allowed                  = false;

		if ( UR_PRO_ACTIVE && urm_check_if_plus_and_above_plan() && ur_check_module_activation( 'membership-groups' ) ) {

			if ( isset( $data['selected_membership_id'] ) && ! empty( $data['selected_membership_id'] ) ) {
				$membership_id    = absint( $data['selected_membership_id'] );
				$membership_group = $membership_group_repository->get_membership_group_by_membership_id( $membership_id );

				if ( ! empty( $membership_group ) && isset( $membership_group['ID'] ) ) {
					$multiple_allowed = $membership_group_service->check_if_multiple_memberships_allowed( $membership_group['ID'] );
				}

				$user_membership_group_ids = array();
				$current_user_id           = get_current_user_id();

				if ( $current_user_id ) {
					$user_memberships          = $members_repository->get_member_membership_by_id( $current_user_id );
					$user_membership_group_ids = array_filter(
						array_map(
							function ( $user_memberships ) use ( $membership_group_repository ) {
								$group = $membership_group_repository->get_membership_group_by_membership_id( $user_memberships['post_id'] );
								if ( isset( $group['ID'] ) ) {
									return $group['ID'];
								}
							},
							$user_memberships
						)
					);

					$user_membership_group_ids = array_values( array_unique( $user_membership_group_ids ) );

					if ( ! in_array( $membership_group, $user_membership_group_ids ) ) {
						$multiple_allowed = true;
					}
				}
			}
		}

		if ( $multiple_allowed ) {

			return array(
				'status' => true,
			);

		} else {
			return array(
				'status'  => false,
				'message' => esc_html__( 'Sorry, multiple memberships are not allowed with your selected plan.', 'user-registration' ),
			);
		}
	}

	public function run_daily_delayed_membership_subscriptions() {
		$all_delayed_orders = $this->orders_repository->get_all_delayed_orders( date( 'Y-m-d 00:00:00' ) );

		ur_get_logger()->notice(
			sprintf(
				__( 'Scheduled Subscriptions job started for the date: (%s)', 'user-registration' ),
				date( 'd F,Y' )
			),
			array( 'source' => 'urm-membership-crons' )
		);

		if ( empty( $all_delayed_orders ) ) {
			ur_get_logger()->notice( __( 'No delayed orders found.', 'user-registration' ), array( 'source' => 'urm-membership-crons' ) );

			return;
		}
		$updated_subscription_for_users = array();

		foreach ( $all_delayed_orders as $data ) {
			$decoded_data = json_decode( $data['sub_data'], true );
			if ( ! isset( $decoded_data['subscription_id'] ) ) {
				continue;
			}
			$subscription_id = $decoded_data['subscription_id'];
			$user            = get_userdata( $decoded_data['member_id'] );
			if ( $user ) {
				$cancel_subscription = $this->subscription_repository->cancel_subscription_by_id( $subscription_id, false, true );
				ur_get_logger()->notice( $cancel_subscription['message'], array( 'source' => 'urm-membership-crons' ) );
				$previous_subscription             = json_decode( get_user_meta( $user->ID, 'urm_previous_subscription_data', true ), true );
				$updated_subscription_for_users[]  = $user->user_login;
				$decoded_data['subscription_data'] = $previous_subscription;
				$subscription_data                 = $this->prepare_upgrade_subscription_data( $decoded_data['membership'], $decoded_data['member_id'], $decoded_data );
				$subscription_data['status']       = 'active';
				$this->subscription_repository->update( $subscription_id, $subscription_data );
				$last_order = $this->members_orders_repository->get_member_orders( $user->ID );
				$this->orders_repository->delete_order_meta(
					array(
						'order_id' => $last_order['ID'],
						'meta_key' => 'delayed_until',
					)
				);
				delete_user_meta( $user->ID, 'urm_next_subscription_data' );
				delete_user_meta( $user->ID, 'urm_previous_subscription_data' );
				delete_user_meta( $user->ID, 'urm_previous_order_data' );
			}
		}

		ur_get_logger()->notice(
			sprintf(
				__( 'Subscription updated for %s', 'user-registration' ),
				implode( ',', $updated_subscription_for_users )
			),
			array( 'source' => 'urm-membership-crons' )
		);
	}

	/**
	 * Prepares subscription data for upgrading a membership.
	 *
	 * This method retrieves and processes the membership data for a given member,
	 * calculates the expiry and trial dates based on the membership type, and
	 * constructs an array of subscription data including user ID, membership ID,
	 * start date, expiry date, next billing date, billing amount, and status.
	 *
	 * @param int   $membership_id The ID of the membership to be upgraded.
	 * @param int   $member_id The ID of the member for whom the subscription is being upgraded.
	 * @param array $extra_data Additional data required for preparing the subscription, such as
	 *                          remaining subscription days, trial status, and total used trial days.
	 *
	 * @return array The prepared subscription data including trial information if applicable.
	 * @throws \Exception
	 */
	public function prepare_upgrade_subscription_data( $membership_id, $member_id, $extra_data ) {
		$current_subscription         = $extra_data['subscription_data'];
		$remaining_subscription_value = $extra_data['remaining_subscription_value'];
		$membership                   = get_post( $membership_id, ARRAY_A );
		$membership_meta              = json_decode( wp_unslash( get_post_meta( $membership['ID'], 'ur_membership', true ) ), true );
		$expiry_date                  = '';
		if ( 'subscription' == $membership_meta['type'] ) { // TODO: calculate with trial date
			$expiry_date = self::get_expiry_date( date( 'Y-m-d' ), $membership_meta['subscription']['duration'], $remaining_subscription_value );
		}
		$billing_cycle = ( 'subscription' === $membership_meta['type'] ) ? $membership_meta['subscription']['duration'] : '';

		$subscription_data = array(
			'user_id'           => $member_id,
			'item_id'           => $membership['ID'],
			'start_date'        => date( 'Y-m-d 00:00:00' ),
			'expiry_date'       => $expiry_date,
			'next_billing_date' => $expiry_date,
			'billing_amount'    => $membership_meta['amount'] ?? 0,
			'status'            => 'free' === $membership_meta['type'] ? 'active' : 'pending',
			'billing_cycle'     => $billing_cycle,
		);

		if ( isset( $extra_data['coupon'] ) && ! empty( $extra_data['coupon'] ) ) {
			$subscription_data['coupon'] = $extra_data['coupon'];
		}

		if ( isset( $membership_meta['trial_status'] ) && 'on' === $membership_meta['trial_status'] ) {
			$remaining_trial_days          = $membership_meta['trial_data']['value'];
			$dont_calculate_trial_end_date = ! empty( $current_subscription['trial_end_date'] ) && $current_subscription['trial_end_date'] > date( 'Y-m-d 00:00:00' );
			$trial_data                    = array(
				'trial_start_date' => date( 'Y-m-d' ),
				'trial_end_date'   => ! $dont_calculate_trial_end_date ? self::get_expiry_date( date( 'Y-m-d' ), $membership_meta['trial_data']['duration'], $remaining_trial_days ) : $current_subscription['trial_end_date'],
			);

			$subscription_data                      = array_merge( $subscription_data, $trial_data );
			$subscription_data['start_date']        = $trial_data['trial_end_date'];
			$subscription_data['expiry_date']       = self::get_expiry_date( $trial_data['trial_end_date'], $membership_meta['subscription']['duration'], $remaining_subscription_value );
			$subscription_data['next_billing_date'] = $subscription_data['expiry_date'];
		}

		return $subscription_data;
	}

	public function renew_membership( $user, $selected_pg, $membership_id, $team_id ) {
		$member_id                            = $user->ID;
		$username                             = $user->user_login;
		$member_subscription                  = $this->members_subscription_repository->get_subscription_data_by_member_and_membership_id( $member_id, $membership_id );
		$membership                           = $this->membership_repository->get_single_membership_by_ID( $member_subscription['item_id'] );
		$membership_details                   = wp_unslash( json_decode( $membership['meta_value'], true ) );
		$membership_details['payment_method'] = $selected_pg;
		$membership_details['post_title']     = $membership['post_title'];
		$membership_details['membership']     = $membership_id;
		$order_service                        = new OrderService();
		$members_data                         = array(
			'membership_data' => $membership_details,
		);

		$membership_process = urm_get_membership_process( $member_id );
		if ( $membership_process && ! in_array( $membership_id, $membership_process['renew'] ) ) {
			$membership_process['renew'][] = $membership_id;
			update_user_meta( $member_id, 'urm_membership_process', $membership_process );
		} else {
			wp_send_json_error(
				array(
					'message' => __( 'Membership renew process already initiated.', 'user-registration' ),
				)
			);
		}

		$orders_data     = $order_service->prepare_orders_data( $members_data, $member_id, $member_subscription, array(), true ); // prepare data for orders table.
		$order           = $this->orders_repository->create( $orders_data );
		$payment_service = new PaymentService( $selected_pg, $membership['ID'], $user->data->user_email );
		$data            = array(
			'membership'        => $membership_id,
			'subscription_id'   => $member_subscription['ID'],
			'member_id'         => $member_id,
			'email'             => $user->user_email,
			'transaction_id'    => $orders_data['orders_data']['transaction_id'],
			'upgrade'           => false,
			'subscription_data' => $member_subscription,
		);

		$renew_response           = $payment_service->build_response( $data );
		$renew_response['status'] = false;

		if ( isset( $renew_response['payment_url'] ) || isset( $renew_response['data'] ) || 'stripe' === $selected_pg ) {
			$renew_response['status'] = true;
			if ( $team_id ) {
				$this->orders_repository->update_order_meta(
					array(
						'order_id'   => $order['ID'],
						'meta_key'   => 'urm_team_id',
						'meta_value' => $team_id,
					)
				);
			}
		} else {
			$this->orders_repository->delete( $order['ID'] );
		}

		return array(
			'extra'    => array(
				'member_id'                => $member_id,
				'username'                 => $username,
				'transaction_id'           => $orders_data['orders_data']['transaction_id'],
				'updated_membership_title' => $membership['post_title'],
				'order_id'   => $order['ID'],
			),
			'response' => $renew_response,
		);
	}

	/**
	 * update_membership_renewal_metas
	 *
	 * @param $member_id
	 * @param $membership_id
	 *
	 * @return void
	 */
	public function update_membership_renewal_metas( $member_id, $membership_id ) {
		update_user_meta( $member_id, 'urm_is_member_renewing', true );
	}

	public function update_subscription_data_for_renewal( $member_subscription, $membership_metas ) {

		$subscription_value    = $membership_metas['subscription']['value'];
		$subscription_duration = $membership_metas['subscription']['duration'];
		$next_billing_date     = new \DateTime( $member_subscription['next_billing_date'] );

		$today = new \DateTime( 'today' );
		if ( $next_billing_date < $today ) {
			$next_billing_date = $today;
		}

		$next_billing_date = $next_billing_date->modify( "+ $subscription_value $subscription_duration" )->format( 'Y-m-d 00:00:00' );

		$this->members_subscription_repository->update(
			$member_subscription['ID'],
			array(
				'start_date'        => date( 'Y-m-d 00:00:00' ),
				'next_billing_date' => $next_billing_date,
				'expiry_date'       => $next_billing_date,
			)
		);
		update_user_meta( $member_subscription['user_id'], 'urm_last_renewed_on', date( 'Y-m-d 00:00:00' ) );
		$membership_process = urm_get_membership_process( $member_subscription['user_id'] );

		if ( ! empty( $membership_process ) && in_array( $member_subscription['item_id'], $membership_process['renew'] ) ) {
			unset( $membership_process['renew'][ array_search( $member_subscription['item_id'], $membership_process['renew'], true ) ] );
			update_user_meta( $member_subscription['user_id'], 'urm_membership_process', $membership_process );

			do_action( 'user_registration_membership_renewed', $member_subscription['user_id'], $member_subscription['item_id'] );
		}
	}

	/**
	 * daily_membership_expiring_soon_check
	 *
	 * @return void
	 */
	public function daily_membership_expiring_soon_check() {
		$days_before_value = get_option( 'user_registration_membership_expiring_soon_days_before', 1 );

		if ( $days_before_value <= 0 ) {
			return;
		}
		$period        = get_option( 'user_registration_membership_expiring_soon_period', 'weeks' );
		$value_in_days = convert_to_days( $days_before_value, $period );
		$date          = new \DateTime( 'today' );
		$check_date    = $date->modify( "+$value_in_days day" )->format( 'Y-m-d H:i:s' );

		$subscriptions = $this->members_subscription_repository->get_about_to_expire_subscriptions( $check_date );
		if ( empty( $subscriptions ) ) {
			return;
		}
		$email_service = new EmailService();
		foreach ( $subscriptions as $subscription ) {

			$user_id      = $subscription['member_id'];
			$checked_date = get_user_meta( $user_id, 'urm_expiring_reminder_sent_for_date', true );

			if ( $checked_date === $subscription['next_billing_date'] ) {
				continue;
			}
			$email_service->send_email( $subscription, 'membership_expiring_soon' );
			update_user_meta( $subscription['member_id'], 'urm_expiring_reminder_sent_for_date', $subscription['next_billing_date'] );
		}
	}

	/**
	 * daily_membership_expiring_soon_check
	 *
	 * @return void
	 */
	public function daily_membership_ended_check() {
		$date          = new \DateTime( 'today' );
		$check_date    = $date->modify( '-1 day' )->format( 'Y-m-d H:i:s' );
		$subscriptions = $this->members_subscription_repository->get_expired_subscriptions( $check_date );
		if ( empty( $subscriptions ) ) {
			return;
		}
		$email_service = new EmailService();
		foreach ( $subscriptions as $subscription ) {
			$user_id      = $subscription['member_id'];
			$checked_date = get_user_meta( $user_id, 'urm_expired_reminder_sent_for_date', true );
			if ( $checked_date === $subscription['expiry_date'] ) {
				continue;
			}
			$email_service->send_email( $subscription, 'membership_ended' );
			update_user_meta( $subscription['member_id'], 'urm_expired_reminder_sent_for_date', $subscription['expiry_date'] );
		}
	}

	/**
	 * daily_membership_expiration_check
	 * Check for memberships that have passed their expiry date and mark them as expired
	 *
	 * @return void
	 */
	public function daily_membership_expiration_check() {
		$date          = new \DateTime( 'today' );
		$check_date    = $date->format( 'Y-m-d H:i:s' );
		$subscriptions = $this->members_subscription_repository->get_subscriptions_to_expire( $check_date );
		if ( empty( $subscriptions ) ) {
			ur_get_logger()->notice(
				sprintf(
					__( 'No memberships found to expire for date: %s', 'user-registration' ),
					$check_date
				),
				array( 'source' => 'urm-membership-expiration' )
			);
			return;
		}

		$expired_count = 0;
		$expired_users = array();

		foreach ( $subscriptions as $subscription ) {
			$subscription_id = $subscription['subscription_id'];
			$user_id         = $subscription['member_id'];
			$membership_id   = isset( $subscription['membership'] ) ? absint( $subscription['membership'] ) : 0;
			$last_order      = $this->members_orders_repository->get_member_orders( $user_id );

			if ( $last_order['order_type'] !== 'subscription' ) {
				continue;
			}
			// Update subscription status to expired
			$update_result = $this->members_subscription_repository->update( $subscription_id, array( 'status' => 'expired' ) );

			if ( $update_result ) {
				++$expired_count;
				$expired_users[] = $subscription['username'];

				// Log the expiration
				ur_get_logger()->notice(
					sprintf(
						__( 'Membership expired for user %1$s (ID: %2$d) - Subscription ID: %3$d', 'user-registration' ),
						$subscription['username'],
						$user_id,
						$subscription_id
					),
					array( 'source' => 'urm-membership-expiration' )
				);

				// Prepare data to trigger subscription expired event.
				$payload = array(
					'subscription_id' => $subscription_id,
					'member_id'       => $user_id,
					'event_type'      => 'expired',
					'meta'            => array(
						'membership_id' => $membership_id,
					),
				);

				do_action( 'ur_membership_subscription_event_triggered', $payload );
			} else {
				ur_get_logger()->error(
					sprintf(
						__( 'Failed to expire membership for user %1$s (ID: %2$d) - Subscription ID: %3$d', 'user-registration' ),
						$subscription['username'],
						$user_id,
						$subscription_id
					),
					array( 'source' => 'urm-membership-expiration' )
				);
			}
		}

		ur_get_logger()->notice(
			sprintf(
				__( 'Membership expiration check completed. %1$d memberships expired for users: %2$s', 'user-registration' ),
				$expired_count,
				implode( ', ', $expired_users )
			),
			array( 'source' => 'urm-membership-expiration' )
		);
	}


	/**
	 * Callback for payment retry check.
	 */
	public function daily_payment_retry_check() {

		$subscriptions = $this->members_subscription_repository->get_subscriptions_to_retry();
		$expired_count = 0;
		$expired_users = array();
		foreach ( $subscriptions as $subscription ) {
			//only handle the subscription case.
			if ( $subscription['order_type'] !== 'subscription' ) {
				continue;
			}

			// Update subscription status to expired
			// $update_result = $this->members_subscription_repository->update( $subscription_id, array( 'status' => 'expired' ) );
			$this->failed_payment_retry_callback( $subscription );
		}
	}

	/**
	 * Payment retry callback for a failed attempt.
	 */
	public function failed_payment_retry_callback( $subscription ) {
		//update the counter for failed payment retry.
		$retry_count = (int) get_user_meta( $subscription['member_id'], 'urm_is_payment_retrying', true );
		update_user_meta( $subscription['member_id'], 'urm_is_payment_retrying', $retry_count + 1 );
		switch ( $subscription['payment_method'] ) {
			case 'paypal':
				$paypal_service = new PaypalService();
				$paypal_service->retry_subscription( $subscription );
				break;
			case 'stripe':
				$stripe_service = new StripeService();
				$stripe_service->retry_subscription( $subscription );
				break;
			default:
				do_action( 'urm_handle_failed_payment_retry', $subscription );
				break;
		}
	}

	/**
	 * Check if user membership expired.
	 *
	 * @param int $user_id User ID.
	 * @param int $subscription_id Subscription ID.
	 * @return boolean
	 */
	public function is_user_membership_expired($user_id, $subscription_id) {
		$subscription = $this->members_subscription_repository->retrieve( $subscription_id );

		if ( empty( $subscription ) || $subscription['user_id'] != $user_id ) {
			return false;
		}

		if( $subscription['status'] === 'expired' ) {
			return true;
		}

		if (empty($subscription['expiry_date'])) {
			return false;
		}

		if( empty( $subscription['billing_cycle'] ) ) {
			return false;
		}

		try {
			$expiry_date = new \DateTime($subscription['expiry_date']);
		} catch (\Exception $e) {
			return false;
		}

		$today       = new \DateTime( 'today' );

		return $expiry_date <= $today;
	}
}
