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

defined('ABSPATH') || exit;

class RuntimePricingMapper
{
    public function mergePricingConfiguration(mixed $pricing, array $globalRules) : array
    {
        $pricing = is_array($pricing) ? $pricing : [];
        $localRules = is_array($pricing['pricingRules'] ?? null) ? (array) $pricing['pricingRules'] : [];
        $globalRules = $this->normalizePricingRuleRuntimeItems($globalRules);
        $localRules = $this->normalizePricingRuleRuntimeItems($localRules);
        $rules = $this->mergeById($localRules, $globalRules);

        $pricing['enabled'] = (bool) ($pricing['enabled'] ?? ($rules !== []));
        $pricing['rules'] = $rules;
        $pricing['pricingRules'] = $rules;

        return $pricing;
    }

    public function extractBasePrice(array $pricing) : float
    {
        return $this->toFloat($pricing['price'] ?? ($pricing['basePrice'] ?? 0));
    }

    public function normalizePriceFormatConfig(mixed $config) : array
    {
        if (! is_array($config)) {
            return [];
        }

        return array_filter([
            'code' => isset($config['code']) ? sanitize_text_field((string) $config['code']) : null,
            'symbol' => isset($config['symbol']) ? sanitize_text_field((string) $config['symbol']) : null,
            'priceFormat' => isset($config['priceFormat']) ? sanitize_text_field((string) $config['priceFormat']) : null,
            'decimalSeparator' => isset($config['decimalSeparator']) ? sanitize_text_field((string) $config['decimalSeparator']) : null,
            'thousandSeparator' => isset($config['thousandSeparator']) ? sanitize_text_field((string) $config['thousandSeparator']) : null,
            'precision' => isset($config['precision']) ? max(0, (int) $config['precision']) : null,
            'trimZeros' => array_key_exists('trimZeros', $config) ? (bool) $config['trimZeros'] : null,
        ], static fn($value) => $value !== null && $value !== '');
    }

    private function normalizePricingRuleRuntimeItems(array $rules) : array
    {
        $items = [];
        foreach ($rules as $rule) {
            if (! is_array($rule) || (isset($rule['enabled']) && ! $rule['enabled'])) {
                continue;
            }
            $id = sanitize_key((string) ($rule['id'] ?? ''));
            $label = sanitize_text_field((string) ($rule['label'] ?? ''));
            $conditions = is_array($rule['conditions'] ?? null) ? array_values(array_filter($rule['conditions'], 'is_array')) : [];
            if ($id === '' || $label === '') {
                continue;
            }
            $target = is_array($rule['target'] ?? null) ? (array) $rule['target'] : [];
            $rule['id'] = $id;
            $rule['label'] = $label;
            $rule['handler'] = $this->normalizePricingHandler((string) ($rule['handler'] ?? 'layersAmount'));
            $rule['scope'] = $this->normalizePricingScope((string) ($rule['scope'] ?? 'all'));
            $rule['match'] = sanitize_key((string) ($rule['match'] ?? 'all')) === 'any' ? 'any' : 'all';
            $rule['target'] = $target;
            $rule['conditions'] = $conditions;
            $rule['enabled'] = true;
            $items[] = $rule;
        }

        return $items;
    }

    private function normalizePricingHandler(string $handler) : string
    {
        $normalized = strtolower(preg_replace('/[^a-z0-9]+/i', '', $handler) ?: '');
        return match ($normalized) {
            'layersamount' => 'layersAmount',
            'textlength' => 'textLength',
            'textlines' => 'textLines',
            'usedcolorsamount', 'colorslength' => 'usedColorsAmount',
            'scale' => 'scale',
            'layersize' => 'layerSize',
            'canvassize' => 'canvasSize',
            default => 'layersAmount',
        };
    }

    private function normalizePricingScope(string $scope) : string
    {
        $scope = sanitize_key($scope);
        return in_array($scope, ['first', 'current'], true) ? $scope : 'all';
    }

    private function mergeById(array $first, array $second) : array
    {
        $merged = [];
        foreach ([$first, $second] as $group) {
            foreach ($group as $item) {
                if (! is_array($item)) {
                    continue;
                }
                $id = sanitize_key((string) ($item['id'] ?? ''));
                if ($id === '') {
                    continue;
                }
                $merged[$id] = isset($merged[$id]) && is_array($merged[$id]) ? array_replace($merged[$id], $item) : $item;
            }
        }
        return array_values($merged);
    }

    private function toFloat(mixed $value, float $fallback = 0.0) : float
    {
        if (is_numeric($value)) {
            return (float) $value;
        }
        $value = str_replace(',', '.', trim((string) $value));
        return is_numeric($value) ? (float) $value : $fallback;
    }
}
