<?php

declare(strict_types=1);

namespace Atdt;

/**
 * Screen registry + dispatch (SPEC §9.4).
 *
 * sessions.state holds a JSON stack of frames like
 * [{"screen":"Matrix","d":{...}}]; the top frame is live. See Screen (the
 * interface), In (the input wrapper), and Ctx (the service hub).
 */
final class ScreenEngine
{
    /** Registered v1 screens (grows through M5–M8). */
    private const SCREENS = [
        'Matrix' => Screens\MatrixScreen::class,
        'NewUserApp' => Screens\NewUserAppScreen::class,
        'PostLogin' => Screens\PostLoginScreen::class,
        'Menu' => Screens\MenuScreen::class,
        'MsgAreas' => Screens\MsgAreasScreen::class,
        'MsgList' => Screens\MsgListScreen::class,
        'Reader' => Screens\ReaderScreen::class,
        'Composer' => Screens\ComposerScreen::class,
        'MailBox' => Screens\MailBoxScreen::class,
        'NewScan' => Screens\NewScanScreen::class,
        'Chat' => Screens\ChatScreen::class,
        'Help' => Screens\HelpScreen::class,
        'EmailSysop' => Screens\EmailSysopScreen::class,
        'SysopChat' => Screens\SysopChatScreen::class,
        'PageSysop' => Screens\PageSysopScreen::class,
        'Oneliners' => Screens\OnelinersScreen::class,
        'Rumors' => Screens\RumorsScreen::class,
        'AutoMsg' => Screens\AutoMsgScreen::class,
        'Voting' => Screens\VotingScreen::class,
        'BbsList' => Screens\BbsListScreen::class,
        'Bulletins' => Screens\BulletinsScreen::class,
        'UserList' => Screens\UserListScreen::class,
        'LastCallers' => Screens\LastCallersScreen::class,
        'WhosOnline' => Screens\WhosOnlineScreen::class,
        'Stats' => Screens\StatsScreen::class,
        'UserSettings' => Screens\UserSettingsScreen::class,
        'Door' => Screens\DoorScreen::class,
    ];

    public static function make(string $name): Screen
    {
        $class = self::SCREENS[$name] ?? null;
        if ($class === null) {
            throw new \RuntimeException("Unknown screen '$name'");
        }
        return new $class();
    }

    public static function exists(string $name): bool
    {
        return isset(self::SCREENS[$name]);
    }

    /** Render the current top screen (connect / re-entry). */
    public static function enterTop(Ctx $c): array
    {
        return self::make($c->topScreen())->enter($c);
    }

    /** Route one input to the current top screen. */
    public static function dispatch(Ctx $c, In $in): array
    {
        return self::make($c->topScreen())->input($c, $in);
    }

    /** describe() for a serialized state stack (who's-online, M5). */
    public static function describeState(string $stateJson): string
    {
        $stack = json_decode($stateJson, true);
        $top = is_array($stack) && $stack !== [] ? end($stack) : null;
        $name = is_array($top) ? (string)($top['screen'] ?? '') : '';
        return self::exists($name) ? self::make($name)->describe() : 'On the board';
    }
}
