<?php

namespace Prodigy\Includes\Helpers;

use DateInterval;
use DateTime;
use DateTimeZone;
use Prodigy\Includes\Prodigy_Cart;

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

/**
 * Prodigy Helper Hosted System class
 *
 * @version    2.8.3
 * @package    Prodigy
 * @subpackage Prodigy/includes
 */
class Prodigy_Cookies {

	/**
	 * Get cookie hook
	 */
	public function __construct() {
		add_action( 'wp_head', array( $this, 'get_cookie' ) );
	}

	/**
	 * @return string|null
	 */
	public static function get_user_cart_cookie(): ?string {
		return isset( $_COOKIE[ Prodigy_Cart::CART_COOKIE_NAME ] ) ? sanitize_text_field( wp_unslash( $_COOKIE[ Prodigy_Cart::CART_COOKIE_NAME ] ) ) : '';
	}

	/**
	 * @param   string $cookie_name
	 *
	 * @return bool
	 */
	public static function has_cookie( string $cookie_name ): bool {
		return isset( $_COOKIE[ $cookie_name ] );
	}

	/**
	 * @param   string $cookie_name
	 *
	 * @return string
	 */
	public static function get_cookie( string $cookie_name ): string {
		return filter_var( $_COOKIE[ $cookie_name ] ?? '', FILTER_SANITIZE_SPECIAL_CHARS ); //phpcs:ignore
	}

	/**
	 * @param   string|null $timeString
	 *
	 * @return string
	 *
	 * @throws \Exception
	 */
	public static function calculate_expiration_time( ?string $timeString ): string {
		if ( $timeString === null ) {
			// Return a default expiration time (e.g., 1 hour from now)
			return time() + 3600;
		}

		$dateTime      = \DateTime::createFromFormat( 'Y-m-d\TH:i:s.uP', $timeString );
		$formattedTime = $dateTime->format( 'Y-m-d H:i:s' );

		$specificDate = new \DateTime( $formattedTime );
		$currentTime  = new \DateTime( 'now' );

		$diff          = $specificDate->getTimestamp() - $currentTime->getTimestamp();
		$diffInSeconds = abs( $diff );

		return time() + $diffInSeconds;
	}

	/**
	 * Whether the request is served over HTTPS. Prefers `wp_is_https()` so reverse proxies
	 * (ngrok, load balancers) that set `X-Forwarded-Proto` are detected; `is_ssl()` alone does not.
	 *
	 * @return bool
	 */
	public static function is_https_request(): bool {
		if ( function_exists( 'wp_is_https' ) ) {
			return wp_is_https();
		}

		return is_ssl();
	}

	/**
	 * Backward-compatible alias for HTTPS detection.
	 *
	 * @return bool
	 */
	public static function request_uses_https(): bool {
		return self::is_https_request();
	}

	/**
	 * SameSite=None with Secure is required for cookies to be available in cross-site iframes (e.g. SAP Ariba PunchOut).
	 * SameSite=None is only valid together with Secure; on HTTP we fall back to Lax.
	 *
	 * @return string
	 */
	public static function get_same_site_attribute(): string {
		return self::is_https_request() ? 'None' : 'Lax';
	}

	/**
	 * @param mixed $expiration Timestamp, numeric string, ISO date string, or null.
	 *
	 * @return int Unix timestamp for cookie expiry.
	 */
	private static function normalize_cookie_expires( $expiration ): int {
		if ( $expiration === null ) {
			return time() + 300;
		}
		if ( is_numeric( $expiration ) ) {
			return (int) $expiration;
		}
		if ( is_string( $expiration ) ) {
			$parsed = strtotime( $expiration );
			if ( $parsed !== false ) {
				return $parsed;
			}
		}

		return time() + 300;
	}

	/**
	 * @param   string      $cookie_name
	 * @param   string|null $cookiepath
	 * @param   string|null $cookiedomain
	 * @param   bool        $httponly
	 *
	 * @return void
	 */
	public static function remove_cookie( string $cookie_name, ?string $cookiepath = null, ?string $cookiedomain = null, bool $httponly = false ): void {
		unset( $_COOKIE[ $cookie_name ] );

		$expiration_time = time() - 3600;
		$path            = $cookiepath ?? COOKIEPATH;
		$domain          = $cookiedomain ?? COOKIE_DOMAIN;
		$secure          = self::is_https_request();
		$samesite        = self::get_same_site_attribute();

		if ( PHP_VERSION_ID >= 70300 ) {
			@setcookie(
				$cookie_name,
				'',
				array(
					'expires'  => $expiration_time,
					'path'     => $path,
					'domain'   => $domain,
					'secure'   => $secure,
					'httponly' => $httponly,
					'samesite' => $samesite,
				)
			);
		} else {
			@setcookie( $cookie_name, '', $expiration_time, $path, $domain, $secure, $httponly );
		}
	}

	/**
	 * @param   string      $name
	 * @param   string      $value
	 * @param   string|null $expiration
	 * @param   string|null $cookiepath
	 * @param   string|null $cookiedomain
	 * @param   bool        $httponly
	 *
	 * @return bool
	 * @throws \Exception
	 */
	public static function set_cookie( string $name, string $value, ?string $expiration = null, ?string $cookiepath = null, ?string $cookiedomain = null, bool $httponly = false ): bool {
		$_COOKIE[ $name ] = $value;

		if ( PHP_SAPI === 'cli' && headers_sent() ) {
			return true;
		}

		$expires_int = self::normalize_cookie_expires( $expiration ?? self::get_default_expiration_time() );
		$path        = $cookiepath ?? COOKIEPATH;
		$domain      = $cookiedomain ?? COOKIE_DOMAIN;
		$secure_flag = self::is_https_request();
		$samesite    = self::get_same_site_attribute();

		if ( PHP_VERSION_ID >= 70300 ) {
			return @setcookie(
				$name,
				$value,
				array(
					'expires'  => $expires_int,
					'path'     => $path,
					'domain'   => $domain,
					'secure'   => $secure_flag,
					'httponly' => $httponly,
					'samesite' => $samesite,
				)
			);
		}

		return @setcookie( $name, $value, $expires_int, $path, $domain, $secure_flag, $httponly );
	}

	/**
	 * @return string
	 * @throws \Exception
	 */
	public static function get_default_expiration_time(): string {
		$currentTime = new DateTime( 'now', new DateTimeZone( 'UTC' ) );
		$currentTime->add( new DateInterval( 'PT5M' ) );

		return $currentTime->format( 'Y-m-d\TH:i:s.uP' );
	}
}
