#include "bootstrap/RuntimeHost.h"

#include <string>

#include "application/lifecycle/RuntimeState.h"
#include "bootstrap/ApplicationRuntime.h"
#include "bootstrap/RuntimeShutdown.h"
#include "bootstrap/RuntimeStartup.h"
#include "foundation/diagnostics/Logger.h"
#include "presentation/MenuController.h"

namespace ta::bootstrap
{
    using ta::application::runtime::RuntimePhase;
    using ta::application::runtime::state;

    RuntimeHost::RuntimeHost(const HMODULE dll_handle) noexcept
        : dll_handle_(dll_handle)
    {
    }

    RuntimeHost::~RuntimeHost() noexcept
    {
        stop();
    }

    bool RuntimeHost::start() noexcept
    {
        std::lock_guard lifecycle_lock(lifecycle_mutex_);
        shutdown_requested_.store(false, std::memory_order_release);

        if (state().phase() == RuntimePhase::Running || state().phase() == RuntimePhase::Starting)
        {
            ta::foundation::logger::warn("RuntimeHost::start ignored because runtime is already active");
            return false;
        }
        if (application_ || menu_ || present_hook_ || feature_hooks_)
        {
            ta::foundation::logger::error("RuntimeHost::start refused because a previous shutdown is incomplete");
            return false;
        }

        state().set_phase(RuntimePhase::Starting);
        RuntimeStartup startup(
            dll_handle_,
            shutdown_requested_,
            console_,
            key_input_,
            application_,
            menu_,
            present_hook_,
            feature_hooks_);

        if (const std::optional<StartupError> error = startup.run())
            return fail_startup(*error);

        state().set_phase(RuntimePhase::Running);
        return true;
    }

    void RuntimeHost::stop() noexcept
    {
        shutdown_requested_.store(true, std::memory_order_release);
        std::lock_guard lifecycle_lock(lifecycle_mutex_);

        const RuntimePhase current_phase = state().phase();
        if (current_phase == RuntimePhase::None || current_phase == RuntimePhase::Stopped ||
            current_phase == RuntimePhase::Stopping)
        {
            return;
        }

        state().set_phase(RuntimePhase::Stopping);
        const bool shutdown_complete = shutdown_components(false);
        state().set_phase(shutdown_complete ? RuntimePhase::Stopped : RuntimePhase::Failed);
    }

    bool RuntimeHost::fail_startup(const StartupError& error) noexcept
    {
        ta::foundation::logger::error(
            "RuntimeHost startup failed | stage=" + std::string(to_string(error.stage)) +
            " | code=" + error.code + " | detail=" + error.detail);

        state().set_phase(RuntimePhase::Stopping);
        static_cast<void>(shutdown_components(true));
        state().set_phase(RuntimePhase::Failed);
        return false;
    }

    bool RuntimeHost::shutdown_components(const bool rollback) noexcept
    {
        RuntimeShutdown shutdown(console_, application_, menu_, present_hook_, feature_hooks_);
        return shutdown.run(rollback);
    }
}
