<?php
/**
 * Public-facing shortcodes and checkout.
 *
 * @package Lucrativeit_Subscription_Recurring_Billing
 */

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

class LUCRSURE_Frontend {

	protected static $assets_enqueued = false;

	/** @var bool */
	protected static $appearance_css_added = false;

	/** @var self|null */
	protected static $instance = null;

	/**
	 * @return self
	 */
	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Register checkout AJAX handlers as early as possible.
	 */
	public static function register_ajax_handlers() {
		static $registered = false;
		if ( $registered ) {
			return;
		}
		$registered = true;
		$handler    = array( self::instance(), 'ajax_checkout' );
		add_action( 'wp_ajax_lucrsure_public_checkout', $handler );
		add_action( 'wp_ajax_nopriv_lucrsure_public_checkout', $handler );
	}

	public function init() {
		static $booted = false;
		if ( $booted ) {
			return;
		}
		$booted = true;

		self::register_ajax_handlers();
		add_shortcode( 'lucrsure_plans', array( $this, 'render_plans_shortcode' ) );
		add_shortcode( 'lucrsure_plan_grid', array( $this, 'render_plan_grid_shortcode' ) );
		add_shortcode( 'lucrsure_hero', array( $this, 'render_hero_shortcode' ) );
		add_shortcode( 'lucrsure_locations', array( $this, 'render_locations_shortcode' ) );
		add_shortcode( 'lucrsure_faq', array( $this, 'render_faq_shortcode' ) );
		add_shortcode( 'lucrsure_locations_plans', array( $this, 'render_locations_plans_shortcode' ) );

		add_action( 'wp_enqueue_scripts', array( $this, 'register_assets' ) );
		add_action( 'wp_footer', array( $this, 'render_payment_notice' ) );
	}

	public function register_assets() {
		$css_path = LUCRSURE_PLUGIN_DIR . 'public/css/lucrsure-public.css';
		$js_path  = LUCRSURE_PLUGIN_DIR . 'public/js/lucrsure-public.js';
		$css_ver  = file_exists( $css_path ) ? (string) filemtime( $css_path ) : LUCRSURE_VERSION;
		$js_ver   = file_exists( $js_path ) ? (string) filemtime( $js_path ) : LUCRSURE_VERSION;

		wp_register_style( 'lucrsure-public', LUCRSURE_PLUGIN_URL . 'public/css/lucrsure-public.css', array(), $css_ver );
		wp_register_script( 'lucrsure-public', LUCRSURE_PLUGIN_URL . 'public/js/lucrsure-public.js', array( 'jquery' ), $js_ver, true );
	}

	protected function enqueue_public_styles() {
		if ( ! wp_style_is( 'lucrsure-public', 'registered' ) ) {
			$this->register_assets();
		}

		wp_enqueue_style( 'lucrsure-public' );

		if ( ! self::$appearance_css_added ) {
			wp_add_inline_style( 'lucrsure-public', lucrsure_frontend_appearance_css() );
			self::$appearance_css_added = true;
		}
	}

	protected function enqueue_assets( array $config ) {
		if ( self::$assets_enqueued ) {
			wp_localize_script( 'lucrsure-public', 'LUCRSUREPublic', $config );
			return;
		}

		$this->enqueue_public_styles();
		wp_enqueue_script( 'lucrsure-public' );
		wp_localize_script( 'lucrsure-public', 'LUCRSUREPublic', $config );
		wp_add_inline_script(
			'lucrsure-public',
			'window.LUCRSUREPublic = Object.assign( window.LUCRSUREPublic || {}, ' . wp_json_encode( $config ) . ' );',
			'before'
		);
		self::$assets_enqueued = true;
	}

	public function render_plans_shortcode( $atts ) {
		return $this->build_plans_markup( $atts );
	}

