<?php
namespace Tiamr;

use Tiamr\Utils\Sanitizer;

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

final class Meta {
    /**
     * Legacy key kept for backwards-compatible rule mapping.
     */
    public const CONDITION = '_tiamr_condition';

    public const ACTION    = '_tiamr_action';
    public const AUDIENCE  = '_tiamr_audience';
    public const LOCATION  = '_tiamr_location';
    public const ROLES     = '_tiamr_roles';
    public const PAGES     = '_tiamr_pages';
    public const POSTS     = '_tiamr_posts';

    /** Internal value used when no Free rule meta exists. */
    public const CONDITION_NO_RULE = 'no_rule';

    public const AUDIENCE_EVERYONE    = 'everyone';
    public const AUDIENCE_LOGGED_IN   = 'logged_in';
    public const AUDIENCE_LOGGED_OUT  = 'logged_out';
    public const AUDIENCE_ROLE_IS     = 'role_is';
    public const AUDIENCE_ROLE_IS_NOT = 'role_is_not';

    public const LOCATION_EVERYWHERE  = 'everywhere';
    public const LOCATION_PAGE_IS     = 'page_is';
    public const LOCATION_PAGE_IS_NOT = 'page_is_not';
    public const LOCATION_POST_IS     = 'post_is';
    public const LOCATION_POST_IS_NOT = 'post_is_not';

    /**
     * Backwards-compatible aliases for older code/hooks that may still refer
     * to condition constants.
     */
    public const CONDITION_EVERYONE    = self::AUDIENCE_EVERYONE;
    public const CONDITION_LOGGED_IN   = self::AUDIENCE_LOGGED_IN;
    public const CONDITION_LOGGED_OUT  = self::AUDIENCE_LOGGED_OUT;
    public const CONDITION_ROLE_IS     = self::AUDIENCE_ROLE_IS;
    public const CONDITION_ROLE_IS_NOT = self::AUDIENCE_ROLE_IS_NOT;
    public const CONDITION_PAGE_IS     = self::LOCATION_PAGE_IS;
    public const CONDITION_PAGE_IS_NOT = self::LOCATION_PAGE_IS_NOT;
    public const CONDITION_POST_IS     = self::LOCATION_POST_IS;
    public const CONDITION_POST_IS_NOT = self::LOCATION_POST_IS_NOT;

    public const ACTION_SHOW = 'show';
    public const ACTION_HIDE = 'hide';

    public static function get_audience_conditions(): array {
        return [
            self::AUDIENCE_EVERYONE    => __('Everyone', 'titanium-advanced-menu-rules'),
            self::AUDIENCE_LOGGED_IN   => __('Logged in', 'titanium-advanced-menu-rules'),
            self::AUDIENCE_LOGGED_OUT  => __('Logged out', 'titanium-advanced-menu-rules'),
            self::AUDIENCE_ROLE_IS     => __('Role is', 'titanium-advanced-menu-rules'),
            self::AUDIENCE_ROLE_IS_NOT => __('Role is not', 'titanium-advanced-menu-rules'),
        ];
    }

    public static function get_location_conditions(): array {
        return [
            self::LOCATION_EVERYWHERE  => __('Everywhere', 'titanium-advanced-menu-rules'),
            self::LOCATION_PAGE_IS     => __('Page is', 'titanium-advanced-menu-rules'),
            self::LOCATION_PAGE_IS_NOT => __('Page is not', 'titanium-advanced-menu-rules'),
            self::LOCATION_POST_IS     => __('Post is', 'titanium-advanced-menu-rules'),
            self::LOCATION_POST_IS_NOT => __('Post is not', 'titanium-advanced-menu-rules'),
        ];
    }

    /**
     * Backwards-compatible helper for condition options.
     */
    public static function get_conditions(): array {
        return self::get_audience_conditions() + [
            self::LOCATION_PAGE_IS     => __('Page is', 'titanium-advanced-menu-rules'),
            self::LOCATION_PAGE_IS_NOT => __('Page is not', 'titanium-advanced-menu-rules'),
            self::LOCATION_POST_IS     => __('Post is', 'titanium-advanced-menu-rules'),
            self::LOCATION_POST_IS_NOT => __('Post is not', 'titanium-advanced-menu-rules'),
        ];
    }

    public static function get_allowed_conditions(): array {
        return array_merge([self::CONDITION_NO_RULE], array_keys(self::get_conditions()));
    }

    public static function get_allowed_audience_conditions(): array {
        return array_keys(self::get_audience_conditions());
    }

    public static function get_allowed_location_conditions(): array {
        return array_keys(self::get_location_conditions());
    }

