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

//! Shared test helpers for symbolique tests.

use crate::{
  DefaultValue, StringIdent, Symbol, SymbolVisibility,
  partitions::{SymbolEntry, symbols::Symbols},
};

pub type DV = DefaultValue;
pub type SI = StringIdent;
pub type TP = String;

pub fn test_span_cache() -> laburnum::SpanCache {
  laburnum::SpanCache::new(1, 0)
}

pub fn test_span(cache: &mut laburnum::SpanCache, n: usize) -> laburnum::Span {
  laburnum::Span::new(cache, n * 10, 5)
}

pub fn make_definition(
  name: &str,
  value: Option<DV>,
  visibility: SymbolVisibility,
) -> Symbol<DV, SI, TP> {
  Symbol::Definition {
    name: StringIdent::new(name),
    value,
    visibility,
  }
}

pub fn make_reference(
  self_path: &str,
  name: Option<&str>,
  target_path: &str,
  is_absolute: bool,
  nameable: bool,
) -> Symbol<DV, SI, TP> {
  Symbol::Reference {
    path: self_path.to_string(),
    name: name.map(StringIdent::new),
    target_path: target_path.to_string(),
    is_absolute,
    nameable,
  }
}

pub fn make_keyword(name: &str) -> Symbol<DV, SI, TP> {
  Symbol::Keyword {
    name: StringIdent::new(name),
  }
}

pub fn make_value(value: DV) -> Symbol<DV, SI, TP> {
  Symbol::Value { value }
}

pub fn make_scope(value: Option<DV>) -> Symbol<DV, SI, TP> {
  Symbol::Scope { value }
}

pub fn make_import(
  path: &str,
  alias: Option<&str>,
  value: Option<DV>,
) -> Symbol<DV, SI, TP> {
  Symbol::Import {
    path: path.to_string(),
    alias: alias.map(StringIdent::new),
    value,
  }
}

pub fn dummy_symbol_entry(
  cache: &mut laburnum::SpanCache,
) -> SymbolEntry<DV, SI, TP> {
  let span = test_span(cache, 0);
  let hash = laburnum::ContentHash::new(b"test_symbol_entry");
  let handle = laburnum::database::RecordHandle::<Symbols<DV, SI, TP>>::new(hash);
  SymbolEntry::new("test_symbol_entry".to_string(), span, handle)
}

/// A no-op [`SourceResolver`](laburnum::SourceResolver) for tests.
///
/// It carries no source text, so spans and source keys do not resolve; ident
/// and path rendering fall back to the `<unresolved>` placeholder. Sufficient
/// for tests that only check the shape of `description`/`report` output.
pub struct TestSourceResolver;

impl laburnum::SourceResolver for TestSourceResolver {
  fn try_resolve_span(&self, _span: &laburnum::Span) -> Option<String> {
    None
  }

  fn source_uri(
    &self,
    _source_key: laburnum::SourceKey,
  ) -> Option<laburnum::Uri> {
    None
  }
}

pub fn test_source_resolver() -> TestSourceResolver {
  TestSourceResolver
}
