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

defined('ABSPATH') || exit;

class PricingSnapshot
{
    public const VERSION = 1;

    public static function normalize(mixed $pricing, float $fallbackBase = 0.0) : array
    {
        if (is_string($pricing)) {
            $pricing = Json::decode($pricing, []);
        }

        $pricing = is_array($pricing) ? $pricing : [];
        $display = is_array($pricing['display_breakdown'] ?? null)
            ? $pricing['display_breakdown']
            : (is_array($pricing['uiBreakdown'] ?? null) ? $pricing['uiBreakdown'] : []);

        $base = self::readFloat([
            $pricing['base_price'] ?? null,
            $pricing['base'] ?? null,
            $pricing['basePrice'] ?? null,
            $display['base_price'] ?? null,
            $display['base'] ?? null,
        ], $fallbackBase);

        $fixedFee = self::readFloat([
            $pricing['fixed_fee'] ?? null,
            $pricing['fixedFee'] ?? null,
            $display['fixed_fee'] ?? null,
            $display['fixedFee'] ?? null,
        ], 0.0);

        $designerBase = self::readFloat([
            $pricing['designer_base_price'] ?? null,
            $pricing['designerBasePrice'] ?? null,
            $pricing['designerBase'] ?? null,
            $display['designer_base_price'] ?? null,
            $display['designerBasePrice'] ?? null,
            $display['designerBase'] ?? null,
        ], 0.0);

        $standard = self::readFloat([
            $pricing['standard_price'] ?? null,
            $pricing['standard'] ?? null,
            $display['standard_price'] ?? null,
            $display['standard'] ?? null,
        ], 0.0);

        $rulesTotal = self::readFloat([
            $pricing['rules_total'] ?? null,
            $pricing['rules'] ?? null,
            $display['rules_total'] ?? null,
            $display['rules'] ?? null,
        ], 0.0);

        $finalPrice = self::readFloat([
            $pricing['final_price'] ?? null,
            $pricing['total'] ?? null,
            $display['final_price'] ?? null,
            $display['total'] ?? null,
        ], $base);

        $adjustment = self::readFloat([
            $pricing['adjustment_total'] ?? null,
            $pricing['adjustment'] ?? null,
            $display['adjustment_total'] ?? null,
            $display['adjustment'] ?? null,
        ], $finalPrice - $base);

        if (! array_key_exists('adjustment_total', $pricing) && ! array_key_exists('adjustment', $pricing)) {
            $adjustment = $finalPrice - $base;
        }
        if (! array_key_exists('final_price', $pricing) && ! array_key_exists('total', $pricing)) {
            $finalPrice = $base + $adjustment;
        }

        $appliedRules = is_array($pricing['applied_rules'] ?? null)
            ? array_values(array_filter($pricing['applied_rules'], 'is_array'))
            : (is_array($pricing['appliedRules'] ?? null) ? array_values(array_filter($pricing['appliedRules'], 'is_array')) : []);

        $warnings = is_array($pricing['warnings'] ?? null) ? array_values($pricing['warnings']) : [];
        $breakdownRows = is_array($pricing['breakdown'] ?? null) ? array_values(array_filter($pricing['breakdown'], 'is_array')) : [];
        if ($breakdownRows === []) {
            $breakdownRows = self::buildBreakdownRows($base, $fixedFee, $designerBase, $standard, $rulesTotal);
        }

        $displayBreakdown = [
            'base_price' => $base,
            'fixed_fee' => $fixedFee,
            'designer_base_price' => $designerBase,
            'standard_price' => $standard,
            'rules_total' => $rulesTotal,
            'adjustment_total' => $adjustment,
            'final_price' => $finalPrice,
        ];

        return [
            'payload_version' => self::VERSION,
            'success' => array_key_exists('success', $pricing) ? ! empty($pricing['success']) : true,
            'base_price' => $base,
            'adjustment_total' => $adjustment,
            'final_price' => $finalPrice,
            'fixed_fee' => $fixedFee,
            'designer_base_price' => $designerBase,
            'standard_price' => $standard,
            'rules_total' => $rulesTotal,
            'display_breakdown' => $displayBreakdown,
            'breakdown' => $breakdownRows,
            'applied_rules' => $appliedRules,
            'warnings' => $warnings,
            // Transitional aliases kept to avoid breaking existing consumers.
            'base' => $base,
            'basePrice' => $base,
            'adjustment' => $adjustment,
            'total' => $finalPrice,
            'fixedFee' => $fixedFee,
            'designerBase' => $designerBase,
            'designerBasePrice' => $designerBase,
            'standard' => $standard,
            'rules' => $rulesTotal,
            'uiBreakdown' => [
                'base' => $base,
                'designerBase' => $designerBase,
                'standard' => $standard,
                'rules' => $rulesTotal,
                'adjustment' => $adjustment,
                'total' => $finalPrice,
            ],
            'appliedRules' => $appliedRules,
        ];
    }

    public static function encode(mixed $pricing, float $fallbackBase = 0.0) : string
    {
        return Json::encode(self::normalize($pricing, $fallbackBase));
    }

    protected static function readFloat(array $values, float $fallback) : float
    {
        foreach ($values as $value) {
            if ($value === null || $value === '') {
                continue;
            }
            if (is_numeric($value)) {
                return (float) $value;
            }
        }

        return $fallback;
    }

    protected static function buildBreakdownRows(float $base, float $fixedFee, float $designerBase, float $standard, float $rulesTotal) : array
    {
        return [
            ['type' => 'base', 'amount' => $base],
            ['type' => 'fixed_fee', 'amount' => $fixedFee],
            ['type' => 'designer_base', 'amount' => $designerBase],
            ['type' => 'standard', 'amount' => $standard],
            ['type' => 'rules', 'amount' => $rulesTotal],
        ];
    }
}
