///|
/// Intent Gate turns raw robots decisions into reviewable AI-crawler
/// acceptance evidence. It is the higher-level layer that checks why an
/// agent wants a URL, what data class is involved, and whether enough
/// authorization evidence exists before a crawl or model-training job ships.
pub(all) enum IntentPurpose {
  PurposeSearchIndex
  PurposeMonitoring
  PurposeResearch
  PurposeArchive
  PurposeAiTraining
  PurposeSecurityScan
  PurposePriceComparison
  PurposeUnknown
} derive(Eq, Debug)

///|
pub(all) enum IntentSensitivity {
  SensitivityPublic
  SensitivityAccount
  SensitivityPersonalData
  SensitivityCredential
  SensitivityAdmin
  SensitivityPaidContent
  SensitivityTrainingCorpus
} derive(Eq, Debug)

///|
pub(all) enum ConsentMode {
  ConsentNone
  ConsentRobotsOnly
  ConsentOwnerApproved
  ConsentContractual
  ConsentInternalTest
} derive(Eq, Debug)

///|
pub(all) enum IntentVerdict {
  IntentPermitted
  IntentNeedsReview
  IntentDenied
} derive(Eq, Debug)

///|
pub(all) enum IntentRiskBand {
  IntentRiskGreen
  IntentRiskYellow
  IntentRiskOrange
  IntentRiskRed
} derive(Eq, Debug)

///|
pub(all) struct CrawlIntent {
  label : String
  user_agent : String
  url_or_path : String
  purpose : IntentPurpose
  sensitivity : IntentSensitivity
  consent : ConsentMode
  expected_allowed : Bool?
  retention_days : Int
  evidence_id : String
  note : String
} derive(Eq, Debug)

///|
pub(all) struct IntentReview {
  intent : CrawlIntent
  target_result : TargetAuditResult
  verdict : IntentVerdict
  risk_band : IntentRiskBand
  risk_points : Int
  robots_allowed : Bool
  requires_human_review : Bool
  blockers : Array[String]
  obligations : Array[String]
  evidence_line : String
  tags : Array[String]
} derive(Eq, Debug)

///|
pub(all) struct IntentGateSummary {
  total_intents : Int
  permitted_intents : Int
  denied_intents : Int
  review_intents : Int
  robots_allowed : Int
  robots_blocked : Int
  high_risk_intents : Int
  missing_evidence : Int
  explicit_authorization : Int
  average_risk : Int
  score : Int
  notes : Array[String]
} derive(Eq, Debug)

///|
pub(all) struct IntentGateReport {
  policy : RobotsPolicy
  intents : Array[CrawlIntent]
  reviews : Array[IntentReview]
  summary : IntentGateSummary
  target_summary : SiteAuditSummary
} derive(Eq, Debug)

///|
pub fn IntentPurpose::label(self : IntentPurpose) -> String {
  match self {
    PurposeSearchIndex => "search-index"
    PurposeMonitoring => "monitoring"
    PurposeResearch => "research"
    PurposeArchive => "archive"
    PurposeAiTraining => "ai-training"
    PurposeSecurityScan => "security-scan"
    PurposePriceComparison => "price-comparison"
    PurposeUnknown => "unknown"
  }
}

///|
pub fn IntentSensitivity::label(self : IntentSensitivity) -> String {
  match self {
    SensitivityPublic => "public"
    SensitivityAccount => "account"
    SensitivityPersonalData => "personal-data"
    SensitivityCredential => "credential"
    SensitivityAdmin => "admin"
    SensitivityPaidContent => "paid-content"
    SensitivityTrainingCorpus => "training-corpus"
  }
}

///|
pub fn ConsentMode::label(self : ConsentMode) -> String {
  match self {
    ConsentNone => "none"
    ConsentRobotsOnly => "robots-only"
    ConsentOwnerApproved => "owner-approved"
    ConsentContractual => "contractual"
    ConsentInternalTest => "internal-test"
  }
}

///|
pub fn IntentVerdict::label(self : IntentVerdict) -> String {
  match self {
    IntentPermitted => "permitted"
    IntentNeedsReview => "needs-review"
    IntentDenied => "denied"
  }
}

