///|
/// 宿主错误与文件格式错误分离;所有数据源须提供不可变的静态快照。
/// 宿主范围读取错误:HostFailure 为实际宿主抛错,ShortRead 为返回长度不符,RangeOutOfBounds 为范围越界。不是 SQLite 格式损坏。
pub(all) suberror SourceError {
  HostFailure(String)
  ShortRead(String)
  RangeOutOfBounds(String)
}

///|
/// 长度和偏移为有符号 64 位;单次读取长度仍为 Int,必须精确返回请求长度。
/// 同步静态范围源;长度与偏移为非负 Int64,单次长度为非负 Int,必须精确返回请求字节,失败抛 SourceError。宿主负责一致副本、I/O 和句柄生命周期。
pub(open) trait RangeSource {
  fn byte_length64(Self) -> Int64
  fn read_range64(Self, Int64, Int) -> Bytes raise SourceError
}

///|
/// 将旧 PageSource 包装为 RangeSource。自身检查越界和短读;旧源实际抛出的 SqliteError 归为 HostFailure。不能扩展旧源的实际 Int 地址空间。
pub struct PageSourceAdapter {
  source : &PageSource
}

///|
/// 包装旧同步源,不立即读取;之后分别检查越界和短读,实际宿主抛错归 HostFailure。
pub fn PageSourceAdapter::new(source : &PageSource) -> PageSourceAdapter {
  { source, }
}

///|
/// 返回静态源字节长度,不执行格式检查。
pub impl RangeSource for PageSourceAdapter with fn byte_length64(self) {
  self.source.byte_length().to_int64()
}

///|
/// 按源契约返回准确范围字节;范围和长度错误按实现所属的源错误类型返回。
pub impl RangeSource for PageSourceAdapter with fn read_range64(
  self,
  offset,
  count,
) {
  check_source_range(self.byte_length64(), offset, count)
  let data = self.source.read_range(offset.to_int(), count) catch {
    Invalid(message) | Unsupported(message) | LimitExceeded(message) =>
      raise HostFailure(message)
  }
  if data.length() != count {
    raise ShortRead(
      "旧 PageSource 短读:offset=\{offset}, expected=\{count}, actual=\{data.length()}",
    )
  }
  data
}

///|
/// 返回静态源字节长度,不执行格式检查。
pub impl RangeSource for BytesSource with fn byte_length64(self) {
  self.data.length().to_int64()
}

///|
/// 按源契约返回准确范围字节;范围和长度错误按实现所属的源错误类型返回。
pub impl RangeSource for BytesSource with fn read_range64(self, offset, count) {
  check_source_range(self.byte_length64(), offset, count)
  let start = offset.to_int()
  self.data[start:start + count].to_owned()
}

///|
fn check_source_range(
  size : Int64,
  offset : Int64,
  count : Int,
) -> Unit raise SourceError {
  if size < 0L ||
    offset < 0L ||
    count < 0 ||
    offset > size ||
    count.to_int64() > size - offset {
    raise RangeOutOfBounds(
      "范围读取越界:offset=\{offset}, count=\{count}, size=\{size}",
    )
  }
}

///|
fn range_read(
  source : &RangeSource,
  offset : Int64,
  count : Int,
) -> Bytes raise SourceError {
  check_source_range(source.byte_length64(), offset, count)
  let data = source.read_range64(offset, count)
  if data.length() != count {
    raise ShortRead(
      "范围读取短读:offset=\{offset}, expected=\{count}, actual=\{data.length()}",
    )
  }
  data
}

///|
fn range_sqlite_read(
  source : &RangeSource,
  offset : Int64,
  count : Int,
) -> Bytes raise SqliteError {
  range_read(source, offset, count) catch {
    HostFailure(message) => raise Unsupported("source/host_failure: \{message}")
    ShortRead(message) => raise Unsupported("source/short_read: \{message}")
    RangeOutOfBounds(message) =>
      raise Unsupported("source/range_out_of_bounds: \{message}")
  }
}

///|
priv enum DataSource {
  LegacySource(&PageSource)
  WideSource(&RangeSource)
}

///|
fn data_length(source : DataSource) -> Int64 {
  match source {
    LegacySource(source) => source.byte_length().to_int64()
    WideSource(source) => source.byte_length64()
  }
}

///|
fn data_read(
  source : DataSource,
  offset : Int64,
  count : Int,
) -> Bytes raise SqliteError {
  match source {
    LegacySource(source) => {
      if offset < 0L || offset > 2147483647L {
        raise LimitExceeded("旧 PageSource 偏移超出 Int 范围")
      }
      source_read(source, offset.to_int(), count)
    }
    WideSource(source) => range_sqlite_read(source, offset, count)
  }
}

///|
/// 64 位寻址;页号保持 Int,超过 2147483647 页显式拒绝,避免静默截断。
/// 打开 64 位静态范围源,初始化只读取 100 字节头;页号仍最多 2147483647。宿主 SourceError 映射为 Unsupported(source/...),报告为 Incomplete。max_report_pages 独立约束全库报告。
pub fn open_range_source(
  source : &RangeSource,
  limits? : Limits = Limits::default(),
  max_report_pages? : Int = 100000,
) -> Database raise SqliteError {
  open_data_source(WideSource(source), limits, None, max_report_pages~)
}

