// Copyright 2026 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
priv enum TransportState {
  Normal
  Closed
  Error(Error)
}

///|
priv struct Transport {
  mut state : TransportState
  reader : &@io.BinaryReader
  read_lock : @semaphore.Semaphore
  write_buf : @io_buffer.Buffer
  writer : &@io.BinaryWriter
  write_lock : @semaphore.Semaphore
}

///|
const BUFFER_SIZE = 4096

///|
fn Transport::new(
  reader : &@io.BinaryReader,
  writer : &@io.BinaryWriter,
) -> Transport {
  {
    state: Normal,
    reader,
    read_lock: Semaphore(1),
    write_buf: @io_buffer.new(BUFFER_SIZE),
    writer,
    write_lock: Semaphore(1),
  }
}

///|
#warnings("-fragile_catch_all")
async fn Transport::read_more(self : Transport) -> Unit {
  self.read_lock.acquire()
  defer self.read_lock.release()
  match self.state {
    Normal => ()
    Closed => raise ConnectionClosed
    Error(err) => raise err
  }
  let controller = @io.BinaryReaderImpl::get_controller(self.reader)
  let prev_len = controller.buffered().length()
  try @io.BinaryReaderImpl::ensure_buffered(self.reader, prev_len + 1) catch {
    err => {
      self.state = Error(err)
      raise err
    }
  } noraise {
    true => ()
    false => self.state = Closed
  }
}

///|
async fn Transport::flush_write(self : Transport) -> Unit {
  self.write_lock.acquire()
  defer self.write_lock.release()
  guard self.write_buf.len > 0 else {  }
  match self.state {
    Normal => ()
    Closed => raise ConnectionClosed
    Error(err) => raise err
  }
  let start = self.write_buf.start
  let end = self.write_buf.start + self.write_buf.len
  let data = self.write_buf.buf.unsafe_reinterpret_as_bytes()[start:end]
  self.writer.write(data)
  self.write_buf.start = 0
  self.write_buf.len = 0
}