// Copyright Two Neutron Stars Incorporated and contributors
// SPDX-License-Identifier: BlueOak-1.0.0

//! File-level symbol reader extension trait.
//!
//! This module provides [`SymboliqueReadExt`], for querying file-level symbols
//! from `QueryClient`.
//!
//! # Architecture (ADR0003)
//!
//! Queries go through the `FileSymbols` index to find `SymbolEntry` values,
//! then optionally follow the handle to retrieve the full `Symbol` shape from
//! the shared `Symbols` partition.
//!
//! ```text
//! query_client.file_symbol_at_path()
//!     │
//!     ├─► index_get::<FileSymbols>(sort_key) → SymbolEntry { span, handle }
//!     │
//!     └─► get::<Symbols>(handle.content_hash()) → Symbol shape
//! ```

use {
  crate::{
    core::{Ident, SymbolPath, Value, Visibility},
    partitions::{file::FileSymbols, records::SymbolEntry, symbols::Symbols},
  },
  laburnum::database::{
    HasPartition, RecordRef,
    query::QueryClient,
    storage::Partitions,
  },
};

/// Extension trait for reading file-level symbols from partitions.
///
/// Provides typed methods for querying symbols written during the file parsing
/// stage. Methods query the `FileSymbols` index and optionally follow handles
/// to the shared `Symbols` partition.
pub trait SymboliqueReadExt<P: Partitions> {
  /// Look up a file-level symbol by exact sort key.
  ///
  /// Returns the index entry if found. Use `resolve_file_symbol` to follow
  /// the handle to the full symbol shape.
  fn file_symbol_at_path<V, I, Path, S>(
    &self,
    sort_key: &Path,
  ) -> Option<SymbolEntry<V, I, Path, S>>
  where
    V: Value<I>,
    I: Ident,
    Path: SymbolPath,
    S: Visibility,
    P::Stores: HasPartition<FileSymbols<V, I, Path, S>>;

  /// Query file-level symbols with a sort key prefix.
  ///
  /// Returns all index entries whose sort key starts with `prefix`.
  fn file_symbols_with_prefix<V, I, Path, S>(
    &self,
    prefix: &Path,
  ) -> Vec<(Path, SymbolEntry<V, I, Path, S>)>
  where
    V: Value<I>,
    I: Ident,
    Path: SymbolPath,
    S: Visibility,
    P::Stores: HasPartition<FileSymbols<V, I, Path, S>>;

  /// Follow a symbol entry's handle to retrieve the full symbol shape.
  fn resolve_file_symbol<V, I, Path, S>(
    &self,
    entry: &SymbolEntry<V, I, Path, S>,
  ) -> Option<RecordRef<'_, Symbols<V, I, Path, S>>>
  where
    V: Value<I> + 'static,
    I: Ident,
    Path: SymbolPath + 'static,
    S: Visibility,
    P::Stores: HasPartition<Symbols<V, I, Path, S>>;
}

impl<P: Partitions> SymboliqueReadExt<P> for QueryClient<P> {
  fn file_symbol_at_path<V, I, Path, S>(
    &self,
    sort_key: &Path,
  ) -> Option<SymbolEntry<V, I, Path, S>>
  where
    V: Value<I>,
    I: Ident,
    Path: SymbolPath,
    S: Visibility,
    P::Stores: HasPartition<FileSymbols<V, I, Path, S>>,
  {
    self.index_get::<FileSymbols<V, I, Path, S>>(sort_key)
  }

  fn file_symbols_with_prefix<V, I, Path, S>(
    &self,
    prefix: &Path,
  ) -> Vec<(Path, SymbolEntry<V, I, Path, S>)>
  where
    V: Value<I>,
    I: Ident,
    Path: SymbolPath,
    S: Visibility,
    P::Stores: HasPartition<FileSymbols<V, I, Path, S>>,
  {
    self.index_range::<FileSymbols<V, I, Path, S>>(prefix)
  }

  fn resolve_file_symbol<V, I, Path, S>(
    &self,
    entry: &SymbolEntry<V, I, Path, S>,
  ) -> Option<RecordRef<'_, Symbols<V, I, Path, S>>>
  where
    V: Value<I> + 'static,
    I: Ident,
    Path: SymbolPath + 'static,
    S: Visibility,
    P::Stores: HasPartition<Symbols<V, I, Path, S>>,
  {
    self.get::<Symbols<V, I, Path, S>>(entry.symbol.content_hash())
  }
}