///|
pub fn IntentRiskBand::label(self : IntentRiskBand) -> String {
  match self {
    IntentRiskGreen => "green"
    IntentRiskYellow => "yellow"
    IntentRiskOrange => "orange"
    IntentRiskRed => "red"
  }
}

///|
pub fn crawl_intent(
  label : StringView,
  user_agent : StringView,
  url_or_path : StringView,
  purpose : IntentPurpose,
  sensitivity : IntentSensitivity,
  consent : ConsentMode,
) -> CrawlIntent {
  {
    label: label.to_owned(),
    user_agent: user_agent.to_owned(),
    url_or_path: url_or_path.to_owned(),
    purpose,
    sensitivity,
    consent,
    expected_allowed: None,
    retention_days: 0,
    evidence_id: "",
    note: "",
  }
}

///|
pub fn CrawlIntent::with_expected(
  self : CrawlIntent,
  expected_allowed : Bool,
) -> CrawlIntent {
  {
    label: self.label,
    user_agent: self.user_agent,
    url_or_path: self.url_or_path,
    purpose: self.purpose,
    sensitivity: self.sensitivity,
    consent: self.consent,
    expected_allowed: Some(expected_allowed),
    retention_days: self.retention_days,
    evidence_id: self.evidence_id,
    note: self.note,
  }
}

///|
pub fn CrawlIntent::with_retention(
  self : CrawlIntent,
  retention_days : Int,
) -> CrawlIntent {
  {
    label: self.label,
    user_agent: self.user_agent,
    url_or_path: self.url_or_path,
    purpose: self.purpose,
    sensitivity: self.sensitivity,
    consent: self.consent,
    expected_allowed: self.expected_allowed,
    retention_days,
    evidence_id: self.evidence_id,
    note: self.note,
  }
}

///|
pub fn CrawlIntent::with_evidence(
  self : CrawlIntent,
  evidence_id : StringView,
) -> CrawlIntent {
  {
    label: self.label,
    user_agent: self.user_agent,
    url_or_path: self.url_or_path,
    purpose: self.purpose,
    sensitivity: self.sensitivity,
    consent: self.consent,
    expected_allowed: self.expected_allowed,
    retention_days: self.retention_days,
    evidence_id: evidence_id.to_owned(),
    note: self.note,
  }
}

///|
pub fn CrawlIntent::with_note(
  self : CrawlIntent,
  note : StringView,
) -> CrawlIntent {
  {
    label: self.label,
    user_agent: self.user_agent,
    url_or_path: self.url_or_path,
    purpose: self.purpose,
    sensitivity: self.sensitivity,
    consent: self.consent,
    expected_allowed: self.expected_allowed,
    retention_days: self.retention_days,
    evidence_id: self.evidence_id,
    note: note.to_owned(),
  }
}

///|
pub fn CrawlIntent::to_target(self : CrawlIntent) -> AuditTarget {
  let item = match self.expected_allowed {
    Some(expected) =>
      expected_target(
        self.label,
        self.user_agent,
        self.url_or_path,
        expected,
        self.importance(),
        self.note,
      )
    None =>
      target(self.label, self.user_agent, self.url_or_path)
      .with_importance(self.importance())
      .with_note(self.note)
  }
  item
}

///|
pub fn CrawlIntent::importance(self : CrawlIntent) -> TargetImportance {
  match self.sensitivity {
    SensitivityPublic => ImportanceNormal
    SensitivityAccount => ImportanceHigh
    SensitivityPersonalData => ImportanceCritical
    SensitivityCredential => ImportanceCritical
    SensitivityAdmin => ImportanceCritical
    SensitivityPaidContent => ImportanceHigh
    SensitivityTrainingCorpus => ImportanceHigh
  }
}

///|
pub fn CrawlIntent::has_evidence(self : CrawlIntent) -> Bool {
  !self.evidence_id.trim().is_empty()
}

///|
pub fn CrawlIntent::needs_explicit_authorization(self : CrawlIntent) -> Bool {
  self.purpose == PurposeAiTraining ||
  self.purpose == PurposePriceComparison ||
  self.sensitivity == SensitivityPersonalData ||
  self.sensitivity == SensitivityCredential ||
  self.sensitivity == SensitivityAdmin ||
  self.sensitivity == SensitivityPaidContent ||
  self.sensitivity == SensitivityTrainingCorpus
}

