<?php
/**
 * Floating Sidebar
 *
 * Renders the floating related posts widget in wp_footer.
 * Supports 5 variants, configurable position, auto-refresh, and dismissal.
 *
 * @package     Relatedly\Theming\Floating
 * @since       2.0.0
 * @fs_premium_only
 */

namespace Relatedly\Theming\Floating;

use Relatedly\Core\Options;
use Relatedly\Core\QueryBuilder;
use Relatedly\Premium\FeatureGate;

defined( 'ABSPATH' ) || exit;

/**
 * Renders and refreshes the premium floating sidebar.
 *
 * @since 2.0.0
 */
class Sidebar {

	/**
	 * Plugin settings repository.
	 *
	 * @since 2.0.0
	 * @var Options
	 */
	private Options $options;

	/**
	 * Related posts query builder.
	 *
	 * @since 2.0.0
	 * @var QueryBuilder
	 */
	private QueryBuilder $query;

	/**
	 * Create the floating sidebar service.
	 *
	 * @since 2.0.0
	 * @param Options      $options Plugin settings repository.
	 * @param QueryBuilder $query   Related posts query builder.
	 */
	public function __construct( Options $options, QueryBuilder $query ) {
		$this->options = $options;
		$this->query   = $query;
	}

	/**
	 * Register sidebar rendering and refresh hooks.
	 *
	 * @since 2.0.0
	 */
	public function init_hooks(): void {
		if ( ! FeatureGate::can_use_floating_sidebar() ) {
			return;
		}

		if ( ! $this->options->get( 'floating_sidebar_enabled', false ) ) {
			return;
		}
		add_action( 'wp_footer', array( $this, 'render' ), 20 );
		add_action( 'wp_ajax_relatedly_floating_sidebar_refresh', array( $this, 'ajax_refresh' ) );
		add_action( 'wp_ajax_nopriv_relatedly_floating_sidebar_refresh', array( $this, 'ajax_refresh' ) );
	}

	/**
	 * Output the floating sidebar HTML in wp_footer.
	 *
	 * @since 2.0.0
	 */
	public function render(): void {
		if ( ! is_single() ) {
			return;
		}

		$post = get_post();
		if ( ! $post ) {
			return;
		}

		$enabled_types = (array) $this->options->get( 'post_types', array( 'post' ) );
		if ( ! in_array( get_post_type( $post ), $enabled_types, true ) ) {
			return;
		}

		$num_posts = (int) $this->options->get( 'floating_sidebar_num_posts', 1 );
		$posts     = $this->query->get_related_posts( $post->ID, $num_posts, 'floating' );

		if ( empty( $posts ) ) {
			return;
		}

		$variant  = (string) $this->options->get( 'floating_sidebar_variant', 'variant1' );
		$position = (string) $this->options->get( 'floating_sidebar_position', 'right' );
		$z_index  = (int) $this->options->get( 'floating_sidebar_z_index', 9999 );

		$renderer = $this->get_variant_renderer( $variant );

		echo '<div class="relatedly-floating-sidebar relatedly-floating-' . esc_attr( $position ) . '" '
			. 'style="z-index:' . esc_attr( $z_index ) . ';" '
			. 'data-relatedly-source="' . esc_attr( $post->ID ) . '" '
			. 'data-relatedly-type="floating">';

		echo '<button class="relatedly-floating-close" aria-label="' . esc_attr__( 'Close', 'relatedly' ) . '">&times;</button>';

		foreach ( $posts as $related_post ) {
			echo $renderer->render( array( $related_post ), $post->ID ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- rendered by theme class
		}

		echo '</div>';

		$this->output_inline_js( $post->ID );
	}

	/**
	 * AJAX handler for auto-refresh.
	 *
	 * @since 2.0.0
	 */
	public function ajax_refresh(): void {
		if ( ! wp_verify_nonce(
			sanitize_text_field( wp_unslash( $_POST['nonce'] ?? '' ) ),
			'relatedly_floating_sidebar_refresh'
		) ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'relatedly' ) ) );
		}

		$post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
		if ( ! $post_id || ! get_post( $post_id ) ) {
			wp_send_json_error( array( 'message' => __( 'Invalid post.', 'relatedly' ) ) );
		}

		$num_posts = (int) $this->options->get( 'floating_sidebar_num_posts', 1 );
		$posts     = $this->query->get_related_posts( $post_id, $num_posts, 'floating' );
		$variant   = (string) $this->options->get( 'floating_sidebar_variant', 'variant1' );
		$renderer  = $this->get_variant_renderer( $variant );

		$html = '';
		foreach ( $posts as $post ) {
			$html .= $renderer->render( array( $post ), $post_id );
		}

		wp_send_json_success( array( 'html' => $html ) );
	}

	// -------------------------------------------------------------------------
	// Internal
	// -------------------------------------------------------------------------

	/**
	 * Create the selected floating variant renderer.
	 *
	 * @param string $variant Variant key.
	 * @return \Relatedly\Theming\AbstractTheme
	 */
	private function get_variant_renderer( string $variant ): \Relatedly\Theming\AbstractTheme {
		$map = array(
			'variant1' => Variants\Variant1::class,
			'variant2' => Variants\Variant2::class,
			'variant3' => Variants\Variant3::class,
			'variant4' => Variants\Variant4::class,
			'variant5' => Variants\Variant5::class,
		);

		$class = $map[ $variant ] ?? $map['variant1'];

		$labels = new \Relatedly\Labels\LabelProvider( $this->options );
		return new $class( $this->options, $labels );
	}

	/**
	 * Print the runtime settings consumed by the frontend script.
	 *
	 * @param int $post_id Source post ID.
	 */
	private function output_inline_js( int $post_id ): void {
		$auto_refresh         = (bool) $this->options->get( 'floating_sidebar_auto_refresh_enabled', false );
		$auto_refresh_seconds = (int) $this->options->get( 'floating_sidebar_auto_refresh_seconds', 10 );
		$dismiss_behavior     = (string) $this->options->get( 'floating_sidebar_dismiss_behavior', 'per_page' );
		$scroll_trigger       = (string) $this->options->get( 'floating_sidebar_display_trigger', 'always' );
		$scroll_pct           = (int) $this->options->get( 'floating_sidebar_scroll_percentage', 25 );

		wp_add_inline_script(
			'relatedly-tracking',
			sprintf(
				'window.relatedlyFloating = %s;',
				wp_json_encode(
					array(
						'ajaxUrl'            => admin_url( 'admin-ajax.php' ),
						'nonce'              => wp_create_nonce( 'relatedly_floating_sidebar_refresh' ),
						'postId'             => $post_id,
						'autoRefresh'        => $auto_refresh,
						'autoRefreshSeconds' => $auto_refresh_seconds,
						'dismissBehavior'    => $dismiss_behavior,
						'scrollTrigger'      => $scroll_trigger,
						'scrollPct'          => $scroll_pct,
					)
				)
			)
		);
	}
}
