<?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\Repositories;

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

defined('ABSPATH') || exit;

class UserDesignRepository
{
    public function create(array $payload) : int
    {
        $postId = wp_insert_post([
            'post_type' => UserDesignPostType::TYPE,
            'post_status' => 'private',
            'post_title' => sanitize_text_field((string) ($payload['title'] ?? __('User design', 'asuka-product-designer'))),
            'post_author' => (int) ($payload['userId'] ?? get_current_user_id()),
        ], true);

        if (is_wp_error($postId) || ! $postId) {
            return 0;
        }

        $this->persistMeta((int) $postId, $payload);

        return (int) $postId;
    }

    public function update(int $postId, array $payload) : bool
    {
        if ($postId <= 0 || get_post_type($postId) !== UserDesignPostType::TYPE) {
            return false;
        }

        if (! empty($payload['title'])) {
            wp_update_post([
                'ID' => $postId,
                'post_title' => sanitize_text_field((string) $payload['title']),
            ]);
        }

        $this->persistMeta($postId, $payload);

        return true;
    }

    public function find(int $postId) : array
    {
        if ($postId <= 0) {
            return [];
        }

        $post = get_post($postId);
        if (! $post || $post->post_type !== UserDesignPostType::TYPE) {
            return [];
        }

        return [
            'id' => (int) $post->ID,
            'title' => $post->post_title,
            'status' => $post->post_status,
            'authorId' => (int) $post->post_author,
            'configId' => (int) get_post_meta($post->ID, '_apd_config_id', true),
            'productId' => (int) get_post_meta($post->ID, '_apd_product_id', true),
            'userId' => (int) get_post_meta($post->ID, '_apd_user_id', true),
            'orderId' => (int) get_post_meta($post->ID, '_apd_order_id', true),
            'orderItemId' => (int) get_post_meta($post->ID, '_apd_order_item_id', true),
            'previewUrls' => $this->decode(get_post_meta($post->ID, '_apd_preview_urls', true)),
            'priceSnapshot' => $this->decode(get_post_meta($post->ID, '_apd_price_snapshot', true)),
            'productionData' => $this->decode(get_post_meta($post->ID, '_apd_production_data', true)),
            'designJson' => $this->decode(get_post_meta($post->ID, '_apd_design_json', true)),
            'stateJson' => $this->decode(get_post_meta($post->ID, '_apd_state_json', true)),
            'accessToken' => (string) get_post_meta($post->ID, '_apd_access_token', true),
        ];
    }

    protected function persistMeta(int $postId, array $payload) : void
    {
        $map = [
            '_apd_design_json' => $payload['designJson'] ?? null,
            '_apd_state_json' => $payload['stateJson'] ?? null,
            '_apd_preview_urls' => $payload['previewUrls'] ?? null,
            '_apd_config_id' => $payload['configId'] ?? null,
            '_apd_product_id' => $payload['productId'] ?? null,
            '_apd_user_id' => $payload['userId'] ?? null,
            '_apd_price_snapshot' => $payload['priceSnapshot'] ?? null,
            '_apd_production_data' => $payload['productionData'] ?? null,
            '_apd_order_id' => $payload['orderId'] ?? null,
            '_apd_order_item_id' => $payload['orderItemId'] ?? null,
            '_apd_access_token' => $payload['accessToken'] ?? null,
        ];

        foreach ($map as $key => $value) {
            if ($value === null) {
                continue;
            }

            $sanitized = $this->sanitizeMetaValue($key, $value);
            update_post_meta($postId, $key, $this->isJsonMetaKey($key) ? wp_slash($sanitized) : $sanitized);
        }
    }

    protected function decode($raw)
    {
        if (! is_string($raw) || $raw === '') {
            return $raw;
        }

        $decoded = json_decode($raw, true);
        return json_last_error() === JSON_ERROR_NONE ? $decoded : $raw;
    }

    private function isJsonMetaKey(string $key) : bool
    {
        return in_array($key, ['_apd_design_json', '_apd_state_json', '_apd_preview_urls', '_apd_price_snapshot', '_apd_production_data'], true);
    }

    private function sanitizeMetaValue(string $key, mixed $value) : string
    {
        if (in_array($key, ['_apd_config_id', '_apd_product_id', '_apd_user_id', '_apd_order_id', '_apd_order_item_id'], true)) {
            return (string) absint($value);
        }

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

        if ($this->isJsonMetaKey($key)) {
            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 : '';
        }

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

}