	/**
	 * Backward-compatible alias for the grid template.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return string
	 */
	public function render_plan_grid_shortcode( $atts ) {
		$atts = is_array( $atts ) ? $atts : array();
		$atts['template'] = 'grid';
		if ( empty( $atts['plans_heading'] ) ) {
			if ( ! empty( $atts['heading'] ) ) {
				$atts['plans_heading'] = $atts['heading'];
			} elseif ( ! empty( $atts['title'] ) ) {
				$atts['plans_heading'] = $atts['title'];
			}
		}
		return $this->build_plans_markup( $atts );
	}

	/**
	 * Render hero section only.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return string
	 */
	public function render_hero_shortcode( $atts ) {
		$atts = shortcode_atts(
			array(
				'title'            => '',
				'heading'          => '',
				'hero_heading'     => '',
				'subtitle'         => '',
				'hero_subtitle'    => '',
				'button_text'      => '',
				'hero_button_text' => '',
				'button_url'       => '',
				'hero_button_url'  => '',
				'image'            => '',
				'image_path'       => '',
				'image_id'         => 0,
				'show_hero'        => 'yes',
			),
			$atts,
			'lucrsure_hero'
		);

		if ( ! $this->should_show_hero( $atts ) ) {
			return '';
		}

		$this->enqueue_public_styles();

		return $this->build_hero_markup( $atts );
	}

	/**
	 * Render branch locations grid only.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return string
	 */
	public function render_locations_shortcode( $atts ) {
		$atts = shortcode_atts(
			array(
				'heading'        => '',
				'subtitle'       => '',
				'branches'       => '',
				'show_locations' => 'yes',
			),
			$atts,
			'lucrsure_locations'
		);

		if ( ! $this->should_show_locations( $atts ) ) {
			return '';
		}

		$this->enqueue_public_styles();

		return $this->build_locations_markup( $atts );
	}

	/**
	 * Render FAQ section only.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return string
	 */
	public function render_faq_shortcode( $atts ) {
		$atts = shortcode_atts(
			array(
				'heading'      => '',
				'faq_heading'  => '',
				'subtitle'     => '',
				'faq_subtitle' => '',
				'show_faq'     => 'yes',
			),
			$atts,
			'lucrsure_faq'
		);

		if ( ! $this->should_show_faq( $atts ) ) {
			return '';
		}

		$this->enqueue_public_styles();

		return $this->build_faq_markup( $atts );
	}

	/**
	 * Render locations section followed by subscription packages.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return string
	 */
	public function render_locations_plans_shortcode( $atts ) {
		$atts = shortcode_atts(
			array(
				'category'           => '',
				'category_id'        => 0,
				'interval'           => 'month',
				'show_intervals'     => 'yes',
				'popular'            => 0,
				'subtitle'           => '',
				'footer'             => __( 'Prices in USD. Trial periods apply when configured on the plan.', 'lucrativeit-subscription-recurring-billing' ),
				'locations_heading'  => '',
				'locations_subtitle' => '',
				'branches'           => '',
				'show_locations'     => '',
				'title'              => '',
				'hero_heading'       => '',
				'hero_subtitle'      => '',
				'hero_button_text'   => '',
				'hero_button_url'    => '',
				'image'              => '',
				'image_path'         => '',
				'image_id'           => 0,
				'show_hero'          => '',
				'faq_heading'        => '',
				'faq_subtitle'       => '',
				'show_faq'           => '',
				'template'           => '',
			),
			$atts,
			'lucrsure_locations_plans'
		);

		$this->enqueue_public_styles();
		wp_enqueue_script( 'lucrsure-public' );

		$parts = array();

		if ( $this->should_show_hero( $atts ) ) {
			$hero_html = $this->build_hero_markup( $atts );
			if ( '' !== $hero_html ) {
				$parts[] = $hero_html;
			}
		}

		if ( $this->should_show_locations( $atts ) ) {
			$locations_html = $this->build_locations_markup(
				array(
					'heading'  => $atts['locations_heading'],
					'subtitle' => $atts['locations_subtitle'],
					'branches' => $atts['branches'],
				)
			);
			if ( '' !== $locations_html ) {
				$parts[] = $locations_html;
			}
		}

		$parts[] = $this->build_plans_markup( $atts );

		if ( $this->should_show_faq( $atts ) ) {
			$faq_html = $this->build_faq_markup( $atts );
			if ( '' !== $faq_html ) {
				$parts[] = $faq_html;
			}
		}

		if ( 1 === count( $parts ) ) {
			return $parts[0];
		}

		return '<div class="lucrsure-category-page">' . implode( '', $parts ) . '</div>';
	}

