<?php
/**
 * BookiFlex Core
 *
 * @package    BookiFlex
 * @subpackage Core
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */

declare(strict_types=1);

namespace BookiFlex\Core\ORM\DataProvider;

use Carbon_Fields\Datastore\Post_Meta_Datastore;

defined( 'ABSPATH' ) || exit;

/**
 * Parsed Carbon meta fields data and base meta fields of post from the database to a normalized array.
 */
class CarbonFieldsParser extends Post_Meta_Datastore
{
    /** @var array<string, callable[]> */
    private static array $normalizers = [];

    /**
     * Push a normalizer onto the stack for a post type.
     * Each normalizer receives the raw CF value tree and returns only the keys it handles.
     * Results are merged in registration order — later entries win on key conflicts.
     */
    public static function registerNormalizer(string $postType, callable $normalizer): void
    {
        self::$normalizers[$postType][] = $normalizer;
    }

    /**
     * @param string $postType type of post
     * @param mixed $data raw meta fields data like from the database
     * @param bool $normalize normalize data
     * @return array|null
     */
    public function parse(string $postType, mixed $data, bool $normalize = true): ?array
    {
        if (!is_array($data)) {
            return null;
        }

        $results = [];
        foreach ($data as $item) {
            if (!isset($item['post_id'], $item['meta_key'], $item['meta_value'])) {
                continue;
            }
            $class                       = new \stdClass();
            $class->key                  = $item['meta_key'];
            $class->value                = $item['meta_value'];
            $results[$item['post_id']][] = $class;
        }

        return array_map(function ($metaField) use ($postType, $normalize) {
            $tree = $this->cascading_storage_array_to_value_tree_array($metaField);
            if ($normalize) {
                return $this->normalize($postType, $tree);
            }

            return $this->cascading_storage_array_to_value_tree_array($metaField);
        }, $results);
    }

    public static function defaultNormalize(array $data): array
    {
        $result = [];
        foreach ($data as $key => $value) {
            $result[$key] = count($value) > 1
                ? array_map(fn($item) => $item['value'], $value)
                : $value[0]['value'];
        }

        return $result;
    }

    private function normalize(string $customPostType, array $data): array
    {
        $stack = self::$normalizers[$customPostType] ?? [];

        if (empty($stack)) {
            return self::defaultNormalize($data);
        }

        $result = [];
        foreach ($stack as $normalizer) {
            $result = array_merge($result, $normalizer($data));
        }

        return $result;
    }
}