///|
pub fn CrawlIntent::has_explicit_authorization(self : CrawlIntent) -> Bool {
  self.consent == ConsentOwnerApproved ||
  self.consent == ConsentContractual ||
  self.consent == ConsentInternalTest
}

///|
pub fn CrawlIntent::purpose_summary(self : CrawlIntent) -> String {
  self.purpose.label() +
  "/" +
  self.sensitivity.label() +
  "/" +
  self.consent.label()
}

///|
pub fn review_intent(
  policy : RobotsPolicy,
  intent : CrawlIntent,
) -> IntentReview {
  let result = audit_target(policy, intent.to_target())
  let blockers = intent_blockers(intent, result)
  let obligations = intent_obligations(intent, result)
  let risk_points = intent_risk_points(intent, result, blockers, obligations)
  let risk_band = classify_intent_risk(risk_points)
  let verdict = classify_intent_verdict(intent, result, blockers, risk_points)
  let requires_human_review = verdict == IntentNeedsReview
  let evidence_line = intent_evidence_line(intent, result, verdict, risk_points)
  {
    intent,
    target_result: result,
    verdict,
    risk_band,
    risk_points,
    robots_allowed: result.decision.allowed,
    requires_human_review,
    blockers,
    obligations,
    evidence_line,
    tags: intent_tags(intent, result, verdict, risk_band),
  }
}

///|
pub fn review_intents(
  policy : RobotsPolicy,
  intents : Array[CrawlIntent],
) -> IntentGateReport {
  let reviews : Array[IntentReview] = []
  let targets : Array[AuditTarget] = []
  for intent in intents {
    targets.push(intent.to_target())
    reviews.push(review_intent(policy, intent))
  }
  let target_report = audit_targets(policy, targets)
  {
    policy,
    intents,
    reviews,
    summary: summarize_intent_reviews(reviews),
    target_summary: target_report.summary,
  }
}

///|
pub fn RobotsPolicy::review_intents(
  self : RobotsPolicy,
  intents : Array[CrawlIntent],
) -> IntentGateReport {
  review_intents(self, intents)
}

///|
pub fn summarize_intent_reviews(
  reviews : Array[IntentReview],
) -> IntentGateSummary {
  let notes : Array[String] = []
  let mut total_intents = 0
  let mut permitted_intents = 0
  let mut denied_intents = 0
  let mut review_intents = 0
  let mut robots_allowed = 0
  let mut robots_blocked = 0
  let mut high_risk_intents = 0
  let mut missing_evidence = 0
  let mut explicit_authorization = 0
  let mut risk_sum = 0
  for review in reviews {
    total_intents = total_intents + 1
    risk_sum = risk_sum + review.risk_points
    match review.verdict {
      IntentPermitted => permitted_intents = permitted_intents + 1
      IntentNeedsReview => review_intents = review_intents + 1
      IntentDenied => denied_intents = denied_intents + 1
    }
    if review.robots_allowed {
      robots_allowed = robots_allowed + 1
    } else {
      robots_blocked = robots_blocked + 1
    }
    if review.risk_band == IntentRiskOrange || review.risk_band == IntentRiskRed {
      high_risk_intents = high_risk_intents + 1
    }
    if !review.intent.has_evidence() {
      missing_evidence = missing_evidence + 1
    }
    if review.intent.has_explicit_authorization() {
      explicit_authorization = explicit_authorization + 1
    }
  }
  let average_risk = if total_intents == 0 {
    0
  } else {
    risk_sum / total_intents
  }
  let score = intent_gate_score(
    total_intents, denied_intents, review_intents, high_risk_intents, missing_evidence,
  )
  if total_intents == 0 {
    notes.push("no AI crawler intent was provided")
  }
  if denied_intents > 0 {
    notes.push(
      "some intents are denied by robots policy or authorization rules",
    )
  }
  if review_intents > 0 {
    notes.push("some intents require human review before release")
  }
  if missing_evidence > 0 {
    notes.push("some intents lack a reusable evidence id")
  }
  if explicit_authorization == 0 && total_intents > 0 {
    notes.push(
      "no intent records explicit owner approval or contractual consent",
    )
  }
  {
    total_intents,
    permitted_intents,
    denied_intents,
    review_intents,
    robots_allowed,
    robots_blocked,
    high_risk_intents,
    missing_evidence,
    explicit_authorization,
    average_risk,
    score,
    notes,
  }
}