    public static function get_actions(): array {
        return [
            self::ACTION_SHOW => __('Show', 'titanium-advanced-menu-rules'),
            self::ACTION_HIDE => __('Hide', 'titanium-advanced-menu-rules'),
        ];
    }

    public static function get_rule(int $menu_item_id): array {
        $action        = (string) get_post_meta($menu_item_id, self::ACTION, true);
        $audience      = (string) get_post_meta($menu_item_id, self::AUDIENCE, true);
        $location      = (string) get_post_meta($menu_item_id, self::LOCATION, true);
        $legacy_rule   = (string) get_post_meta($menu_item_id, self::CONDITION, true);
        $roles         = get_post_meta($menu_item_id, self::ROLES, true);
        $pages         = get_post_meta($menu_item_id, self::PAGES, true);
        $posts         = get_post_meta($menu_item_id, self::POSTS, true);

        $action = Sanitizer::sanitize_action($action);

        if ('' === $audience && '' === $location && '' !== $legacy_rule) {
            [$audience, $location] = self::map_legacy_condition($legacy_rule);
        } else {
            $audience = Sanitizer::sanitize_audience_condition($audience);
            $location = Sanitizer::sanitize_location_condition($location);
        }

        $roles = Sanitizer::sanitize_roles(is_array($roles) ? $roles : []);
        $pages = Sanitizer::sanitize_post_ids(is_array($pages) ? $pages : [], 'page');
        $posts = Sanitizer::sanitize_post_ids(is_array($posts) ? $posts : [], 'post');

        return [
            'action'   => $action,
            'audience' => $audience,
            'location' => $location,
            'roles'    => $roles,
            'pages'    => $pages,
            'posts'    => $posts,

            // Legacy keys kept for filters/third-party compatibility.
            'condition' => self::legacy_condition_from_blocks($audience, $location),
        ];
    }

    public static function update_rule(int $menu_item_id, array $rule): void {
        $action   = Sanitizer::sanitize_action($rule['action'] ?? self::ACTION_SHOW);
        $audience = Sanitizer::sanitize_audience_condition($rule['audience'] ?? self::AUDIENCE_EVERYONE);
        $location = Sanitizer::sanitize_location_condition($rule['location'] ?? self::LOCATION_EVERYWHERE);
        $roles    = Sanitizer::sanitize_roles($rule['roles'] ?? []);
        $pages    = Sanitizer::sanitize_post_ids($rule['pages'] ?? [], 'page');
        $posts    = Sanitizer::sanitize_post_ids($rule['posts'] ?? [], 'post');

        // Show + Everyone + Everywhere is the default WordPress behaviour, so store nothing.
        if (
            self::ACTION_SHOW === $action &&
            self::AUDIENCE_EVERYONE === $audience &&
            self::LOCATION_EVERYWHERE === $location
        ) {
            self::delete_rule_meta($menu_item_id);
            return;
        }

        delete_post_meta($menu_item_id, self::CONDITION);

        update_post_meta($menu_item_id, self::ACTION, $action);
        update_post_meta($menu_item_id, self::AUDIENCE, $audience);
        update_post_meta($menu_item_id, self::LOCATION, $location);
        update_post_meta($menu_item_id, self::ROLES, $roles);
        update_post_meta($menu_item_id, self::PAGES, $pages);
        update_post_meta($menu_item_id, self::POSTS, $posts);
    }

    private static function delete_rule_meta(int $menu_item_id): void {
        delete_post_meta($menu_item_id, self::CONDITION);
        delete_post_meta($menu_item_id, self::ACTION);
        delete_post_meta($menu_item_id, self::AUDIENCE);
        delete_post_meta($menu_item_id, self::LOCATION);
        delete_post_meta($menu_item_id, self::ROLES);
        delete_post_meta($menu_item_id, self::PAGES);
        delete_post_meta($menu_item_id, self::POSTS);
    }

    /**
     * @return array{0:string,1:string}
     */
    private static function map_legacy_condition(string $condition): array {
        $condition = Sanitizer::sanitize_condition($condition);

        if (in_array($condition, [self::LOCATION_PAGE_IS, self::LOCATION_PAGE_IS_NOT, self::LOCATION_POST_IS, self::LOCATION_POST_IS_NOT], true)) {
            return [self::AUDIENCE_EVERYONE, $condition];
        }

        if (in_array($condition, self::get_allowed_audience_conditions(), true)) {
            return [$condition, self::LOCATION_EVERYWHERE];
        }

        return [self::AUDIENCE_EVERYONE, self::LOCATION_EVERYWHERE];
    }

    private static function legacy_condition_from_blocks(string $audience, string $location): string {
        if (self::LOCATION_EVERYWHERE !== $location) {
            return $location;
        }

        return $audience;
    }
}
