#pragma once

#include <Windows.h>

#include <atomic>
#include <cstdint>
#include <memory>
#include <optional>
#include <string>

#include "bootstrap/RuntimeHandles.h"

namespace ta::adapters::windows::console
{
    class WindowsConsoleSession;
}

namespace ta::adapters::windows::input
{
    class WindowsKeyInput;
}

namespace ta::presentation
{
    class MenuController;
}

namespace ta::bootstrap
{
    class ApplicationRuntime;

    enum class StartupStage : std::uint8_t
    {
        Storage,
        Localization,
        Resources,
        UnityWindow,
        Il2Cpp,
        UnityApi,
        ApplicationGraph,
        DisplayMetrics,
        DxLibraries,
        PresentHook,
        FeatureHooks
    };

    struct StartupError final
    {
        StartupStage stage = StartupStage::Storage;
        std::string code;
        std::string detail;
    };

    [[nodiscard]] const char* to_string(StartupStage stage) noexcept;

    class RuntimeStartup final
    {
    public:
        RuntimeStartup(
            HMODULE dll_handle,
            std::atomic_bool& shutdown_requested,
            ta::adapters::windows::console::WindowsConsoleSession& console,
            ta::adapters::windows::input::WindowsKeyInput& key_input,
            std::unique_ptr<ApplicationRuntime>& application,
            std::unique_ptr<ta::presentation::MenuController>& menu,
            std::optional<PresentHookHandle>& present_hook,
            std::optional<FeatureHooksHandle>& feature_hooks) noexcept;

        [[nodiscard]] std::optional<StartupError> run() noexcept;

    private:
        void show_console_if_enabled() noexcept;
        void log_startup_banner() const;
        [[nodiscard]] bool wait_for_unity_window() const noexcept;
        [[nodiscard]] bool wait_for_dx_libraries() const noexcept;

        HMODULE dll_handle_ = nullptr;
        std::atomic_bool& shutdown_requested_;
        ta::adapters::windows::console::WindowsConsoleSession& console_;
        ta::adapters::windows::input::WindowsKeyInput& key_input_;
        std::unique_ptr<ApplicationRuntime>& application_;
        std::unique_ptr<ta::presentation::MenuController>& menu_;
        std::optional<PresentHookHandle>& present_hook_;
        std::optional<FeatureHooksHandle>& feature_hooks_;
    };
}