///|
pub fn IntentGateSummary::pass_rate_percent(self : IntentGateSummary) -> Int {
  if self.total_intents == 0 {
    0
  } else {
    self.permitted_intents * 100 / self.total_intents
  }
}

///|
pub fn IntentGateSummary::is_release_ready(self : IntentGateSummary) -> Bool {
  self.denied_intents == 0 &&
  self.review_intents == 0 &&
  self.missing_evidence == 0
}

///|
pub fn IntentGateSummary::to_line(self : IntentGateSummary) -> String {
  "intents=" +
  self.total_intents.to_string() +
  " permitted=" +
  self.permitted_intents.to_string() +
  " review=" +
  self.review_intents.to_string() +
  " denied=" +
  self.denied_intents.to_string() +
  " score=" +
  self.score.to_string()
}

///|
pub fn IntentGateSummary::to_markdown(self : IntentGateSummary) -> String {
  let lines : Array[String] = []
  lines.push("## Intent Gate Summary")
  lines.push("")
  lines.push("- Total intents: " + self.total_intents.to_string())
  lines.push("- Permitted intents: " + self.permitted_intents.to_string())
  lines.push("- Needs review: " + self.review_intents.to_string())
  lines.push("- Denied intents: " + self.denied_intents.to_string())
  lines.push("- Robots allowed: " + self.robots_allowed.to_string())
  lines.push("- Robots blocked: " + self.robots_blocked.to_string())
  lines.push("- High risk intents: " + self.high_risk_intents.to_string())
  lines.push("- Missing evidence: " + self.missing_evidence.to_string())
  lines.push(
    "- Explicit authorization: " + self.explicit_authorization.to_string(),
  )
  lines.push("- Average risk: " + self.average_risk.to_string())
  lines.push("- Pass rate: " + self.pass_rate_percent().to_string() + "%")
  lines.push("- Score: " + self.score.to_string())
  if self.notes.is_empty() {
    lines.push("- Notes: none")
  } else {
    lines.push("- Notes: " + self.notes.join("; "))
  }
  lines.join("\n")
}

///|
pub fn IntentReview::to_markdown_row(self : IntentReview) -> String {
  "| " +
  intent_cell(self.intent.label) +
  " | " +
  intent_cell(self.intent.user_agent) +
  " | " +
  intent_cell(self.target_result.snapshot.normalized) +
  " | " +
  self.intent.purpose.label() +
  " | " +
  self.intent.sensitivity.label() +
  " | " +
  self.intent.consent.label() +
  " | " +
  (if self.robots_allowed { "allow" } else { "block" }) +
  " | " +
  self.verdict.label() +
  " | " +
  self.risk_band.label() +
  " | " +
  self.risk_points.to_string() +
  " | " +
  intent_cell(self.intent.evidence_id) +
  " |"
}

///|
pub fn IntentReview::to_line(self : IntentReview) -> String {
  self.verdict.label().to_upper() +
  " " +
  self.intent.label +
  " " +
  self.target_result.snapshot.normalized +
  " risk=" +
  self.risk_points.to_string() +
  " evidence=" +
  evidence_label(self.intent)
}

///|
pub fn IntentReview::has_blocker(
  self : IntentReview,
  blocker : StringView,
) -> Bool {
  let expected = blocker.to_owned()
  self.blockers.contains(expected)
}

///|
pub fn IntentGateReport::to_markdown(self : IntentGateReport) -> String {
  let lines : Array[String] = []
  lines.push("# RoboPolicy Intent Gate")
  lines.push("")
  lines.push(self.summary.to_markdown())
  lines.push("")
  lines.push("## Intent Reviews")
  lines.push("")
  lines.push(
    "| Label | Agent | Path | Purpose | Sensitivity | Consent | Robots | Verdict | Risk Band | Risk | Evidence |",
  )
  lines.push(
    "| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |",
  )
  for review in self.reviews {
    lines.push(review.to_markdown_row())
  }
  lines.push("")
  lines.push("## Evidence Lines")
  lines.push("")
  for review in self.reviews {
    lines.push("- " + review.evidence_line)
  }
  lines.join("\n")
}