///|
/// 缓存累计统计;hits/misses 是块请求次数,bytes_read 是宿主实际返回字节数,resident_pages 是当前驻留块数。
pub(all) struct CacheStatistics {
  hits : Int64
  misses : Int64
  bytes_read : Int64
  resident_pages : Int
} derive(Debug)

///|
/// 按固定块缓存,FIFO 淘汰;缓存与扫描状态、归属报告、WAL 索引预算互相独立。
/// 固定块 FIFO 范围缓存;驻留块有界,返回字节副本,失败不缓存。不会限制遍历状态、单条 payload、全库报告或 WAL 索引的内存。
pub struct CachedSource {
  priv source : &RangeSource
  priv size : Int64
  priv block_size : Int
  priv capacity : Int
  priv blocks : Map[Int64, Bytes]
  priv slots : Array[Int64]
  priv mut next_slot : Int
  priv mut hits : Int64
  priv mut misses : Int64
  priv mut bytes_read : Int64
}

///|
/// 创建固定块 FIFO 缓存;block_size 默认 4096,max_pages 默认 256,均须为正并符合限制。不是数据库或报告内存上限。
pub fn CachedSource::new(
  source : &RangeSource,
  block_size? : Int = 4096,
  max_pages? : Int = 256,
) -> CachedSource raise SqliteError {
  if block_size < 1 ||
    block_size > 65536 ||
    max_pages < 1 ||
    max_pages > 1048576 {
    raise Invalid(
      "缓存块大小须在 1–65536、容量须在 1–1048576 之间",
    )
  }
  let size = source.byte_length64()
  if size < 0L {
    raise Invalid("数据源长度不能为负数")
  }
  {
    source,
    size,
    block_size,
    capacity: max_pages,
    blocks: Map([]),
    slots: [],
    next_slot: 0,
    hits: 0L,
    misses: 0L,
    bytes_read: 0L,
  }
}

///|
/// 返回累计块命中、未命中、实际宿主字节和当前驻留块数,不进行额外读取。
pub fn CachedSource::statistics(self : CachedSource) -> CacheStatistics {
  {
    hits: self.hits,
    misses: self.misses,
    bytes_read: self.bytes_read,
    resident_pages: self.blocks.length(),
  }
}

///|
/// 返回静态源字节长度,不执行格式检查。
pub impl RangeSource for CachedSource with fn byte_length64(self) {
  self.size
}

///|
/// 按源契约返回准确范围字节;范围和长度错误按实现所属的源错误类型返回。
pub impl RangeSource for CachedSource with fn read_range64(self, offset, count) {
  check_source_range(self.size, offset, count)
  let result : FixedArray[Byte] = FixedArray::make(count, 0)
  let mut copied = 0
  while copied < count {
    let position = offset + copied.to_int64()
    let key = position / self.block_size.to_int64()
    let start = key * self.block_size.to_int64()
    let data = match self.blocks.get(key) {
      Some(data) => {
        self.hits = self.hits + 1L
        data
      }
      None => {
        let size = Int64::min(self.block_size.to_int64(), self.size - start).to_int()
        let data = range_read(self.source, start, size)
        self.misses = self.misses + 1L
        self.bytes_read = self.bytes_read + size.to_int64()
        if self.slots.length() < self.capacity {
          self.slots.push(key)
        } else {
          self.blocks.remove(self.slots[self.next_slot])
          self.slots[self.next_slot] = key
          self.next_slot = (self.next_slot + 1) % self.capacity
        }
        self.blocks[key] = data
        data
      }
    }
    let in_block = (position - start).to_int()
    let length = Int::min(count - copied, data.length() - in_block)
    for i = 0; i < length; i = i + 1 {
      result[copied + i] = data[in_block + i]
    }
    copied = copied + length
  }
  Bytes::from_array(result)
}

///|
pub extend BytesSource with RangeSource::{byte_length64, read_range64}

///|
pub extend PageSourceAdapter with RangeSource::{byte_length64, read_range64}

///|
pub extend CachedSource with RangeSource::{byte_length64, read_range64}

///|
pub extend CacheStatistics with @debug.Debug::{to_repr}

///|
// 既有公开 Database.source 字段保持类型;64 位源无法表示的长度明确返回 -1。
priv struct LegacyRangeView {
  source : &RangeSource
}

///|
impl PageSource for LegacyRangeView with fn byte_length(self) {
  let size = self.source.byte_length64()
  if size < 0L || size > 2147483647L {
    -1
  } else {
    size.to_int()
  }
}

///|
impl PageSource for LegacyRangeView with fn read_range(self, offset, count) {
  if PageSource::byte_length(self) < 0 {
    raise LimitExceeded(
      "64 位数据源无法用旧 PageSource 表示,请使用 Database.source64",
    )
  }
  range_sqlite_read(self.source, offset.to_int64(), count)
}

///|
/// 返回用于完整读取的 64 位源;旧 source 字段保持 v0.5 的 Int 契约。
/// 获取完整 64 位静态范围视图;旧源经适配器返回,不扩展旧源实际地址空间。
pub fn Database::source64(self : Database) -> &RangeSource {
  let result : &RangeSource = match self.data_source {
    LegacySource(source) => (PageSourceAdapter::new(source) : &RangeSource)
    WideSource(source) => source
  }
  result
}