#include "adapters/windows/console/WindowsConsoleSession.h"

#include <string>

#include "foundation/diagnostics/Logger.h"

namespace ta::adapters::windows::console
{
    WindowsConsoleSession::~WindowsConsoleSession() noexcept
    {
        close();
    }

    bool WindowsConsoleSession::open(const std::string_view title) noexcept
    {
        if (open_)
            return true;

        original_stdin_ = GetStdHandle(STD_INPUT_HANDLE);
        original_stdout_ = GetStdHandle(STD_OUTPUT_HANDLE);
        original_stderr_ = GetStdHandle(STD_ERROR_HANDLE);
        if (!AllocConsole())
            return false;

        output_ = CreateFileA(
            "CONOUT$",
            GENERIC_READ | GENERIC_WRITE,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            nullptr,
            OPEN_EXISTING,
            FILE_ATTRIBUTE_NORMAL,
            nullptr);
        if (!output_ || output_ == INVALID_HANDLE_VALUE)
        {
            output_ = nullptr;
            FreeConsole();
            return false;
        }

        SetStdHandle(STD_INPUT_HANDLE, original_stdin_);
        SetStdHandle(STD_OUTPUT_HANDLE, original_stdout_);
        SetStdHandle(STD_ERROR_HANDLE, original_stderr_);

        sink_.set_output(output_);
        ta::foundation::logger::set_sink(&sink_);
        const std::string owned_title(title);
        SetConsoleTitleA(owned_title.c_str());
        open_ = true;
        return true;
    }

    void WindowsConsoleSession::close() noexcept
    {
        if (!open_)
            return;

        ta::foundation::logger::set_sink(nullptr);
        sink_.set_output(nullptr);
        if (output_ && output_ != INVALID_HANDLE_VALUE)
            CloseHandle(output_);
        output_ = nullptr;
        FreeConsole();
        SetStdHandle(STD_INPUT_HANDLE, original_stdin_);
        SetStdHandle(STD_OUTPUT_HANDLE, original_stdout_);
        SetStdHandle(STD_ERROR_HANDLE, original_stderr_);
        open_ = false;
    }
}