	/**
	 * Whether the hero section should render.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return bool
	 */
	protected function should_show_hero( array $atts ) {
		if ( isset( $atts['show_hero'] ) && '' !== $atts['show_hero'] ) {
			return 'no' !== strtolower( (string) $atts['show_hero'] );
		}

		$frontend = lucrsure_frontend_settings();
		return ! empty( $frontend['hero_enabled'] );
	}

	/**
	 * Whether the FAQ section should render.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return bool
	 */
	protected function should_show_faq( array $atts ) {
		if ( isset( $atts['show_faq'] ) && '' !== $atts['show_faq'] ) {
			return 'no' !== strtolower( (string) $atts['show_faq'] );
		}

		$frontend = lucrsure_frontend_settings();
		return ! empty( $frontend['faq_enabled'] );
	}

	/**
	 * Build hero section HTML.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return string
	 */
	protected function build_hero_markup( array $atts ) {
		$frontend = lucrsure_frontend_settings();

		$heading = $this->resolve_hero_heading( $atts, $frontend );
		$subtitle = '' !== (string) ( $atts['hero_subtitle'] ?? '' )
			? (string) $atts['hero_subtitle']
			: ( '' !== (string) ( $atts['subtitle'] ?? '' )
				? (string) $atts['subtitle']
				: (string) $frontend['hero_subtitle'] );
		$button_text = '' !== (string) ( $atts['hero_button_text'] ?? '' )
			? (string) $atts['hero_button_text']
			: ( '' !== (string) ( $atts['button_text'] ?? '' )
				? (string) $atts['button_text']
				: (string) $frontend['hero_button_text'] );
		$button_url = '' !== (string) ( $atts['hero_button_url'] ?? '' )
			? (string) $atts['hero_button_url']
			: ( '' !== (string) ( $atts['button_url'] ?? '' )
				? (string) $atts['button_url']
				: (string) $frontend['hero_button_url'] );

		if ( '' === trim( $heading ) && '' === trim( $subtitle ) ) {
			return '';
		}

		if ( '' === $button_url ) {
			$button_url = '#lucrsure-plans';
		}

		$view_data = array(
			'instance_id' => lucrsure_frontend_section_id( 'hero' ),
			'heading'     => $heading,
			'subtitle'    => $subtitle,
			'button_text' => $button_text,
			'button_url'  => $button_url,
			'image_url'   => $this->resolve_hero_image_url( $atts, $frontend ),
		);

		if ( ! empty( $view_data['image_url'] ) ) {
			$this->enqueue_public_styles();
			$hero_selector = '#' . sanitize_html_class( $view_data['instance_id'] );
			$hero_image    = lucrsure_esc_css_url( $view_data['image_url'] );
			if ( '' !== $hero_image ) {
				$hero_css = $hero_selector . '{--lucrsure-hero-image:url("' . $hero_image . '");}';
				wp_add_inline_style( 'lucrsure-public', $hero_css );
			}
		}

		ob_start();
		// phpcs:ignore WordPress.PHP.DontExtract.extract_extract
		extract( $view_data, EXTR_SKIP );
		include LUCRSURE_PLUGIN_DIR . 'public/views/hero.php';
		return (string) ob_get_clean();
	}

