<?php

// phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedNamespaceFound -- APD is the established namespace shared with the Pro add-on and retained for backward compatibility.
namespace APD\Meta;

use APD\PostTypes\UserDesignPostType;
use APD\Support\Json;
use APD\Support\UserDesignAccess;

defined('ABSPATH') || exit;

class UserDesignMeta
{
    private const JSON_KEYS = [
        '_apd_design_json',
        '_apd_preview_urls',
        '_apd_state_json',
        '_apd_price_snapshot',
        '_apd_production_data',
    ];

    private const INT_KEYS = [
        '_apd_config_id',
        '_apd_product_id',
        '_apd_user_id',
        '_apd_order_id',
        '_apd_order_item_id',
    ];

    public function register() : void
    {
        $keys = [
            '_apd_design_json',
            '_apd_preview_urls',
            '_apd_state_json',
            '_apd_config_id',
            '_apd_product_id',
            '_apd_user_id',
            '_apd_price_snapshot',
            '_apd_production_data',
            '_apd_order_id',
            '_apd_order_item_id',
            '_apd_access_token',
        ];

        foreach ($keys as $key) {
            register_post_meta(UserDesignPostType::TYPE, $key, [
                'show_in_rest' => false,
                'single' => true,
                'type' => 'string',
                'auth_callback' => [$this, 'canAccessMeta'],
                'sanitize_callback' => fn($value) => $this->sanitizeValue($key, $value),
                'default' => '',
            ]);
        }
    }

    public function canAccessMeta(bool $allowed, string $metaKey, int $postId, int $userId) : bool
    {
        if ($allowed) {
            return true;
        }

        return UserDesignAccess::canAccessPostForUser($postId, $userId > 0 ? $userId : get_current_user_id());
    }

    private function sanitizeValue(string $key, mixed $value) : string
    {
        if (in_array($key, self::INT_KEYS, true)) {
            return (string) absint($value);
        }

        if (in_array($key, self::JSON_KEYS, true)) {
            return $this->sanitizeJsonLike($value);
        }

        if ($key === '_apd_access_token') {
            return UserDesignAccess::sanitizeToken((string) $value);
        }

        return sanitize_text_field(is_scalar($value) ? wp_unslash((string) $value) : wp_json_encode($value));
    }

    private function sanitizeJsonLike(mixed $value) : string
    {
        if (is_array($value) || is_object($value)) {
            return (string) wp_json_encode($value, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        }

        if (! is_string($value)) {
            return '';
        }

        $normalized = Json::normalize($value, flags: JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        return $normalized !== null ? $normalized : '';
    }
}
