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

//! File-level symbol partitions.
//!
//! Stage 1 of the symbolique pipeline. Parsing a single source file produces:
//!
//! - **FileSymbols**: Index-only partition with `SymbolEntry` index entries
//!   pointing to shapes in the shared `Symbols` partition
//!
//! This stage is parallelizable across files.

use {
  super::records::SymbolEntry,
  crate::core::{
    Ident, Symbol, SymbolPath, SymbolVisibility, Value, Visibility,
  },
  laburnum::{
    ContentHash, Ident as LaburnumIdent,
    database::{Partition, PartitionKey},
    record::{Record, hash_record},
  },
  std::{hash::Hash, marker::PhantomData},
};

/// File-level symbol index partition (index-only).
///
/// Stores only index entries that reference shapes in the shared `Symbols`
/// partition. Each entry contains a span and a handle to the symbol shape.
///
/// # Type Parameters
///
/// - `V`: Value type for literals
/// - `I`: Identifier type for names
/// - `P`: Symbol path type (used as the partition sort key)
/// - `S`: Visibility type carried by definitions
#[derive(Hash)]
pub struct FileSymbols<V, I, P, S = SymbolVisibility>(PhantomData<(V, I, P, S)>);

impl<V, I, P, S> Default for FileSymbols<V, I, P, S> {
  fn default() -> Self {
    Self(PhantomData)
  }
}

impl<V, I, P, S> Clone for FileSymbols<V, I, P, S> {
  fn clone(&self) -> Self {
    *self
  }
}

impl<V, I, P, S> Copy for FileSymbols<V, I, P, S> {}

impl<V, I, P, S> std::fmt::Debug for FileSymbols<V, I, P, S> {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.debug_struct("FileSymbols").finish()
  }
}

impl<V, I, P, S> PartitionKey for FileSymbols<V, I, P, S>
where
  V: Value<I>,
  I: Ident,
  P: SymbolPath,
  S: Visibility,
{
  const KEY: LaburnumIdent = LaburnumIdent::new("symbolique::file_symbols");
}

impl<V, I, P, S> Partition for FileSymbols<V, I, P, S>
where
  V: Value<I>,
  I: Ident,
  P: SymbolPath,
  S: Visibility,
{
  type Record = (); // Index-only
  type IndexEntry = SymbolEntry<V, I, P, S>;
  type SortKey = P;
}

/// File-level symbol index partition.
///
/// Stores path-keyed index entries that link hierarchical paths to symbol
/// shapes. The path serves as the sort key, enabling `begins_with` queries
/// for scope traversal.
#[derive(Hash)]
pub struct FileSymbolIndex<V, I, P, S = SymbolVisibility>(
  PhantomData<(V, I, P, S)>,
);

impl<V, I, P, S> Default for FileSymbolIndex<V, I, P, S> {
  fn default() -> Self {
    Self(PhantomData)
  }
}

impl<V, I, P, S> Clone for FileSymbolIndex<V, I, P, S> {
  fn clone(&self) -> Self {
    *self
  }
}

impl<V, I, P, S> Copy for FileSymbolIndex<V, I, P, S> {}

impl<V, I, P, S> std::fmt::Debug for FileSymbolIndex<V, I, P, S> {
  fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
    f.debug_struct("FileSymbolIndex").finish()
  }
}

impl<V, I, P, S> PartitionKey for FileSymbolIndex<V, I, P, S>
where
  V: Value<I>,
  I: Ident,
  P: SymbolPath,
  S: Visibility,
{
  const KEY: LaburnumIdent =
    LaburnumIdent::new("symbolique::file_symbol_index");
}

impl<V, I, P, S> Partition for FileSymbolIndex<V, I, P, S>
where
  V: Value<I>,
  I: Ident,
  P: SymbolPath,
  S: Visibility,
{
  type Record = (); // Index-only
  type IndexEntry = SymbolEntry<V, I, P, S>;
  type SortKey = P;
}

impl<V, I, P, S> Record for Symbol<V, I, P, S>
where
  V: Value<I>,
  I: Ident,
  P: SymbolPath,
  S: Visibility,
{
  fn content_hash(&self) -> ContentHash {
    hash_record(self)
  }
}
