///|
pub fn redact_clinical_note(input : String) -> DeidResult raise DeidError {
  let policy = RedactionPolicy::default()
  redact_with_policy(input, policy)
}

///|
pub fn redact_strict_clinical_note(
  input : String,
) -> DeidResult raise DeidError {
  redact_with_policy(input, RedactionPolicy::strict())
}

///|
pub fn review_clinical_note(input : String) -> DeidResult raise DeidError {
  redact_with_policy(input, RedactionPolicy::review())
}

///|
pub fn redact_chinese_note(input : String) -> DeidResult raise DeidError {
  let policy = with_policy_locale(RedactionPolicy::default(), Chinese)
  redact_with_policy(input, policy, rules=chinese_rule_pack().rules)
}

///|
pub fn redact_english_note(input : String) -> DeidResult raise DeidError {
  let policy = with_policy_locale(RedactionPolicy::default(), English)
  redact_with_policy(input, policy, rules=english_rule_pack().rules)
}

///|
pub fn redact_high_precision(input : String) -> DeidResult raise DeidError {
  redact_with_policy(
    input,
    RedactionPolicy::strict(),
    rules=high_precision_rule_pack().rules,
  )
}

///|
pub fn scan_clinical_note(input : String) -> Array[Finding] raise DeidError {
  scan(input, rules=comprehensive_rules())
}

///|
pub fn scan_high_precision(input : String) -> Array[Finding] raise DeidError {
  scan(input, rules=high_precision_rule_pack().rules)
}

///|
pub fn scan_with_profile(
  input : String,
  profile : Profile,
) -> Array[Finding] raise DeidError {
  scan(input, rules=select_pack(profile).rules)
}

///|
pub fn redact_with_profile(
  input : String,
  profile : Profile,
  mode : ReplacementMode,
) -> DeidResult raise DeidError {
  profile_redaction(input, profile, mode)
}

///|
pub fn redact_texts(
  texts : Array[String],
  config : RedactionConfig,
) -> Array[String] raise DeidError {
  texts.map(text => redact_with_config(text, config).text)
}

///|
pub fn scan_texts(
  texts : Array[String],
  rules : Array[Rule],
) -> Array[Array[Finding]] raise DeidError {
  texts.map(text => scan(text, rules~))
}

///|
pub fn summarize_texts(
  texts : Array[String],
  config : RedactionConfig,
) -> Array[String] raise DeidError {
  texts.map(text => audit_summary(redact_with_config(text, config).audit))
}

///|
pub fn redact_and_audit_json(
  input : String,
  config : RedactionConfig,
) -> String raise DeidError {
  result_to_json(redact_with_config(input, config))
}

///|
pub fn redact_and_audit_markdown(
  input : String,
  config : RedactionConfig,
) -> String raise DeidError {
  let result = redact_with_config(input, config)
  audit_report_with_context(input, result.audit, config.policy.context_window)
}

///|
pub fn redact_and_audit_csv(
  input : String,
  config : RedactionConfig,
) -> String raise DeidError {
  audit_csv(redact_with_config(input, config).audit)
}

///|
pub fn preview_text(
  input : String,
  config : RedactionConfig,
) -> String raise DeidError {
  let findings = preview_redaction(input, config)
  let (text, _) = apply_findings_with_mode(input, findings, config.policy.mode)
  text
}

///|
pub fn explain_text(
  input : String,
  config : RedactionConfig,
) -> String raise DeidError {
  let result = redact_with_config(input, {
    ..config,
    policy: { ..config.policy, action: ReviewOnly },
  })
  let lines = [quality_report(input, result)]
  for finding in result.findings {
    lines.push("- \{finding.id}: \{explain_risk(finding.kind)}")
  }
  lines.join("\n")
}

///|
pub fn redact_with_protected_fields(
  input : String,
  protected_fields : Array[String],
  config : RedactionConfig,
) -> String raise DeidError {
  redact_named_fields(input, protected_fields, config)
}

///|
pub fn redact_key_value_document(
  input : String,
  config : RedactionConfig,
) -> String raise DeidError {
  redact_fields(input, config)
}

///|
pub fn redact_csv_row(
  input : String,
  config : RedactionConfig,
) -> String raise DeidError {
  redact_delimited_row(input, ',', config)
}

///|
pub fn redact_tsv_row(
  input : String,
  config : RedactionConfig,
) -> String raise DeidError {
  redact_delimited_row(input, '\t', config)
}

///|
pub fn redact_document_sections(
  input : String,
  config : RedactionConfig,
) -> String raise DeidError {
  redact_sections(input, config)
}

///|
pub fn redact_in_fixed_chunks(
  input : String,
  width : Int,
  config : RedactionConfig,
) -> String raise DeidError {
  redact_chunks(split_fixed_chunks(input, width), {
    ..ChunkPolicy::default(),
    config,
  })
}

///|
pub fn redact_in_lines(
  input : String,
  config : RedactionConfig,
) -> String raise DeidError {
  redact_lines_joined(input, config, "\n")
}

///|
pub fn result_for_mode(
  input : String,
  mode : ReplacementMode,
) -> DeidResult raise DeidError {
  redact_with_config(input, {
    ..RedactionConfig::default(),
    policy: with_policy_mode(RedactionPolicy::default(), mode),
  })
}

///|
pub fn modes_preview(input : String) -> Map[String, String] raise DeidError {
  {
    "token": result_for_mode(input, Token).text,
    "preserve-length": result_for_mode(input, PreserveLength).text,
    "partial": result_for_mode(input, Partial).text,
    "stable-hash": result_for_mode(input, StableHash).text,
  }
}

///|
pub fn safe_default_contract(input : String) -> Bool raise DeidError {
  let result = redact_clinical_note(input)
  output_contract_passes(input, result)
}

///|
pub fn package_capability_report() -> String {
  [
    "detectors=\{comprehensive_rules().length()}",
    "profiles=4",
    "replacement_modes=4",
    "formats=markdown,json,csv,plain",
    "mapping=bidirectional",
    "batch=true",
    "streaming=true",
  ].join("\n")
}