	/**
	 * Build FAQ section HTML.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return string
	 */
	protected function build_faq_markup( array $atts ) {
		$frontend = lucrsure_frontend_settings();
		$heading  = '' !== (string) ( $atts['faq_heading'] ?? '' )
			? (string) $atts['faq_heading']
			: ( '' !== (string) ( $atts['heading'] ?? '' )
				? (string) $atts['heading']
				: (string) $frontend['faq_heading'] );
		$subtitle = '' !== (string) ( $atts['faq_subtitle'] ?? '' )
			? (string) $atts['faq_subtitle']
			: ( '' !== (string) ( $atts['subtitle'] ?? '' )
				? (string) $atts['subtitle']
				: (string) $frontend['faq_subtitle'] );
		$items    = lucrsure_normalize_faq_items( $frontend['faq_items'] );

		if ( empty( $items ) ) {
			return '';
		}

		$view_data = array(
			'instance_id' => lucrsure_frontend_section_id( 'faq' ),
			'heading'     => $heading,
			'subtitle'    => $subtitle,
			'items'       => $items,
		);

		ob_start();
		// phpcs:ignore WordPress.PHP.DontExtract.extract_extract
		extract( $view_data, EXTR_SKIP );
		include LUCRSURE_PLUGIN_DIR . 'public/views/faq.php';
		return (string) ob_get_clean();
	}

	/**
	 * Resolve hero heading from shortcode attributes or settings.
	 *
	 * @param array $atts     Shortcode attributes.
	 * @param array $frontend Frontend settings.
	 * @return string
	 */
	protected function resolve_hero_heading( array $atts, array $frontend ) {
		if ( '' !== (string) ( $atts['title'] ?? '' ) ) {
			return (string) $atts['title'];
		}
		if ( '' !== (string) ( $atts['hero_heading'] ?? '' ) ) {
			return (string) $atts['hero_heading'];
		}
		if ( '' !== (string) ( $atts['heading'] ?? '' ) ) {
			return (string) $atts['heading'];
		}

		return (string) $frontend['hero_heading'];
	}

	/**
	 * Resolve hero image URL from shortcode attributes or settings.
	 *
	 * @param array $atts     Shortcode attributes.
	 * @param array $frontend Frontend settings.
	 * @return string
	 */
	protected function resolve_hero_image_url( array $atts, array $frontend ) {
		if ( '' !== (string) ( $atts['image_path'] ?? '' ) ) {
			return esc_url( (string) $atts['image_path'] );
		}
		if ( '' !== (string) ( $atts['image'] ?? '' ) ) {
			return esc_url( (string) $atts['image'] );
		}

		$image_id = (int) ( $atts['image_id'] ?? 0 );
		if ( $image_id <= 0 ) {
			$image_id = (int) $frontend['hero_image_id'];
		}

		return lucrsure_hero_image_url( $image_id );
	}

	/**
	 * Whether the locations section should render.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return bool
	 */
	protected function should_show_locations( array $atts ) {
		if ( isset( $atts['show_locations'] ) && '' !== $atts['show_locations'] ) {
			return 'no' !== strtolower( (string) $atts['show_locations'] );
		}

		$frontend = lucrsure_frontend_settings();
		return ! empty( $frontend['locations_enabled'] );
	}

	/**
	 * Resolve branches for the locations section.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return array[]
	 */
	protected function resolve_location_branches( array $atts ) {
		$repo = new LUCRSURE_Branch_Repository();
		$ids  = array();

		if ( ! empty( $atts['branches'] ) ) {
			$ids = array_map( 'absint', array_filter( array_map( 'trim', explode( ',', (string) $atts['branches'] ) ) ) );
		} else {
			$frontend = lucrsure_frontend_settings();
			$ids      = array_map( 'absint', (array) $frontend['locations_branch_ids'] );
		}

		return $repo->for_display( $ids );
	}

	/**
	 * Build locations section HTML.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return string
	 */
	protected function build_locations_markup( array $atts ) {
		$this->enqueue_public_styles();

		$frontend = lucrsure_frontend_settings();
		$heading  = '' !== (string) $atts['heading'] ? (string) $atts['heading'] : (string) $frontend['locations_heading'];
		$subtitle = '' !== (string) $atts['subtitle'] ? (string) $atts['subtitle'] : (string) $frontend['locations_subtitle'];
		$branches = $this->resolve_location_branches( $atts );

		if ( empty( $branches ) ) {
			return '';
		}

		$view_data = array(
			'instance_id' => lucrsure_frontend_section_id( 'locations' ),
			'heading'     => $heading,
			'subtitle'    => $subtitle,
			'branches'    => $branches,
		);

		ob_start();
		// phpcs:ignore WordPress.PHP.DontExtract.extract_extract
		extract( $view_data, EXTR_SKIP );
		include LUCRSURE_PLUGIN_DIR . 'public/views/locations.php';
		return (string) ob_get_clean();
	}

