#include <vtpty/MockPty.hpp>

#include <crispy/BufferObject.hpp>

#include <cerrno>

using namespace std::chrono;
using std::optional;
using std::string_view;

namespace vtpty
{

MockPty::MockPty(PageSize size): _pageSize { size }
{
}

PtySlave& MockPty::slave() noexcept
{
    return _slave;
}

std::optional<Pty::ReadResult> MockPty::read(crispy::BufferObject<char>& storage,
                                             std::optional<std::chrono::milliseconds> /*timeout*/,
                                             size_t size)
{
    auto const n = std::min({ size, _outputBuffer.size() - _outputReadOffset, storage.bytesAvailable() });
    auto const chunk = string_view { _outputBuffer.data() + _outputReadOffset, n };
    _outputReadOffset += n;
    auto const pooled = storage.writeAtEnd(chunk);
    return ReadResult { .data = string_view(pooled.data(), pooled.size()), .fromStdoutFastPipe = false };
}

void MockPty::wakeupReader()
{
    // No-op. as we're a mock-pty.
}

int MockPty::write(std::string_view data)
{
    switch (_writeBehavior)
    {
        case PtyWriteBehavior::FailAgain: errno = EAGAIN; return -1;
        case PtyWriteBehavior::FailFatally: errno = EIO; return -1;
        case PtyWriteBehavior::Accept: break;
    }

    // Writing into stdin.
    _inputBuffer += std::string_view(data.data(), data.size());
    return static_cast<int>(data.size());
}

PageSize MockPty::pageSize() const noexcept
{
    return _pageSize;
}

void MockPty::resizeScreen(PageSize cells, std::optional<ImageSize> pixels)
{
    _pageSize = cells;
    _pixelSize = pixels;
}

StartResult MockPty::start()
{
    _closed = false;
    return {};
}

void MockPty::close()
{
    _closed = true;
}

void MockPty::waitForClosed()
{
    // No-op. as we're a mock-pty.
}

bool MockPty::isClosed() const noexcept
{
    return _closed;
}

} // namespace vtpty