///|
pub fn IntentGateReport::to_csv(self : IntentGateReport) -> String {
  let lines : Array[String] = []
  lines.push(
    "label,user_agent,path,purpose,sensitivity,consent,robots,verdict,risk_band,risk,evidence",
  )
  for review in self.reviews {
    lines.push(review.to_csv_row())
  }
  lines.join("\n")
}

///|
pub fn IntentReview::to_csv_row(self : IntentReview) -> String {
  intent_csv_cell(self.intent.label) +
  "," +
  intent_csv_cell(self.intent.user_agent) +
  "," +
  intent_csv_cell(self.target_result.snapshot.normalized) +
  "," +
  intent_csv_cell(self.intent.purpose.label()) +
  "," +
  intent_csv_cell(self.intent.sensitivity.label()) +
  "," +
  intent_csv_cell(self.intent.consent.label()) +
  "," +
  intent_csv_cell(if self.robots_allowed { "allow" } else { "block" }) +
  "," +
  intent_csv_cell(self.verdict.label()) +
  "," +
  intent_csv_cell(self.risk_band.label()) +
  "," +
  intent_csv_cell(self.risk_points.to_string()) +
  "," +
  intent_csv_cell(self.intent.evidence_id)
}

///|
pub fn IntentGateReport::to_json(self : IntentGateReport) -> String {
  let rows : Array[String] = []
  for review in self.reviews {
    rows.push(review.to_json())
  }
  "{" +
  "\"summary\":" +
  self.summary.to_json() +
  ",\"reviews\":[" +
  rows.join(",") +
  "]}"
}

///|
pub fn IntentGateSummary::to_json(self : IntentGateSummary) -> String {
  "{" +
  "\"total_intents\":" +
  self.total_intents.to_string() +
  ",\"permitted_intents\":" +
  self.permitted_intents.to_string() +
  ",\"review_intents\":" +
  self.review_intents.to_string() +
  ",\"denied_intents\":" +
  self.denied_intents.to_string() +
  ",\"robots_allowed\":" +
  self.robots_allowed.to_string() +
  ",\"robots_blocked\":" +
  self.robots_blocked.to_string() +
  ",\"high_risk_intents\":" +
  self.high_risk_intents.to_string() +
  ",\"missing_evidence\":" +
  self.missing_evidence.to_string() +
  ",\"explicit_authorization\":" +
  self.explicit_authorization.to_string() +
  ",\"average_risk\":" +
  self.average_risk.to_string() +
  ",\"score\":" +
  self.score.to_string() +
  "}"
}

///|
pub fn IntentReview::to_json(self : IntentReview) -> String {
  "{" +
  "\"label\":\"" +
  intent_json_escape(self.intent.label) +
  "\",\"user_agent\":\"" +
  intent_json_escape(self.intent.user_agent) +
  "\",\"path\":\"" +
  intent_json_escape(self.target_result.snapshot.normalized) +
  "\",\"purpose\":\"" +
  self.intent.purpose.label() +
  "\",\"sensitivity\":\"" +
  self.intent.sensitivity.label() +
  "\",\"consent\":\"" +
  self.intent.consent.label() +
  "\",\"robots_allowed\":" +
  self.robots_allowed.to_string() +
  ",\"verdict\":\"" +
  self.verdict.label() +
  "\",\"risk_band\":\"" +
  self.risk_band.label() +
  "\",\"risk_points\":" +
  self.risk_points.to_string() +
  ",\"evidence\":\"" +
  intent_json_escape(self.intent.evidence_id) +
  "\"}"
}

///|
pub fn safe_public_ai_intent(
  label : StringView,
  user_agent : StringView,
  url_or_path : StringView,
  evidence_id : StringView,
) -> CrawlIntent {
  crawl_intent(
    label,
    user_agent,
    url_or_path,
    PurposeMonitoring,
    SensitivityPublic,
    ConsentOwnerApproved,
  )
  .with_expected(true)
  .with_retention(7)
  .with_evidence(evidence_id)
}

