<?php

namespace Daylight\Core\Modules\Cart;

use Daylight\Core\Models\Country;
use Daylight\Core\Models\Shipping\ShippingZone;

final class FreeShippingPostalEvaluator
{
    public static function grants(?string $shippingPostalCode, Country $shippingCountry, ?ShippingZone $shippingZone): bool
    {
        if ($shippingPostalCode === null || trim($shippingPostalCode) === '') {
            return false;
        }

        if ($shippingZone === null) {
            return false;
        }

        if (! $shippingZone->countries->contains('id', $shippingCountry->id)) {
            return false;
        }

        $prefixes = self::resolvePrefixes($shippingZone, $shippingCountry);

        if ($prefixes === []) {
            return false;
        }

        $normalized = self::normalizePostalCodeDigits($shippingPostalCode);

        if ($normalized === '') {
            return false;
        }

        foreach ($prefixes as $prefix) {
            if (! is_string($prefix) && ! is_int($prefix)) {
                continue;
            }

            $prefixString = (string) $prefix;

            if ($prefixString === '') {
                continue;
            }

            if (str_starts_with($normalized, $prefixString)) {
                return true;
            }
        }

        return false;
    }

    /**
     * @return list<string>
     */
    public static function resolvePrefixes(ShippingZone $shippingZone, Country $shippingCountry): array
    {
        $raw = $shippingZone->free_shipping_postal_prefixes;

        if (! is_array($raw) || $raw === []) {
            return [];
        }

        if (array_is_list($raw)) {
            return array_values(array_filter(array_map(
                static fn ($p): string => is_string($p) || is_int($p) ? (string) $p : '',
                $raw
            ), static fn (string $s): bool => $s !== ''));
        }

        $wanted = strtoupper($shippingCountry->code);

        foreach ($raw as $key => $value) {
            if (strtoupper((string) $key) !== $wanted) {
                continue;
            }

            if (! is_array($value)) {
                return [];
            }

            return array_values(array_filter(array_map(
                static fn ($p): string => is_string($p) || is_int($p) ? (string) $p : '',
                $value
            ), static fn (string $s): bool => $s !== ''));
        }

        return [];
    }

    public static function normalizePostalCodeDigits(string $postalCode): string
    {
        return preg_replace('/\D/', '', $postalCode) ?? '';
    }
}
