<?php

declare(strict_types=1);

namespace App\Services\SupportCenter;

/**
 * 兼容发布清单、Support Center 检查响应及包内 manifest 的更新策略字段。
 */
final class HostSystemUpdatePolicyResolver
{
    /**
     * @param  array<string, mixed>  $payload
     * @return array{force_update: bool, min_version: ?string, min_update_version: ?int}
     */
    public function resolve(array $payload): array
    {
        $package = is_array($payload['package'] ?? null) ? $payload['package'] : [];
        $upgrade = is_array($payload['upgrade'] ?? null) ? $payload['upgrade'] : [];
        $packageRequirements = is_array($package['requirements'] ?? null) ? $package['requirements'] : [];
        $requirements = is_array($payload['requirements'] ?? null) ? $payload['requirements'] : [];

        return [
            'force_update' => $this->firstBool([
                $payload['force_update'] ?? null,
                $package['force_update'] ?? null,
                $upgrade['force_update'] ?? null,
            ]) ?? false,
            'min_version' => $this->firstString([
                $payload['min_upgradable_version'] ?? null,
                $payload['minimum_version'] ?? null,
                $payload['min_version'] ?? null,
                $package['min_upgradable_version'] ?? null,
                $package['minimum_version'] ?? null,
                $package['min_version'] ?? null,
                $packageRequirements['min_version'] ?? null,
                $packageRequirements['minimum_version'] ?? null,
                $packageRequirements['min_display_version'] ?? null,
                $requirements['min_version'] ?? null,
                $requirements['minimum_version'] ?? null,
                $requirements['min_display_version'] ?? null,
                $upgrade['minimum_version'] ?? null,
            ]),
            'min_update_version' => $this->firstInt([
                $payload['min_upgradable_update_version'] ?? null,
                $payload['minimum_update_version'] ?? null,
                $payload['min_update_version'] ?? null,
                $package['min_upgradable_update_version'] ?? null,
                $package['minimum_update_version'] ?? null,
                $package['min_update_version'] ?? null,
                $packageRequirements['min_update_version'] ?? null,
                $packageRequirements['minimum_update_version'] ?? null,
                $packageRequirements['min_upgradable_update_version'] ?? null,
                $requirements['min_update_version'] ?? null,
                $requirements['minimum_update_version'] ?? null,
                $requirements['min_upgradable_update_version'] ?? null,
                $upgrade['minimum_update_version'] ?? null,
            ]),
        ];
    }

    /**
     * @param  array<string, mixed>|null  $requirements
     * @param  array{force_update: bool, min_version: ?string, min_update_version: ?int}  $policy
     * @return array<string, mixed>|null
     */
    public function canonicalRequirements(?array $requirements, array $policy): ?array
    {
        $canonical = $requirements ?? [];

        if ($policy['min_version'] !== null) {
            $canonical['min_version'] = $policy['min_version'];
        }

        if ($policy['min_update_version'] !== null) {
            $canonical['min_update_version'] = $policy['min_update_version'];
        }

        return $canonical === [] ? null : $canonical;
    }

    /** @param list<mixed> $values */
    private function firstString(array $values): ?string
    {
        foreach ($values as $value) {
            if (is_string($value) && trim($value) !== '') {
                return trim($value);
            }
        }

        return null;
    }

    /** @param list<mixed> $values */
    private function firstInt(array $values): ?int
    {
        foreach ($values as $value) {
            if ($value === null || $value === '') {
                continue;
            }

            if (is_int($value) || is_numeric($value)) {
                $resolved = (int) $value;

                if ($resolved >= 0) {
                    return $resolved;
                }
            }
        }

        return null;
    }

    /** @param list<mixed> $values */
    private function firstBool(array $values): ?bool
    {
        foreach ($values as $value) {
            if ($value === null || $value === '') {
                continue;
            }

            $resolved = filter_var($value, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);

            if ($resolved !== null) {
                return $resolved;
            }
        }

        return null;
    }
}
