///|
/// Identifies the input side associated with a linkage validation error.
pub(all) enum LinkageSide {
  LinkageLeft
  LinkageRight
} derive(Eq, Debug)

///|
/// Supplies one caller-defined identifier and Latin name to batch linkage.
pub(all) struct LinkRecord {
  id : String
  name : String
} derive(Eq, Debug)

///|
/// Configures blocking, scoring, result retention, and per-record work limits.
pub(all) struct LinkageConfig {
  match_config : MatchConfig
  blocking_algorithms : Array[Algorithm]
  max_candidates_per_left : Int
  minimum_score : Double
  retain_rejected : Bool
} derive(Eq, Debug)

///|
/// Retains complete matching evidence for one blocked cross-dataset pair.
pub(all) struct LinkCandidate {
  left_id : String
  right_id : String
  score : Double
  accepted : Bool
  evidence : MatchEvidence
} derive(Eq, Debug)

///|
/// Represents one accepted one-to-one record link.
pub(all) struct AcceptedLink {
  left_id : String
  right_id : String
  evidence : MatchEvidence
} derive(Eq, Debug)

///|
/// Counts each observable stage of a batch linkage run.
pub(all) struct LinkageStats {
  left_input_count : Int
  right_input_count : Int
  blocked_candidate_count : Int
  evaluated_pair_count : Int
  accepted_link_count : Int
  rejected_candidate_count : Int
  unmatched_left_count : Int
  unmatched_right_count : Int
} derive(Eq, Debug)

///|
/// Contains deterministic links, unmatched IDs, optional rejections, and counts.
pub(all) struct LinkageReport {
  links : Array[AcceptedLink]
  unmatched_left_ids : Array[String]
  unmatched_right_ids : Array[String]
  rejected_candidates : Array[LinkCandidate]
  stats : LinkageStats
  notices : Array[String]
} derive(Eq, Debug)

///|
/// Reports invalid settings, records, or a failed indexing or matching stage.
pub(all) enum LinkageError {
  InvalidLinkageMatchConfig(MatchError)
  NoLinkageBlockingAlgorithms
  DuplicateLinkageBlockingAlgorithm(Algorithm)
  InvalidLinkageCandidateLimit(Int)
  InvalidLinkageMinimumScore(Double)
  EmptyLinkageRecordId(LinkageSide)
  DuplicateLinkageRecordId(LinkageSide, String)
  LinkageIndexFailed(LinkageSide, String, IndexError)
  LinkageMatchFailed(String, String, MatchError)
} derive(Eq, Debug)