///|
pub fn training_intent(
  label : StringView,
  user_agent : StringView,
  url_or_path : StringView,
  consent : ConsentMode,
  evidence_id : StringView,
) -> CrawlIntent {
  crawl_intent(
    label,
    user_agent,
    url_or_path,
    PurposeAiTraining,
    SensitivityTrainingCorpus,
    consent,
  )
  .with_expected(true)
  .with_retention(30)
  .with_evidence(evidence_id)
}

///|
pub fn blocked_private_intent(
  label : StringView,
  user_agent : StringView,
  url_or_path : StringView,
) -> CrawlIntent {
  crawl_intent(
    label,
    user_agent,
    url_or_path,
    PurposeResearch,
    SensitivityPersonalData,
    ConsentNone,
  )
  .with_expected(false)
  .with_retention(0)
}

///|
pub fn sample_intents() -> Array[CrawlIntent] {
  [
    safe_public_ai_intent(
      "public-docs-monitor", "ResearchBot", "/private/summary.html", "owner-ticket-42",
    ),
    training_intent(
      "training-corpus-review",
      "ResearchBot",
      "/private/summary.html",
      ConsentRobotsOnly,
      "dataset-plan-7",
    ),
    blocked_private_intent(
      "private-json-training", "ResearchBot", "/private/data.json",
    ),
  ]
}

///|
pub fn sample_intent_gate_markdown() -> String {
  review_intents(parse(sample_robots()), sample_intents()).to_markdown()
}

///|
fn intent_blockers(
  intent : CrawlIntent,
  result : TargetAuditResult,
) -> Array[String] {
  let blockers : Array[String] = []
  if !result.decision.allowed {
    blockers.push("robots.txt blocks this path")
  }
  if intent.needs_explicit_authorization() &&
    !intent.has_explicit_authorization() {
    blockers.push("explicit authorization is required for this intent")
  }
  if intent.sensitivity == SensitivityCredential ||
    intent.sensitivity == SensitivityAdmin {
    if intent.consent != ConsentInternalTest &&
      intent.consent != ConsentOwnerApproved {
      blockers.push("credential or admin surfaces require owner approval")
    }
  }
  if intent.retention_days > 90 && intent.consent != ConsentContractual {
    blockers.push("long retention requires contractual consent")
  }
  blockers
}

///|
fn intent_obligations(
  intent : CrawlIntent,
  result : TargetAuditResult,
) -> Array[String] {
  let obligations : Array[String] = []
  obligations.push("record normalized path " + result.snapshot.normalized)
  if intent.has_evidence() {
    obligations.push("attach evidence " + intent.evidence_id)
  } else {
    obligations.push("add reviewer-visible evidence id")
  }
  if intent.consent == ConsentOwnerApproved ||
    intent.consent == ConsentContractual {
    obligations.push("keep authorization proof with release notes")
  }
  if intent.purpose == PurposeAiTraining {
    obligations.push("document dataset purpose and exclusion scope")
  }
  if intent.retention_days > 0 {
    obligations.push(
      "enforce retention " + intent.retention_days.to_string() + " days",
    )
  }
  if result.snapshot.had_query || result.snapshot.had_fragment {
    obligations.push("review query and fragment stripping before fetch")
  }
  obligations
}

///|
fn intent_risk_points(
  intent : CrawlIntent,
  result : TargetAuditResult,
  blockers : Array[String],
  obligations : Array[String],
) -> Int {
  let mut risk = result.risk_points
  risk = risk + intent_purpose_risk(intent.purpose)
  risk = risk + intent_sensitivity_risk(intent.sensitivity)
  risk = risk + intent_consent_risk(intent.consent)
  risk = risk + blockers.length() * 6
  risk = risk + obligations.length() / 3
  if !intent.has_evidence() {
    risk = risk + 4
  }
  if intent.retention_days > 30 {
    risk = risk + 2
  }
  if intent.retention_days > 90 {
    risk = risk + 4
  }
  if result.snapshot.had_query || result.snapshot.had_fragment {
    risk = risk + 1
  }
  risk
}

///|
fn intent_purpose_risk(purpose : IntentPurpose) -> Int {
  match purpose {
    PurposeSearchIndex => 1
    PurposeMonitoring => 1
    PurposeResearch => 2
    PurposeArchive => 2
    PurposeAiTraining => 5
    PurposeSecurityScan => 4
    PurposePriceComparison => 4
    PurposeUnknown => 6
  }
}

