<?php

declare(strict_types=1);

namespace PpPhp\Core\Licensing;

use PpPhp\Core\PlatformSettings;

/**
 * Is this install the MAIN licence server or a BACKUP of one?
 *
 * The role changes what the Licence server console offers: the main issues
 * licences and hands out pairing codes; a backup shows its pairing/sync status
 * and never issues.
 *
 * Where the role lives, and why it survives updates:
 *   • the authoritative value is a row in the `settings` table (DB survives any
 *     code update);
 *   • a fresh BACKUP bundle also ships `config/server-role.json` so the very
 *     first request already knows its role and the main's address — that file is
 *     under config/, which the updater never overwrites, so it persists too.
 */
final class ServerRole
{
    public const MAIN = 'main';
    public const BACKUP = 'backup';

    public const SETTING = 'platform.server_role';

    /** Per-request memo of the resolved role bag; cleared whenever it changes. */
    private static ?array $cache = null;

    /** Path to the role file shipped inside a backup bundle. */
    public static function file(?string $basePath = null): string
    {
        $basePath ??= defined('BASE_PATH') ? constant('BASE_PATH') : dirname(__DIR__, 2);
        return rtrim($basePath, '/') . '/config/server-role.json';
    }

    public static function role(): string
    {
        $r = self::bag();
        return ($r['role'] ?? self::MAIN) === self::BACKUP ? self::BACKUP : self::MAIN;
    }

    public static function isBackup(): bool
    {
        return self::role() === self::BACKUP;
    }

    /** The main server's address, when this install is a backup. */
    public static function mainUrl(): string
    {
        return (string) (self::bag()['main'] ?? '');
    }

    public static function setBackup(string $mainUrl): void
    {
        PlatformSettings::set(self::SETTING, ['role' => self::BACKUP, 'main' => rtrim(trim($mainUrl), '/')]);
        self::$cache = null;
    }

    public static function setMain(): void
    {
        PlatformSettings::set(self::SETTING, ['role' => self::MAIN, 'main' => '']);
        self::$cache = null;
    }

    /**
     * The effective role bag: the DB setting if present, otherwise seeded from
     * the shipped config file (a fresh backup install), otherwise main.
     */
    private static function bag(): array
    {
        if (self::$cache !== null) return self::$cache;

        try {
            $s = PlatformSettings::get(self::SETTING);
            if (!empty($s['role'])) return self::$cache = $s;
        } catch (\Throwable $e) {
            // no DB yet — fall through to the file
        }

        $file = self::file();
        if (is_file($file)) {
            $data = json_decode((string) @file_get_contents($file), true);
            if (is_array($data) && ($data['role'] ?? '') === self::BACKUP) {
                // Persist to the DB so later reads don't depend on the file.
                try { PlatformSettings::set(self::SETTING, ['role' => self::BACKUP, 'main' => (string) ($data['main'] ?? '')]); } catch (\Throwable $e) {}
                return self::$cache = ['role' => self::BACKUP, 'main' => (string) ($data['main'] ?? '')];
            }
        }
        return self::$cache = ['role' => self::MAIN, 'main' => ''];
    }
}
