<?php
/**
 * Referral code persistence service.
 *
 * Persists referral codes across page navigation using dual-layer storage
 * (cookie + localStorage) so the friend claim panel survives browsing.
 *
 * @package Awesomemotive\Rewardswp\Services
 * @since 1.4.1
 */

namespace Awesomemotive\Rewardswp\Services;

use Awesomemotive\Rewardswp\Helpers\CookieHelper;
use Awesomemotive\Rewardswp\Settings\Options\Referrals\ReferralVariableOption;
use function Awesomemotive\Rewardswp\Helpers\get_option_value;
use function Awesomemotive\Rewardswp\Helpers\is_current_user_a_member;

/**
 * Referral Code Service.
 *
 * @since 1.4.1
 */
class ReferralCodeService {

	/**
	 * Cookie and localStorage key for referral code.
	 *
	 * @since 1.4.1
	 */
	const REFERRAL_CODE_KEY = 'rewardswp_referral_code';

	/**
	 * Referral code expiration in days.
	 *
	 * @since 1.4.1
	 */
	const REFERRAL_CODE_DAYS_TO_EXPIRE = 30;

	/**
	 * Cookie helper instance.
	 *
	 * @since 1.4.1
	 *
	 * @var CookieHelper
	 */
	private CookieHelper $cookie_helper;

	/**
	 * Constructor.
	 *
	 * @since 1.4.1
	 *
	 * @param CookieHelper $cookie_helper Cookie Helper.
	 */
	public function __construct( CookieHelper $cookie_helper ) {
		$this->cookie_helper = $cookie_helper;
	}

	/**
	 * Get the active referral code from URL parameter or persisted cookie.
	 *
	 * Returns empty string when the ?rewardswp= query param is present (explicit
	 * panel navigation should not trigger friend claim mode) or when the user
	 * is already a member.
	 *
	 * @since 1.4.1
	 *
	 * @return string The referral code, or empty string if none active.
	 */
	public function get_active_referral_code(): string {
		$referral_slug     = get_option_value( ReferralVariableOption::class );
		$referral_code_raw = filter_input( INPUT_GET, $referral_slug );
		$referral_code     = $referral_code_raw ? sanitize_text_field( $referral_code_raw ) : '';

		// Fall back to persisted referral code from cookie if URL parameter is missing.
		if ( empty( $referral_code ) ) {
			$referral_code = $this->get_persisted_referral_code() ?? '';

			// Don't enter friend claim mode when explicitly navigating the rewards panel.
			if ( ! empty( $referral_code ) && ! empty( filter_input( INPUT_GET, 'rewardswp' ) ) ) {
				$referral_code = '';
			}
		}

		// No friend claim mode if user is already a member.
		if ( ! empty( $referral_code ) && is_current_user_a_member() ) {
			return '';
		}

		return $referral_code;
	}

	/**
	 * Persist the referral code in both cookie and localStorage.
	 *
	 * @since 1.4.1
	 *
	 * @param string $code The referral code.
	 *
	 * @return void
	 */
	public function persist_referral_code( string $code ): void {
		$this->set_cookie( $code );
		$this->save_to_local_storage( $code );
	}

	/**
	 * Get the persisted referral code from the cookie.
	 *
	 * @since 1.4.1
	 *
	 * @return string|null The referral code or null if not set.
	 */
	public function get_persisted_referral_code(): ?string {
		return $this->cookie_helper->get_cookie( self::REFERRAL_CODE_KEY );
	}

	/**
	 * Get the cookie domain used by CookieHelper.
	 *
	 * @since 1.4.1
	 *
	 * @return string The cookie domain.
	 */
	public function get_cookie_domain(): string {
		return $this->cookie_helper->get_cookie_domain();
	}

	/**
	 * Get the cookie path used by CookieHelper.
	 *
	 * @since 1.4.1
	 *
	 * @return string The cookie path.
	 */
	public function get_cookie_path(): string {
		return $this->cookie_helper->get_cookie_path();
	}

	/**
	 * Clear both cookie and localStorage persistence.
	 *
	 * @since 1.4.1
	 *
	 * @return void
	 */
	public function clear_persistence(): void {
		$this->clear_cookie();
		$this->clear_local_storage();
	}

	/**
	 * Clear the referral code cookie.
	 *
	 * Sets the cookie with an expired timestamp to remove it.
	 *
	 * @since 1.4.1
	 *
	 * @return void
	 */
	public function clear_cookie(): void {
		setcookie(
			self::REFERRAL_CODE_KEY,
			'',
			time() - DAY_IN_SECONDS,
			$this->cookie_helper->get_cookie_path(),
			$this->cookie_helper->get_cookie_domain()
		);
	}

	/**
	 * Clear the referral code from localStorage via inline script.
	 *
	 * @since 1.4.1
	 *
	 * @return void
	 */
	public function clear_local_storage(): void {
		wp_add_inline_script(
			AssetsService::MAIN_SCRIPT_HANDLE,
			sprintf( "localStorage.removeItem( '%s' );", esc_js( self::REFERRAL_CODE_KEY ) ),
			'before'
		);
	}

	/**
	 * Set the referral code cookie.
	 *
	 * Uses override=true so a new referral link always updates the stored code.
	 *
	 * @since 1.4.1
	 *
	 * @param string $code The referral code.
	 *
	 * @return void
	 */
	private function set_cookie( string $code ): void {
		$this->cookie_helper->set_cookie(
			self::REFERRAL_CODE_KEY,
			sanitize_text_field( $code ),
			self::REFERRAL_CODE_DAYS_TO_EXPIRE,
			true
		);
	}

	/**
	 * Save the referral code to localStorage via inline script.
	 *
	 * @since 1.4.1
	 *
	 * @param string $code The referral code.
	 *
	 * @return void
	 */
	private function save_to_local_storage( string $code ): void {
		wp_add_inline_script(
			AssetsService::MAIN_SCRIPT_HANDLE,
			sprintf(
				"localStorage.setItem( '%s', '%s' );",
				esc_js( self::REFERRAL_CODE_KEY ),
				esc_js( $code )
			),
			'before'
		);
	}
}