	/**
	 * Build subscription packages markup.
	 *
	 * @param array $atts Shortcode attributes.
	 * @return string
	 */
	protected function build_plans_markup( $atts ) {
		$settings = new LUCRSURE_Settings();
		if ( 'woocommerce' === $settings->get( 'subscription_engine', 'custom' ) ) {
			return '<p class="lucrsure-public-notice">' . esc_html__( 'Plan checkout is not available while WooCommerce engine mode is active.', 'lucrativeit-subscription-recurring-billing' ) . '</p>';
		}

		$atts = shortcode_atts(
			array(
				'category'       => '',
				'category_id'    => 0,
				'interval'       => 'month',
				'show_intervals' => 'yes',
				'popular'        => 0,
				'plans_heading'  => '',
				'plans_subtitle' => '',
				'subtitle'       => '',
				'footer'         => __( 'Prices in USD. Trial periods apply when configured on the plan.', 'lucrativeit-subscription-recurring-billing' ),
				'template'       => '',
				'button_text'    => '',
			),
			$atts,
			'lucrsure_plans'
		);

		$frontend       = lucrsure_frontend_settings();
		$template       = lucrsure_resolve_plans_template( $atts );
		$plans_heading  = '' !== (string) $atts['plans_heading']
			? (string) $atts['plans_heading']
			: (string) $frontend['plans_heading'];
		$plans_subtitle = '';
		if ( '' !== (string) $atts['subtitle'] ) {
			$plans_subtitle = (string) $atts['subtitle'];
		} elseif ( '' !== (string) $atts['plans_subtitle'] ) {
			$plans_subtitle = (string) $atts['plans_subtitle'];
		} else {
			$plans_subtitle = (string) $frontend['plans_subtitle'];
		}

		$cat_repo = new LUCRSURE_Plan_Category_Repository();
		$category = null;

		if ( '' !== $atts['category'] ) {
			$category = $cat_repo->find_by_slug( $atts['category'] );
		} elseif ( (int) $atts['category_id'] > 0 ) {
			$category = $cat_repo->find( (int) $atts['category_id'] );
		}

		if ( ! $category || empty( $category['is_active'] ) ) {
			return '<p class="lucrsure-public-notice">' . esc_html__( 'No plan category found for this shortcode.', 'lucrativeit-subscription-recurring-billing' ) . '</p>';
		}

		$plan_repo = new LUCRSURE_Plan_Repository();
		$plans     = 'grid' === $template
			? $plan_repo->active_for_category_ungrouped( $category )
			: $plan_repo->active_for_category( $category );

		if ( empty( $plans ) ) {
			return '<p class="lucrsure-public-notice">' . esc_html__( 'No active plans in this category yet.', 'lucrativeit-subscription-recurring-billing' ) . '</p>';
		}

		$intervals_present = array();
		foreach ( $plans as $plan ) {
			$key = sanitize_key( $plan['billing_interval'] );
			if ( '' !== $key ) {
				$intervals_present[ $key ] = true;
			}
		}

		$interval_order   = array_keys( lucrsure_billing_intervals() );
		$default_interval = sanitize_key( $atts['interval'] );
		if ( empty( $intervals_present[ $default_interval ] ) ) {
			foreach ( $interval_order as $key ) {
				if ( ! empty( $intervals_present[ $key ] ) ) {
					$default_interval = $key;
					break;
				}
			}
		}

		$gateways        = $this->enabled_gateways();
		$default_gateway = $settings->get( 'default_gateway', 'manual' );
		if ( ! isset( $gateways[ $default_gateway ] ) && ! empty( $gateways ) ) {
			$default_gateway = (string) array_key_first( $gateways );
		}

		$instance_id = 'lucrsure-plans-' . wp_unique_id();
		$ajax_url    = admin_url( 'admin-ajax.php' );
		$nonce       = wp_create_nonce( 'lucrsure_public_checkout' );

		$this->enqueue_assets(
			array(
				'ajaxUrl' => $ajax_url,
				'nonce'   => $nonce,
				'i18n'    => array(
					'selectPlan'       => __( 'Please select a plan.', 'lucrativeit-subscription-recurring-billing' ),
					'nameRequired'     => __( 'Full name is required.', 'lucrativeit-subscription-recurring-billing' ),
					'emailRequired'    => __( 'A valid email address is required.', 'lucrativeit-subscription-recurring-billing' ),
					'addressRequired'  => __( 'Please complete your billing address.', 'lucrativeit-subscription-recurring-billing' ),
					'processing'       => __( 'Processing…', 'lucrativeit-subscription-recurring-billing' ),
					'checkoutFailed'   => __( 'Could not complete checkout. Please try again.', 'lucrativeit-subscription-recurring-billing' ),
					'sessionExpired'   => __( 'Session expired. Please refresh the page and try again.', 'lucrativeit-subscription-recurring-billing' ),
					'ajaxNotFound'     => __( 'Checkout endpoint not found. Please refresh the page and try again.', 'lucrativeit-subscription-recurring-billing' ),
					'completeSub'      => __( 'Complete subscription', 'lucrativeit-subscription-recurring-billing' ),
				),
			)
		);

		$view_data = array(
			'instance_id'        => $instance_id,
			'checkout_ajax_url'  => $ajax_url,
			'checkout_nonce'     => $nonce,
			'category'           => $category,
			'plans'              => $plans,
			'intervals'          => lucrsure_billing_intervals(),
			'interval_order'     => $interval_order,
			'intervals_present'  => $intervals_present,
			'default_interval'   => $default_interval,
			'show_intervals'     => 'no' !== strtolower( $atts['show_intervals'] ),
			'popular_plan_id'    => (int) $atts['popular'],
			'plans_heading'      => $plans_heading,
			'subtitle'           => $plans_subtitle,
			'footer'             => $atts['footer'],
			'gateways'           => $gateways,
			'default_gateway'    => $default_gateway,
			'settings'           => $settings,
			'template'           => $template,
			'button_text'        => '' !== (string) $atts['button_text'] ? (string) $atts['button_text'] : __( 'Join now', 'lucrativeit-subscription-recurring-billing' ),
		);

		if ( 'grid' === $template ) {
			$view_data = array_merge( $view_data, $this->plan_grid_context( $plans ) );
			$view_data['heading']           = $plans_heading;
			$view_data['checkout_url']      = '#lucrsure-plans';
			$view_data['grid_instance_id']  = 'lucrsure-plan-grid';
		}

		ob_start();
		// Template expects individual variables from the view data array.
		// phpcs:ignore WordPress.PHP.DontExtract.extract_extract
		extract( $view_data, EXTR_SKIP );
		include LUCRSURE_PLUGIN_DIR . 'public/views/plans-checkout.php';
		return (string) ob_get_clean();
	}

