<?php

namespace App\Support\Os;

/**
 * Immutable description of a fleet host's operating system, resolved once by
 * OsDetector from /etc/os-release + a `command -v` probe. Everything that used to
 * hard-code Debian/apt/ufw/systemd now asks an OsProfile instead.
 *
 * Phase-1 fully-supported package managers: apt, dnf (incl. yum), zypper — all on
 * systemd hosts with ufw or firewalld. Arch (pacman) and Alpine (apk/OpenRC) are
 * DETECTED and surfaced, but features that need an unsupported manager/init are
 * gracefully disabled with a German reason via supports().
 */
final class OsProfile
{
    /** Package managers Clusev can drive for updates/installs in this release. */
    public const SUPPORTED_MANAGERS = ['apt', 'dnf', 'zypper'];

    /**
     * @param  list<string>  $available  detected binaries (apt-get, dnf, ufw, firewall-cmd, systemctl, …)
     */
    public function __construct(
        public readonly string $family,          // debian|rhel|suse|arch|alpine|unknown
        public readonly string $id,              // raw /etc/os-release ID
        public readonly string $prettyName,      // PRETTY_NAME for display
        public readonly string $packageManager,  // apt|dnf|zypper|pacman|apk|none
        public readonly string $firewallTool,    // ufw|firewalld|none
        public readonly string $serviceManager,  // systemd|openrc|none
        public readonly array $available = [],
    ) {}

    public function has(string $binary): bool
    {
        return in_array($binary, $this->available, true);
    }

    public function isSystemd(): bool
    {
        return $this->serviceManager === 'systemd';
    }

    /** True when Clusev can drive package install/update on this host. */
    public function managesPackages(): bool
    {
        return in_array($this->packageManager, self::SUPPORTED_MANAGERS, true);
    }

    /** German family label for the UI. */
    public function familyLabel(): string
    {
        return match ($this->family) {
            'debian' => __('backend.family_debian'),
            'rhel' => __('backend.family_rhel'),
            'suse' => __('backend.family_suse'),
            'arch' => __('backend.family_arch'),
            'alpine' => __('backend.family_alpine'),
            default => __('backend.family_unknown'),
        };
    }

    /** German label for the host firewall in the hardening checklist. */
    public function firewallLabel(): string
    {
        return match ($this->firewallTool) {
            'ufw' => __('backend.firewall_label_ufw'),
            'firewalld' => __('backend.firewall_label_firewalld'),
            default => __('backend.firewall_label_generic'),
        };
    }

    /**
     * Whether a feature is supported on this host. Returns NULL when supported, or
     * a German reason to show the operator when not — so unsupported combinations
     * degrade with an explanation instead of failing opaquely.
     */
    public function supports(string $feature): ?string
    {
        return match ($feature) {
            'ssh' => $this->isSystemd()
                ? null
                : __('backend.support_ssh', ['family' => $this->familyLabel()]),
            'services' => $this->isSystemd()
                ? null
                : __('backend.support_services'),
            'updates' => $this->managesPackages()
                ? null
                : __('backend.support_updates', ['family' => $this->familyLabel()]),
            'fail2ban' => ($this->managesPackages() && $this->isSystemd())
                ? null
                : __('backend.support_fail2ban', ['family' => $this->familyLabel()]),
            'firewall' => ($this->firewallTool !== 'none' && $this->isSystemd()
                && ($this->firewallTool === 'firewalld' || $this->managesPackages() || $this->has('ufw')))
                ? null
                : __('backend.support_firewall', ['family' => $this->familyLabel()]),
            // apt -> unattended-upgrades; dnf -> dnf-automatic. A yum-ONLY host (e.g.
            // CentOS 7) maps to the dnf manager for upgrades but has no dnf-automatic
            // (it uses yum-cron), so require a real `dnf` binary for this feature.
            'auto_updates' => (($this->packageManager === 'apt'
                || ($this->packageManager === 'dnf' && $this->has('dnf'))) && $this->isSystemd())
                ? null
                : __('backend.support_auto_updates', ['family' => $this->familyLabel()]),
            default => null,
        };
    }
}
