<?php
namespace Tiamr\Rules;

use Tiamr\Meta;

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

final class Free_Rule_Evaluator {
    /** @var User_Context */
    private $user_context;

    public function __construct(User_Context $user_context) {
        $this->user_context = $user_context;
    }

    public function is_item_visible(\WP_Post $item): bool {
        $rule = Meta::get_rule((int) $item->ID);

        if ($this->is_default_rule($rule)) {
            return true;
        }

        $matches = $this->rule_matches($rule);

        if (Meta::ACTION_HIDE === $rule['action']) {
            return !$matches;
        }

        return $matches;
    }

    public function rule_matches(array $rule): bool {
        return $this->audience_matches($rule) && $this->location_matches($rule);
    }

    private function is_default_rule(array $rule): bool {
        return
            Meta::ACTION_SHOW === ($rule['action'] ?? Meta::ACTION_SHOW) &&
            Meta::AUDIENCE_EVERYONE === ($rule['audience'] ?? Meta::AUDIENCE_EVERYONE) &&
            Meta::LOCATION_EVERYWHERE === ($rule['location'] ?? Meta::LOCATION_EVERYWHERE);
    }

    private function audience_matches(array $rule): bool {
        $audience = $rule['audience'] ?? Meta::AUDIENCE_EVERYONE;
        $roles    = is_array($rule['roles'] ?? null) ? $rule['roles'] : [];

        switch ($audience) {
            case Meta::AUDIENCE_EVERYONE:
                return true;

            case Meta::AUDIENCE_LOGGED_IN:
                return $this->user_context->is_logged_in();

            case Meta::AUDIENCE_LOGGED_OUT:
                return !$this->user_context->is_logged_in();

            case Meta::AUDIENCE_ROLE_IS:
                return $this->user_context->has_any_role($roles);

            case Meta::AUDIENCE_ROLE_IS_NOT:
                return !$this->user_context->has_any_role($roles);

            default:
                return true;
        }
    }

    private function location_matches(array $rule): bool {
        $location = $rule['location'] ?? Meta::LOCATION_EVERYWHERE;
        $pages    = is_array($rule['pages'] ?? null) ? $rule['pages'] : [];
        $posts    = is_array($rule['posts'] ?? null) ? $rule['posts'] : [];

        switch ($location) {
            case Meta::LOCATION_EVERYWHERE:
                return true;

            case Meta::LOCATION_PAGE_IS:
                return $this->is_current_singular_in_targets('page', $pages);

            case Meta::LOCATION_PAGE_IS_NOT:
                return !$this->is_current_singular_in_targets('page', $pages);

            case Meta::LOCATION_POST_IS:
                return $this->is_current_singular_in_targets('post', $posts);

            case Meta::LOCATION_POST_IS_NOT:
                return !$this->is_current_singular_in_targets('post', $posts);

            default:
                return true;
        }
    }

    private function is_current_singular_in_targets(string $post_type, array $target_ids): bool {
        $target_ids = array_map('absint', $target_ids);
        $target_ids = array_filter($target_ids);

        if (empty($target_ids)) {
            return false;
        }

        $current_id = absint(get_queried_object_id());

        if (!$current_id) {
            return false;
        }

        $current_post = get_post($current_id);

        if (!$current_post || $post_type !== $current_post->post_type) {
            return false;
        }

        return in_array($current_id, $target_ids, true);
    }
}