	/**
	 * Branch / interval filter data for the grid template.
	 *
	 * @param array[] $plans Plan rows.
	 * @return array
	 */
	protected function plan_grid_context( array $plans ) {
		$branch_repo  = new LUCRSURE_Branch_Repository();
		$all_branches = $branch_repo->active();
		$branch_names = array();
		$branch_images = array();

		foreach ( $all_branches as $branch ) {
			$branch_id = (int) $branch['id'];
			$branch_names[ $branch_id ] = $branch['name'];
			$image_url = LUCRSURE_Branch_Repository::image_url( $branch, 'large' );
			if ( $image_url ) {
				$branch_images[ $branch_id ] = $image_url;
			}
		}

		$intervals_present = array();
		foreach ( $plans as $plan ) {
			$interval_key = sanitize_key( $plan['billing_interval'] );
			if ( '' !== $interval_key ) {
				$intervals_present[ $interval_key ] = true;
			}
		}

		$filter_intervals = array();
		foreach ( array_keys( lucrsure_billing_intervals() ) as $interval_key ) {
			if ( ! empty( $intervals_present[ $interval_key ] ) ) {
				$filter_intervals[] = $interval_key;
			}
		}

		return array(
			'filter_branches'    => $all_branches,
			'filter_intervals'   => $filter_intervals,
			'branch_names'       => $branch_names,
			'branch_images'      => $branch_images,
			'show_branch_filter' => ! empty( $all_branches ),
			'show_type_filter'   => ! empty( $filter_intervals ),
		);
	}