///|
fn intent_sensitivity_risk(sensitivity : IntentSensitivity) -> Int {
  match sensitivity {
    SensitivityPublic => 0
    SensitivityAccount => 4
    SensitivityPersonalData => 7
    SensitivityCredential => 9
    SensitivityAdmin => 8
    SensitivityPaidContent => 5
    SensitivityTrainingCorpus => 5
  }
}

///|
fn intent_consent_risk(consent : ConsentMode) -> Int {
  match consent {
    ConsentNone => 6
    ConsentRobotsOnly => 3
    ConsentOwnerApproved => 0
    ConsentContractual => 0
    ConsentInternalTest => 1
  }
}

///|
fn classify_intent_risk(risk : Int) -> IntentRiskBand {
  if risk >= 24 {
    IntentRiskRed
  } else if risk >= 14 {
    IntentRiskOrange
  } else if risk >= 7 {
    IntentRiskYellow
  } else {
    IntentRiskGreen
  }
}

///|
fn classify_intent_verdict(
  intent : CrawlIntent,
  result : TargetAuditResult,
  blockers : Array[String],
  risk_points : Int,
) -> IntentVerdict {
  if !result.decision.allowed || blockers.length() >= 2 {
    IntentDenied
  } else if !intent.has_evidence() ||
    !blockers.is_empty() ||
    risk_points >= 14 ||
    result.expectation_status == ExpectationMismatch {
    IntentNeedsReview
  } else {
    IntentPermitted
  }
}

///|
fn intent_tags(
  intent : CrawlIntent,
  result : TargetAuditResult,
  verdict : IntentVerdict,
  risk_band : IntentRiskBand,
) -> Array[String] {
  let tags : Array[String] = []
  tags.push(intent.purpose.label())
  tags.push(intent.sensitivity.label())
  tags.push(intent.consent.label())
  tags.push(verdict.label())
  tags.push(risk_band.label())
  if result.decision.allowed {
    tags.push("robots-allow")
  } else {
    tags.push("robots-block")
  }
  if intent.has_evidence() {
    tags.push("has-evidence")
  } else {
    tags.push("missing-evidence")
  }
  if intent.needs_explicit_authorization() {
    tags.push("explicit-auth-required")
  }
  tags
}

///|
fn intent_evidence_line(
  intent : CrawlIntent,
  result : TargetAuditResult,
  verdict : IntentVerdict,
  risk_points : Int,
) -> String {
  intent.label +
  " => " +
  verdict.label() +
  "; purpose=" +
  intent.purpose.label() +
  "; sensitivity=" +
  intent.sensitivity.label() +
  "; consent=" +
  intent.consent.label() +
  "; robots=" +
  (if result.decision.allowed { "allow" } else { "block" }) +
  "; path=" +
  result.snapshot.normalized +
  "; risk=" +
  risk_points.to_string() +
  "; evidence=" +
  evidence_label(intent)
}

///|
fn evidence_label(intent : CrawlIntent) -> String {
  if intent.has_evidence() {
    intent.evidence_id
  } else {
    "missing"
  }
}

///|
fn intent_gate_score(
  total_intents : Int,
  denied_intents : Int,
  review_intents : Int,
  high_risk_intents : Int,
  missing_evidence : Int,
) -> Int {
  if total_intents == 0 {
    0
  } else {
    intent_clamp_score(
      100 -
      denied_intents * 24 -
      review_intents * 12 -
      high_risk_intents * 8 -
      missing_evidence * 5,
    )
  }
}

///|
fn intent_clamp_score(score : Int) -> Int {
  if score < 0 {
    0
  } else if score > 100 {
    100
  } else {
    score
  }
}

///|
fn intent_cell(value : String) -> String {
  value.replace_all(old="|", new="\\|")
}

///|
fn intent_csv_cell(value : String) -> String {
  "\"" + value.replace_all(old="\"", new="\"\"") + "\""
}

///|
fn intent_json_escape(value : String) -> String {
  value
  .replace_all(old="\\", new="\\\\")
  .replace_all(old="\"", new="\\\"")
  .replace_all(old="\n", new="\\n")
}