<?php
/**
 * Device targeting and conditional logic — packed only in the Pro overlay.
 *
 * Secure design (rafter-secure-design):
 * - Identity: site visitors (frontend) and admins (admin-only snippets).
 * - AuthZ: This file is physically absent from the wordpress.org Lite zip.
 *   Lite always treats stored device/conditional meta as unrestricted.
 *   Presence of the overlay + a valid license applies the stored rules.
 * - Untrusted input: rule values are sanitized on save in Module.
 *
 * @package CodeSnippet
 */

namespace CodeSnippet;

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

/**
 * Evaluates licensed device and conditional snippet rules. Not loaded in Lite.
 */
final class PremiumTargeting {

	/**
	 * @param \WP_Post $post Snippet post.
	 */
	public static function passesDeviceCheck( \WP_Post $post ): bool {
		$device = get_post_meta( $post->ID, '_wpps_device_type', true ) ?: 'all';
		if ( $device === 'all' ) {
			return true;
		}
		$ua = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
		if ( $ua === '' ) {
			return true;
		}
		$is_mobile = (bool) preg_match( '/Mobile|Android|iPhone|iPad|iPod|webOS|IEMobile/i', $ua );
		$is_tablet = (bool) preg_match( '/iPad|Android(?!.*Mobile)|Tablet|Silk/i', $ua );
		switch ( $device ) {
			case 'mobile':
				return $is_mobile && ! $is_tablet;
			case 'tablet':
				return $is_tablet;
			case 'desktop':
				return ! $is_mobile && ! $is_tablet;
			default:
				return true;
		}
	}

	/**
	 * @param \WP_Post $post Snippet post.
	 */
	public static function passesConditionalLogic( \WP_Post $post ): bool {
		$enabled = get_post_meta( $post->ID, '_wpps_conditional_enabled', true ) === '1';
		if ( ! $enabled ) {
			return true;
		}
		$rules = get_post_meta( $post->ID, '_wpps_conditional_rules', true );
		if ( ! is_array( $rules ) || empty( $rules ) ) {
			return true;
		}
		$show = ( $rules['show'] ?? get_post_meta( $post->ID, '_wpps_conditional_show', true ) ) !== '0';
		$pass = self::evaluateConditionalRules( $rules );
		return $show ? $pass : ! $pass;
	}

	/**
	 * Whether any enabled rule needs the resolved main query (Type of Page / Post Type).
	 *
	 * @param \WP_Post $post Snippet post.
	 */
	public static function conditionalRulesNeedQuery( \WP_Post $post ): bool {
		if ( get_post_meta( $post->ID, '_wpps_conditional_enabled', true ) !== '1' ) {
			return false;
		}
		$rules = get_post_meta( $post->ID, '_wpps_conditional_rules', true );
		if ( ! is_array( $rules ) || empty( $rules ) ) {
			return false;
		}
		$groups = $rules['groups'] ?? [ self::normalizeRulesArray( $rules ) ];
		if ( ! is_array( $groups ) ) {
			return false;
		}
		foreach ( $groups as $group ) {
			foreach ( self::normalizeRulesArray( is_array( $group ) ? $group : [] ) as $rule ) {
				if ( in_array( $rule['type'] ?? '', [ 'type_of_page', 'post_type' ], true ) ) {
					return true;
				}
			}
		}
		return false;
	}

	/**
	 * @param array<string, mixed> $rules
	 */
	private static function evaluateConditionalRules( array $rules ): bool {
		$groups = $rules['groups'] ?? null;
		if ( $groups === null ) {
			$groups = [ self::normalizeRulesArray( $rules ) ];
		}
		if ( empty( $groups ) ) {
			return true;
		}
		foreach ( $groups as $group ) {
			if ( self::evaluateRuleGroup( is_array( $group ) ? $group : [] ) ) {
				return true;
			}
		}
		return false;
	}

	/**
	 * @param array<mixed> $group
	 */
	private static function evaluateRuleGroup( array $group ): bool {
		$group = self::normalizeRulesArray( $group );
		foreach ( $group as $rule ) {
			$type     = $rule['type'] ?? '';
			$operator = $rule['operator'] ?? 'contains';
			$value    = $rule['value'] ?? '';
			if ( ! self::evaluateRule( (string) $type, (string) $operator, (string) $value ) ) {
				return false;
			}
		}
		return true;
	}

	/**
	 * @param array<mixed> $rules
	 * @return list<array<string, mixed>>
	 */
	private static function normalizeRulesArray( array $rules ): array {
		$out = [];
		foreach ( $rules as $k => $v ) {
			if ( $k === 'groups' || $k === 'show' ) {
				continue;
			}
			if ( is_array( $v ) && isset( $v['type'] ) ) {
				$out[] = $v;
			}
		}
		return $out;
	}

	private static function evaluateRule( string $type, string $operator, string $value ): bool {
		switch ( $type ) {
			case 'url':
				$current = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
				$match   = in_array( $operator, [ 'equals', 'not_equals' ], true )
					? ( strcasecmp( $current, $value ) === 0 )
					: ( stripos( $current, $value ) !== false );
				return in_array( $operator, [ 'contains', 'equals' ], true ) ? $match : ! $match;
			case 'user_role':
				if ( ! function_exists( 'wp_get_current_user' ) || ! function_exists( 'is_user_logged_in' ) ) {
					return false;
				}
				if ( ! is_user_logged_in() ) {
					return in_array( $operator, [ 'not_equals', 'not_contains' ], true );
				}
				$user = wp_get_current_user();
				$has  = in_array( $value, $user->roles, true );
				return in_array( $operator, [ 'equals', 'contains' ], true ) ? $has : ! $has;
			case 'logged_in':
				if ( ! function_exists( 'is_user_logged_in' ) ) {
					return false;
				}
				$logged_in = is_user_logged_in();
				$wanted    = $value === '1' || $value === 'yes';
				return $logged_in === $wanted;
			case 'type_of_page':
				if ( ! did_action( 'wp' ) ) {
					return false;
				}
				$current = self::getTypeOfPage();
				$match   = $current === $value;
				return in_array( $operator, [ 'equals', 'contains' ], true ) ? $match : ! $match;
			case 'post_type':
				if ( ! did_action( 'wp' ) ) {
					return false;
				}
				$current = self::getCurrentPostType();
				$match   = $current === $value;
				return in_array( $operator, [ 'equals', 'contains' ], true ) ? $match : ! $match;
			default:
				return true;
		}
	}

	private static function getTypeOfPage(): string {
		if ( is_front_page() ) {
			return 'is_front_page';
		}
		if ( is_home() ) {
			return 'is_home';
		}
		if ( is_singular( 'page' ) ) {
			return 'is_page';
		}
		if ( is_singular() ) {
			return 'is_single';
		}
		if ( is_author() ) {
			return 'is_author';
		}
		if ( is_search() ) {
			return 'is_search';
		}
		if ( is_404() ) {
			return 'is_404';
		}
		if ( is_archive() ) {
			return 'is_archive';
		}
		return '';
	}

	private static function getCurrentPostType(): string {
		if ( is_singular() ) {
			$post = get_queried_object();
			return $post instanceof \WP_Post ? $post->post_type : '';
		}
		if ( is_post_type_archive() ) {
			return get_query_var( 'post_type' ) ?: '';
		}
		return '';
	}
}