	protected function enabled_gateways() {
		$out     = array();
		$manager = LUCRSURE_Gateway_Manager::instance();
		foreach ( $manager->enabled() as $gateway ) {
			$out[ $gateway->get_id() ] = $gateway->get_title();
		}
		return $out;
	}

	public function ajax_checkout() {
		$nonce = isset( $_POST['nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['nonce'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
		if ( ! wp_verify_nonce( $nonce, 'lucrsure_public_checkout' ) ) {
			wp_send_json_error(
				array( 'message' => __( 'Security check failed. Please refresh the page and try again.', 'lucrativeit-subscription-recurring-billing' ) ),
				403
			);
		}

		$settings = new LUCRSURE_Settings();
		if ( 'woocommerce' === $settings->get( 'subscription_engine', 'custom' ) ) {
			wp_send_json_error( array( 'message' => __( 'Checkout is unavailable in WooCommerce mode.', 'lucrativeit-subscription-recurring-billing' ) ) );
		}

		$plan_id = isset( $_POST['plan_id'] ) ? absint( $_POST['plan_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification
		$name    = isset( $_POST['name'] ) ? sanitize_text_field( wp_unslash( $_POST['name'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
		$email   = isset( $_POST['email'] ) ? sanitize_email( wp_unslash( $_POST['email'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
		$phone   = isset( $_POST['phone'] ) ? sanitize_text_field( wp_unslash( $_POST['phone'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
		$gateway = isset( $_POST['gateway'] ) ? sanitize_key( wp_unslash( $_POST['gateway'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified above via wp_verify_nonce.
		$billing = lucrsure_sanitize_billing_address( wp_unslash( $_POST ) );

		if ( ! $plan_id || '' === $name || ! is_email( $email ) || ! lucrsure_billing_address_is_complete( $billing ) ) {
			wp_send_json_error( array( 'message' => __( 'Please fill in all required fields.', 'lucrativeit-subscription-recurring-billing' ) ) );
		}

		$gateways = $this->enabled_gateways();
		if ( empty( $gateways ) ) {
			wp_send_json_error( array( 'message' => __( 'No payment methods are enabled.', 'lucrativeit-subscription-recurring-billing' ) ) );
		}
		if ( ! isset( $gateways[ $gateway ] ) ) {
			$gateway = (string) array_key_first( $gateways );
		}

		$plan_repo = new LUCRSURE_Plan_Repository();
		$plan      = $plan_repo->find( $plan_id );
		if ( ! $plan || empty( $plan['is_active'] ) ) {
			wp_send_json_error( array( 'message' => __( 'This plan is no longer available.', 'lucrativeit-subscription-recurring-billing' ) ) );
		}

		$customer_data = array_merge(
			array(
				'name'   => $name,
				'phone'  => $phone,
				'status' => 'active',
			),
			$billing
		);

		if ( ! empty( $plan['branch_id'] ) ) {
			$customer_data['branch_id'] = (int) $plan['branch_id'];
		}

		$customer_repo = new LUCRSURE_Customer_Repository();
		$customer      = $customer_repo->find_by_email( $email );
		if ( $customer ) {
			if ( ! empty( $customer['branch_id'] ) ) {
				unset( $customer_data['branch_id'] );
			}
			$customer_repo->update( (int) $customer['id'], $customer_data );
			$customer_id = (int) $customer['id'];
		} else {
			$customer_data['email'] = $email;
			$customer_id            = $customer_repo->insert( $customer_data );
		}
		if ( ! $customer_id ) {
			wp_send_json_error( array( 'message' => __( 'Could not save customer details.', 'lucrativeit-subscription-recurring-billing' ) ) );
		}

		$start      = current_time( 'mysql' );
		$trial      = (int) $plan['trial_days'];
		$status     = lucrsure_public_checkout_subscription_status( $gateway, $trial );
		$trial_ends = $trial > 0 ? gmdate( 'Y-m-d H:i:s', strtotime( '+' . $trial . ' days', strtotime( $start ) ) ) : null;

		$sub_repo = new LUCRSURE_Subscription_Repository();
		$sub_id   = $sub_repo->insert(
			array(
				'customer_id'          => $customer_id,
				'plan_id'              => $plan_id,
				'status'               => $status,
				'quantity'             => 1,
				'mrr'                  => lucrsure_plan_effective_price( $plan ),
				'start_date'           => $start,
				'trial_ends'           => $trial_ends,
				'current_period_start' => $start,
				'current_period_end'   => lucrsure_next_period_end( $plan['billing_interval'], (int) $plan['interval_count'], $start ),
				'gateway'              => $gateway,
				'auto_renew'           => 1,
			)
		);
		if ( ! $sub_id ) {
			wp_send_json_error( array( 'message' => __( 'Could not create subscription.', 'lucrativeit-subscription-recurring-billing' ) ) );
		}

		$subscription = $sub_repo->find( $sub_id );
		if ( ! $subscription ) {
			wp_send_json_error( array( 'message' => __( 'Could not load the new subscription.', 'lucrativeit-subscription-recurring-billing' ) ) );
		}

		$checkout_result = LUCRSURE_Billing_Engine::instance()->start_subscription( $subscription );

		$invoice     = ( new LUCRSURE_Invoice_Repository() )->find_latest_for_subscription( $sub_id );
		$payment_url = ! empty( $checkout_result['payment_url'] ) ? $checkout_result['payment_url'] : '';
		if ( ! $payment_url && $invoice && ! empty( $invoice['payment_url'] ) ) {
			$payment_url = $invoice['payment_url'];
		}
		$gateway_obj = LUCRSURE_Gateway_Manager::instance()->get( $gateway );

		if ( $payment_url ) {
			wp_send_json_success(
				array(
					'redirect' => $payment_url,
					'message'  => __( 'Redirecting to secure payment…', 'lucrativeit-subscription-recurring-billing' ),
				)
			);
		}

		if ( 'manual' === $gateway || ( $gateway_obj && ! $gateway_obj->supports_automatic_recurring() ) ) {
			wp_send_json_success(
				array(
					'pending' => true,
					'message' => __( 'Subscription received! Your account is pending payment. We have emailed you an invoice with payment instructions.', 'lucrativeit-subscription-recurring-billing' ),
				)
			);
		}

		$error_message = ! empty( $checkout_result['error'] )
			? $checkout_result['error']
			: __( 'Online payment could not be started. Check your payment gateway settings or choose manual payment.', 'lucrativeit-subscription-recurring-billing' );

		wp_send_json_error(
			array(
				'message' => $error_message,
			)
		);
	}

	public function render_payment_notice() {
		// phpcs:ignore WordPress.Security.NonceVerification
		if ( empty( $_GET['lucrsure_payment'] ) ) {
			return;
		}
		// phpcs:ignore WordPress.Security.NonceVerification
		$status = sanitize_key( wp_unslash( $_GET['lucrsure_payment'] ) );
		if ( 'success' === $status ) {
			echo '<div class="lucrsure-public-banner is-success"><p>' . esc_html__( 'Thank you! Your payment was successful.', 'lucrativeit-subscription-recurring-billing' ) . '</p></div>';
		} elseif ( 'cancel' === $status ) {
			echo '<div class="lucrsure-public-banner is-warning"><p>' . esc_html__( 'Payment was cancelled.', 'lucrativeit-subscription-recurring-billing' ) . '</p></div>';
		}
	}
}
