// 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.

///|
/// This type is for internal use only,
/// end users should not use this type directly.
#internal(internal, "this type is for internal use only")
struct ReaderBuffer(@io_buffer.Buffer)

///|
#internal(internal, "this function is for internal use only")
pub fn ReaderBuffer::new() -> ReaderBuffer {
  @io_buffer.new(0)
}

///|
fn ReaderBuffer::clear(self : Self) -> Unit {
  self.0.clear()
}

///|
fn ReaderBuffer::buf(self : Self) -> FixedArray[Byte] {
  self.0.buf
}

///|
fn ReaderBuffer::len(self : Self) -> Int {
  self.0.len
}

///|
fn ReaderBuffer::start(self : Self) -> Int {
  self.0.start
}

///|
fn ReaderBuffer::set_len(self : Self, len : Int) -> Unit {
  self.0.len = len
}

///|
fn ReaderBuffer::set_start(self : Self, start : Int) -> Unit {
  self.0.start = start
}

///|
fn ReaderBuffer::drop(self : Self, n : Int) -> Unit {
  self.0.drop(n)
}

///|
fn ReaderBuffer::enlarge_to(self : Self, n : Int) -> Unit {
  self.0.enlarge_to(n)
}

///|
fn[R : Reader] ReaderBuffer::try_ensure(
  self : Self,
  len : Int,
  reader~ : R,
) -> Bool raise {
  if self.len() >= len {
    return true
  }
  self.enlarge_to(len)
  let capacity = self.buf().length()
  while self.len() < len {
    let offset = self.start() + self.len()
    let n = reader._direct_read(self.buf(), offset~, max_len=capacity - offset)
    if n == 0 {
      return false
    }
    self.set_len(self.len() + n)
  }
  true
}

///|
fn[R : Reader] ReaderBuffer::find_opt(
  self : Self,
  target : Bytes,
  reader~ : R,
) -> Int? raise {
  let target_len = target.length()
  for searched = 0 {
    guard self.try_ensure(searched + target_len, reader~) else { return None }
    let len = self.len()
    let start = self.start() + searched
    let end = self.start() + len
    let region = self.buf().unsafe_reinterpret_as_bytes()[start:end]
    if region.find(target) is Some(i) {
      return Some(searched + i)
    }
    continue len - target_len + 1
  }
}