#include "bootstrap/RuntimeShutdown.h"

#include <string>

#include "adapters/eft/localization/EftLocalizationService.h"
#include "adapters/unity/chams/resources/ChamsBundleRuntime.h"
#include "adapters/windows/console/WindowsConsoleSession.h"
#include "adapters/windows/storage/RuntimeStorageLayout.h"
#include "application/lifecycle/CallbackBarrier.h"
#include "application/lifecycle/RuntimeState.h"
#include "bootstrap/ApplicationRuntime.h"
#include "foundation/diagnostics/Logger.h"
#include "foundation/diagnostics/CrashDiagnostics.h"
#include "presentation/action_feedback/ActionFeedbackPresenter.h"
#include "presentation/MenuController.h"
#include "presentation/localization/UiLocalizationService.h"

namespace ta::bootstrap
{
    using ta::application::runtime::callback_barrier;
    using ta::application::runtime::clear_application_update_thread;

    RuntimeShutdown::RuntimeShutdown(
        ta::adapters::windows::console::WindowsConsoleSession& console,
        std::unique_ptr<ApplicationRuntime>& application,
        std::unique_ptr<ta::presentation::MenuController>& menu,
        std::optional<PresentHookHandle>& present_hook,
        std::optional<FeatureHooksHandle>& feature_hooks) noexcept
        : console_(console),
          application_(application),
          menu_(menu),
          present_hook_(present_hook),
          feature_hooks_(feature_hooks)
    {
    }

    bool RuntimeShutdown::run(const bool rollback) noexcept
    {
        callback_barrier().begin_shutdown();

        bool present_detached = !present_hook_;
        bool feature_hooks_detached = !feature_hooks_;
        bool callbacks_idle = false;
        const char* context = rollback ? "rollback" : "shutdown";

        try
        {
            present_detached = !present_hook_ || present_hook_->detach();
            feature_hooks_detached = !feature_hooks_ || feature_hooks_->detach();

            if (!rollback)
            {
                if (present_detached && present_hook_)
                    ta::foundation::logger::info("RUNTIME", "present hook detached");
                else if (!present_detached)
                    ta::foundation::logger::error("Present detach failed; preserving render resources");

                if (feature_hooks_detached && feature_hooks_)
                    ta::foundation::logger::info("RUNTIME", "game hooks detached");
                else if (!feature_hooks_detached)
                    ta::foundation::logger::error("Feature hook detach failed; preserving modules and hook state");
            }

            callbacks_idle = callback_barrier().wait_for_idle();
            if (!callbacks_idle)
            {
                ta::foundation::logger::error(std::string("RuntimeHost ") + context +
                    " barrier timed out; runtime state was preserved");
            }
            else
            {
                if (present_hook_ && present_detached)
                {
                    present_hook_->release_resources();
                    present_hook_.reset();
                }

                if (feature_hooks_ && feature_hooks_detached)
                {
                    feature_hooks_->release_state();
                    feature_hooks_.reset();
                }
            }

            if (rollback && (!present_detached || !feature_hooks_detached))
                ta::foundation::logger::error("RuntimeHost rollback preserved state because callback detach failed");
        }
        catch (...)
        {
            ta::foundation::logger::error(std::string("RuntimeHost ") + context +
                " failed while shutting down hooks/rendering");
        }

        try
        {
            if (callbacks_idle && present_detached)
                menu_.reset();

            if (application_ && !menu_ && callbacks_idle && feature_hooks_detached)
                application_.reset();
        }
        catch (...)
        {
            ta::foundation::logger::error(std::string("RuntimeHost ") + context +
                " failed while deleting application graph");
        }

        const bool shutdown_complete = callbacks_idle && !present_hook_ && !feature_hooks_ && !application_ && !menu_;
        if (shutdown_complete)
        {
            ta::adapters::unity::chams::ChamsBundleRuntime::instance().reset();
            clear_application_update_thread();
            ta::adapters::eft::localization::EftLocalizationService::reset_session();
            ta::presentation::ActionFeedbackPresenter::reset();
            ta::presentation::localization::reset();
            ta::foundation::diagnostics::crash::shutdown();
            ta::adapters::windows::storage::reset();
            console_.close();
        }
        return shutdown_complete;
    }
}
