<?php
/**
 * Shared update preferences for FleekDash release channels and future plugin blocklists.
 *
 * @package FleekDash\Core
 */

namespace FleekDash\Core;

defined('ABSPATH') || exit;

class UpdatePreferences
{
    public const OPTION_KEY = 'fleekdash_update_preferences';

    public const RELEASE_CHANNEL_STABLE = 'stable';
    public const UPDATE_ACTION_IGNORE = 'ignore';
    public const UPDATE_ACTION_RESPONSE = 'response';
    public const UPDATE_ACTION_NO_UPDATE = 'no_update';

    /**
     * @return array{
     *   receive_prerelease_updates: bool,
     *   blocked_plugin_updates: list<string>
     * }
     */
    public static function getSettings(): array
    {
        $rawSettings = \get_option(self::OPTION_KEY, []);
        $settings = \is_array($rawSettings) ? $rawSettings : [];

        return self::normalizeSettings($settings);
    }

    /**
     * @param array<string, mixed> $settings
     * @return array{
     *   receive_prerelease_updates: bool,
     *   blocked_plugin_updates: list<string>
     * }
     */
    public static function saveSettings(array $settings): array
    {
        $normalized = self::normalizeSettings($settings);
        \update_option(self::OPTION_KEY, $normalized, false);

        return $normalized;
    }

    public static function shouldReceivePrereleaseUpdates(): bool
    {
        $settings = self::getSettings();

        return $settings['receive_prerelease_updates'] === true;
    }

    /**
     * @return list<string>
     */
    public static function getBlockedPluginUpdates(): array
    {
        $settings = self::getSettings();

        return $settings['blocked_plugin_updates'];
    }

    /**
     * @param array<string, mixed> $payload
     */
    public static function resolveReleaseChannelFromPayload(array $payload): string
    {
        $rawChannel = $payload['release_channel'] ?? $payload['channel'] ?? $payload['release_tag'] ?? $payload['tag'] ?? null;

        return self::normalizeReleaseChannel(\is_string($rawChannel) ? $rawChannel : '');
    }

    public static function normalizeReleaseChannel(string $channel): string
    {
        $normalized = \strtolower(\trim(\str_replace(['-', ' '], '_', $channel)));
        if (!\in_array($normalized, [self::RELEASE_CHANNEL_STABLE, 'pre_release', 'experimental'], true)) {
            $normalized = self::RELEASE_CHANNEL_STABLE;
        }

        return $normalized;
    }

    public static function isReleaseChannelEligible(string $channel): bool
    {
        $normalizedChannel = self::normalizeReleaseChannel($channel);
        switch ($normalizedChannel) {
            case self::RELEASE_CHANNEL_STABLE:
                return true;
            case 'pre_release':
                return self::shouldReceivePrereleaseUpdates();
            case 'experimental':
            default:
                return false;
        }
    }

    public static function resolveUpdateVisibilityAction(string $currentVersion, ?\stdClass $updateData): string
    {
        $action = self::UPDATE_ACTION_IGNORE;

        if ($updateData instanceof \stdClass) {
            $newVersion = (string) ($updateData->new_version ?? '');
            $isNewerVersion = $newVersion !== '' && \version_compare($currentVersion, $newVersion, '<');
            if (!$isNewerVersion) {
                $action = self::UPDATE_ACTION_NO_UPDATE;
            } else {
                $releaseChannel = (string) ($updateData->release_channel ?? self::RELEASE_CHANNEL_STABLE);
                if (self::isReleaseChannelEligible($releaseChannel)) {
                    $action = self::UPDATE_ACTION_RESPONSE;
                }
            }
        }

        return $action;
    }

    /**
     * @param array<string, mixed> $settings
     * @return array{
     *   receive_prerelease_updates: bool,
     *   blocked_plugin_updates: list<string>
     * }
     */
    private static function normalizeSettings(array $settings): array
    {
        $blockedPluginUpdates = [];
        $rawBlockedPlugins = $settings['blocked_plugin_updates'] ?? [];
        if (\is_array($rawBlockedPlugins)) {
            foreach ($rawBlockedPlugins as $pluginFile) {
                if (!\is_string($pluginFile) || $pluginFile === '') {
                    continue;
                }

                $normalizedPluginFile = \sanitize_text_field($pluginFile);
                if ($normalizedPluginFile === '') {
                    continue;
                }

                $blockedPluginUpdates[] = $normalizedPluginFile;
            }
        }

        $blockedPluginUpdates = \array_values(\array_unique($blockedPluginUpdates));

        return [
            'receive_prerelease_updates' => !empty($settings['receive_prerelease_updates']),
            'blocked_plugin_updates' => $blockedPluginUpdates,
        ];
    }
}
