#!/usr/bin/env bash
set -Eeuo pipefail

ACTION="${1:-setup}"
LAB_ROOT="${2:-/tmp/soria-glpi-automation-${USER:-student}}"
MARKER_NAME=".soria-glpi-automation-reporting"

fail() { printf 'ERROR: %s\n' "$*" >&2; exit 1; }

resolve_safe_root() {
  case "$LAB_ROOT" in
    /tmp/soria-glpi-*|"${HOME}"/soria-glpi-*) ;;
    *) fail "refused lab root: $LAB_ROOT" ;;
  esac
  [ "$LAB_ROOT" != "/tmp" ] || fail "refused root: /tmp"
  [ "$LAB_ROOT" != "$HOME" ] || fail "refused root: $HOME"
}

require_marker() { [ -f "$LAB_ROOT/$MARKER_NAME" ] || fail "missing marker: $LAB_ROOT/$MARKER_NAME"; }
csv_rows() { awk 'END { print (NR > 0 ? NR - 1 : 0) }' "$1"; }

assert_unique_column() {
  local file="$1" col="$2" label="$3"
  awk -F',' -v col="$col" -v label="$label" '
    NR == 1 { next }
    $col == "" { printf "empty %s at line %d\n", label, NR > "/dev/stderr"; exit 1 }
    seen[$col]++ { printf "duplicate %s: %s\n", label, $col > "/dev/stderr"; exit 1 }
  ' "$file" || fail "$label uniqueness validation failed"
}

setup_lab() {
  if [ -e "$LAB_ROOT" ]; then
    require_marker
    rm -rf "$LAB_ROOT/refs" "$LAB_ROOT/input" "$LAB_ROOT/policy" "$LAB_ROOT/output" "$LAB_ROOT/evidence"
  else
    mkdir -p "$LAB_ROOT"
    : > "$LAB_ROOT/$MARKER_NAME"
  fi

  mkdir -p "$LAB_ROOT/refs" "$LAB_ROOT/input" "$LAB_ROOT/policy" "$LAB_ROOT/output" "$LAB_ROOT/evidence"

  cat > "$LAB_ROOT/refs/entities.csv" <<'CSV'
entity_code,name
ORLEANS,Siège Orléans
TOURS,Agence Tours
LAB,Laboratoire
CSV

  cat > "$LAB_ROOT/refs/groups.csv" <<'CSV'
group_code,name
SUPPORT_N1,Support N1
INFRA,Infrastructure
APPROVERS,Approbateurs
PROCUREMENT,Achats
CSV

  cat > "$LAB_ROOT/refs/categories.csv" <<'CSV'
category_code,name,default_group
INCIDENT_NETWORK,Réseau et connectivité,INFRA
INCIDENT_WORKSTATION,Poste de travail,SUPPORT_N1
REQUEST_ACCESS,Accès et habilitation,SUPPORT_N1
REQUEST_SOFTWARE,Logiciel,SUPPORT_N1
CSV

  cat > "$LAB_ROOT/policy/business-rules.csv" <<'CSV'
order,rule_code,enabled,match_field,operator,match_value,set_category,set_group,set_priority,stop_processing
10,RULE_NET_SUBJECT,yes,subject,contains,vpn,INCIDENT_NETWORK,INFRA,P3,yes
20,RULE_ACCESS_DOMAIN,yes,sender_domain,equals,soria.example,REQUEST_ACCESS,SUPPORT_N1,P4,yes
30,RULE_SOFTWARE_SUBJECT,yes,subject,contains,logiciel,REQUEST_SOFTWARE,SUPPORT_N1,P4,yes
90,RULE_FALLBACK,yes,subject,contains,,INCIDENT_WORKSTATION,SUPPORT_N1,P4,yes
CSV

  cat > "$LAB_ROOT/input/rule-tests.csv" <<'CSV'
test_id,subject,sender_domain,expected_rule,expected_category,expected_group,expected_priority
TEST-001,Vpn indisponible,soria.example,RULE_NET_SUBJECT,INCIDENT_NETWORK,INFRA,P3
TEST-002,Demande accès nouvel arrivant,soria.example,RULE_ACCESS_DOMAIN,REQUEST_ACCESS,SUPPORT_N1,P4
TEST-003,Installation logiciel CAO,partner.example,RULE_SOFTWARE_SUBJECT,REQUEST_SOFTWARE,SUPPORT_N1,P4
TEST-004,Clavier défectueux,partner.example,RULE_FALLBACK,INCIDENT_WORKSTATION,SUPPORT_N1,P4
CSV

  cat > "$LAB_ROOT/policy/collectors.csv" <<'CSV'
collector_code,mailbox,entity_code,collect_unread_only,auto_create_user,enabled
COL_ORL,support-orleans@soria.example,ORLEANS,yes,no,yes
COL_TOU,support-tours@soria.example,TOURS,yes,no,yes
CSV

  cat > "$LAB_ROOT/policy/collector-rules.csv" <<'CSV'
order,rule_code,collector_code,sender_domain,action,entity_code
10,MAIL_REJECT_AUTOREPLY,*,*,REJECT_AUTOREPLY,
20,MAIL_ORL_DOMAIN,COL_ORL,soria.example,CREATE_TICKET,ORLEANS
30,MAIL_TOU_DOMAIN,COL_TOU,soria.example,CREATE_TICKET,TOURS
90,MAIL_REJECT_UNKNOWN,*,*,REJECT_UNKNOWN_DOMAIN,
CSV

  cat > "$LAB_ROOT/input/incoming-mails.csv" <<'CSV'
mail_id,collector_code,from_address,sender_domain,subject,auto_submitted,in_reply_to,expected_action,expected_entity
MAIL-001,COL_ORL,alice@soria.example,soria.example,Vpn indisponible,no,,CREATE_TICKET,ORLEANS
MAIL-002,COL_TOU,bob@soria.example,soria.example,Imprimante agence,no,,CREATE_TICKET,TOURS
MAIL-003,COL_ORL,noreply@vendor.example,vendor.example,Automatic response,yes,,REJECT_AUTOREPLY,
MAIL-004,COL_ORL,spam@external.example,external.example,Offre commerciale,no,,REJECT_UNKNOWN_DOMAIN,
MAIL-005,COL_ORL,alice@soria.example,soria.example,Re Vpn indisponible,no,TCK-001,ADD_FOLLOWUP,ORLEANS
CSV

  cat > "$LAB_ROOT/policy/notifications.csv" <<'CSV'
notification_code,event,enabled,template,recipient_role,queue_delay_minutes
NOTIF_NEW_TICKET,new_ticket,yes,ticket-created,assigned_group,0
NOTIF_FOLLOWUP,new_followup,yes,ticket-followup,requester,15
NOTIF_APPROVAL,new_approval,yes,approval-request,approver,10
NOTIF_CONTRACT,contract_expiry,yes,contract-expiry,procurement,0
CSV

  cat > "$LAB_ROOT/input/notification-events.csv" <<'CSV'
event_id,notification_code,object_id,recipient,created_minute,expected_send_minute
EVT-001,NOTIF_NEW_TICKET,TCK-001,infra@soria.example,100,100
EVT-002,NOTIF_FOLLOWUP,TCK-002,alice@soria.example,110,125
EVT-003,NOTIF_APPROVAL,TCK-003,manager@soria.example,120,130
EVT-004,NOTIF_CONTRACT,CTR-001,procurement@soria.example,130,130
CSV

  cat > "$LAB_ROOT/policy/automatic-actions.csv" <<'CSV'
action_code,mode,enabled,frequency_minutes,last_start_minute,last_end_minute,status,retention_days,max_batch
mailgate,CLI,yes,5,180,181,idle,30,20
queuedmail,CLI,yes,5,182,183,idle,30,50
queuemailclean,CLI,yes,1440,0,1,idle,30,100
contract,CLI,yes,1440,0,1,idle,90,100
watcher,CLI,yes,60,120,,running,30,10
CSV

  cat > "$LAB_ROOT/input/queue.csv" <<'CSV'
queue_id,kind,object_id,created_minute,due_minute,status,retry_count
Q-001,notification,TCK-002,110,125,pending,0
Q-002,notification,TCK-003,120,130,sent,0
Q-003,mail-import,MAIL-003,170,170,rejected,1
Q-004,mail-import,MAIL-004,171,171,rejected,1
Q-005,notification,TCK-099,100,105,pending,3
CSV

  cat > "$LAB_ROOT/refs/suppliers.csv" <<'CSV'
supplier_code,name,active
SUP-DELL,Dell France,yes
SUP-MSP,NetOps Services,yes
SUP-M365,Microsoft,yes
CSV

  cat > "$LAB_ROOT/refs/budgets.csv" <<'CSV'
budget_code,name,start_date,end_date,amount_eur
BUD-HW-2026,Matériel 2026,2026-01-01,2026-12-31,40000
BUD-SVC-2026,Services 2026,2026-01-01,2026-12-31,25000
BUD-SW-2026,Logiciels 2026,2026-01-01,2026-12-31,30000
CSV

  cat > "$LAB_ROOT/input/contracts.csv" <<'CSV'
contract_code,name,supplier_code,budget_code,start_date,end_date,annual_cost_eur,renewal_notice_days,status
CTR-001,Support réseau,SUP-MSP,BUD-SVC-2026,2026-01-01,2026-09-15,12000,60,active
CTR-002,Maintenance postes,SUP-DELL,BUD-HW-2026,2026-01-01,2027-01-31,8000,45,active
CTR-003,Microsoft 365,SUP-M365,BUD-SW-2026,2026-01-01,2026-12-31,18000,90,active
CSV

  cat > "$LAB_ROOT/input/licenses.csv" <<'CSV'
license_code,name,supplier_code,budget_code,seats_owned,seats_assigned,end_date,annual_cost_eur
LIC-M365,Microsoft 365 Business Premium,SUP-M365,BUD-SW-2026,60,54,2026-12-31,18000
LIC-CAD,CAO Pro,SUP-MSP,BUD-SW-2026,10,12,2026-10-15,9000
LIC-BACKUP,Backup Server,SUP-MSP,BUD-SVC-2026,5,4,2027-03-31,4000
CSV

  cat > "$LAB_ROOT/input/ticket-metrics.csv" <<'CSV'
ticket_id,entity_code,category_code,created_minute,assigned_minute,resolved_minute,priority,reopened,satisfaction
TCK-001,ORLEANS,INCIDENT_NETWORK,0,5,45,P3,no,5
TCK-002,ORLEANS,INCIDENT_WORKSTATION,10,20,120,P4,no,4
TCK-003,TOURS,REQUEST_ACCESS,20,40,180,P4,no,5
TCK-004,ORLEANS,INCIDENT_NETWORK,30,35,300,P2,yes,2
TCK-005,TOURS,REQUEST_SOFTWARE,40,70,200,P4,no,4
TCK-006,ORLEANS,INCIDENT_WORKSTATION,50,80,250,P4,no,3
CSV

  cat > "$LAB_ROOT/policy/dashboard-kpis.csv" <<'CSV'
kpi_code,name,definition,target
KPI_VOLUME,Tickets traités,count tickets,6
KPI_TTA,Temps moyen assignation,average assigned-created <= 30,30
KPI_TTR,Temps moyen résolution,average resolved-created <= 180,180
KPI_REOPEN,Taux de réouverture,reopened/count <= 10%,10
KPI_SAT,Satisfaction moyenne,average satisfaction >= 4,4
KPI_BUDGET,Taux budget engagé,committed/total <= 90%,90
CSV

  (
    cd "$LAB_ROOT"
    sha256sum refs/*.csv policy/*.csv input/*.csv > evidence/source-checksums-before.sha256
  )

  cat > "$LAB_ROOT/README.txt" <<'TXT'
Commands:
  setup     create the offline automation and reporting dossier
  status    show fixture counts and current outputs
  run       evaluate rules, collectors, notifications, queues, contracts, licenses and KPIs
  validate  verify expected decisions and source immutability
  reset     delete this marker-protected lab root
TXT

  printf 'GLPI automation and reporting laboratory ready: %s\n' "$LAB_ROOT"
}

show_status() {
  require_marker
  printf 'Business rule tests: %s\n' "$(csv_rows "$LAB_ROOT/input/rule-tests.csv")"
  printf 'Incoming mails: %s\n' "$(csv_rows "$LAB_ROOT/input/incoming-mails.csv")"
  printf 'Automatic actions: %s\n' "$(csv_rows "$LAB_ROOT/policy/automatic-actions.csv")"
  printf 'Contracts: %s\n' "$(csv_rows "$LAB_ROOT/input/contracts.csv")"
  printf 'Licenses: %s\n' "$(csv_rows "$LAB_ROOT/input/licenses.csv")"
  printf 'Ticket metrics: %s\n' "$(csv_rows "$LAB_ROOT/input/ticket-metrics.csv")"
}

run_reference() {
  require_marker
  mkdir -p "$LAB_ROOT/output" "$LAB_ROOT/evidence"

  assert_unique_column "$LAB_ROOT/policy/business-rules.csv" 2 "business rule code"
  assert_unique_column "$LAB_ROOT/input/rule-tests.csv" 1 "rule test id"
  assert_unique_column "$LAB_ROOT/policy/collectors.csv" 1 "collector code"
  assert_unique_column "$LAB_ROOT/policy/notifications.csv" 1 "notification code"
  assert_unique_column "$LAB_ROOT/policy/automatic-actions.csv" 1 "automatic action code"
  assert_unique_column "$LAB_ROOT/refs/suppliers.csv" 1 "supplier code"
  assert_unique_column "$LAB_ROOT/refs/budgets.csv" 1 "budget code"
  assert_unique_column "$LAB_ROOT/input/contracts.csv" 1 "contract code"
  assert_unique_column "$LAB_ROOT/input/licenses.csv" 1 "license code"

  awk -F',' -v OFS=',' -v rules="$LAB_ROOT/policy/business-rules.csv" -v out="$LAB_ROOT/output/rule-test-results.csv" '
    function load_rules(file, line, n) {
      while ((getline line < file) > 0) {
        if (++n == 1) continue
        split(line, f, ",")
        idx[++count] = f[1]
        code[f[1]] = f[2]; enabled[f[1]] = f[3]; field[f[1]] = f[4]
        operator[f[1]] = f[5]; value[f[1]] = tolower(f[6]); category[f[1]] = f[7]
        group[f[1]] = f[8]; priority[f[1]] = f[9]; stop[f[1]] = f[10]
      }
      close(file)
    }
    function matches(ord, subject, domain, candidate) {
      candidate = (field[ord] == "subject" ? tolower(subject) : tolower(domain))
      if (operator[ord] == "equals") return candidate == value[ord]
      if (operator[ord] == "contains") return index(candidate, value[ord]) > 0 || value[ord] == ""
      return 0
    }
    BEGIN { load_rules(rules); print "test_id,matched_rule,category,group,priority,result" > out }
    NR == 1 { next }
    {
      matched = ""; got_category = ""; got_group = ""; got_priority = ""
      for (i = 1; i <= count; i++) {
        ord = idx[i]
        if (enabled[ord] == "yes" && matches(ord, $2, $3)) {
          matched = code[ord]; got_category = category[ord]; got_group = group[ord]; got_priority = priority[ord]
          if (stop[ord] == "yes") break
        }
      }
      result = (matched == $4 && got_category == $5 && got_group == $6 && got_priority == $7 ? "PASS" : "FAIL")
      print $1, matched, got_category, got_group, got_priority, result > out
    }
  ' "$LAB_ROOT/input/rule-tests.csv" || fail "business rule evaluation failed"

  awk -F',' -v OFS=',' -v collectors="$LAB_ROOT/policy/collectors.csv" -v out="$LAB_ROOT/output/mail-routing-results.csv" '
    BEGIN {
      while ((getline line < collectors) > 0) {
        if (++n == 1) continue
        split(line, f, ","); entity[f[1]] = f[3]; enabled[f[1]] = f[6]
      }
      close(collectors); print "mail_id,action,entity,result" > out
    }
    NR == 1 { next }
    {
      action = ""; target = ""
      if (!($2 in entity) || enabled[$2] != "yes") action = "REJECT_DISABLED_COLLECTOR"
      else if ($6 == "yes") action = "REJECT_AUTOREPLY"
      else if ($7 != "") { action = "ADD_FOLLOWUP"; target = entity[$2] }
      else if ($4 == "soria.example") { action = "CREATE_TICKET"; target = entity[$2] }
      else action = "REJECT_UNKNOWN_DOMAIN"
      result = (action == $8 && target == $9 ? "PASS" : "FAIL")
      print $1, action, target, result > out
    }
  ' "$LAB_ROOT/input/incoming-mails.csv" || fail "mail routing evaluation failed"

  awk -F',' -v OFS=',' -v notifications="$LAB_ROOT/policy/notifications.csv" -v out="$LAB_ROOT/output/notification-queue-results.csv" '
    BEGIN {
      while ((getline line < notifications) > 0) {
        if (++n == 1) continue
        split(line, f, ","); enabled[f[1]] = f[3]; delay[f[1]] = f[6]
      }
      close(notifications); print "event_id,notification_code,computed_send_minute,expected_send_minute,result" > out
    }
    NR == 1 { next }
    {
      send = $5 + delay[$2]
      result = (($2 in enabled) && enabled[$2] == "yes" && send == $6 ? "PASS" : "FAIL")
      print $1, $2, send, $6, result > out
    }
  ' "$LAB_ROOT/input/notification-events.csv" || fail "notification queue evaluation failed"

  awk -F',' -v OFS=',' -v now=240 -v out="$LAB_ROOT/output/automatic-action-health.csv" '
    BEGIN { print "action_code,health,reason" > out }
    NR == 1 { next }
    {
      health = "OK"; reason = "scheduled"
      if ($3 != "yes") { health = "DISABLED"; reason = "action disabled" }
      else if ($2 != "CLI") { health = "REVIEW"; reason = "CLI mode recommended" }
      else if ($7 == "running" && $6 == "" && now - $5 >= 2 * $4) { health = "STUCK"; reason = "running beyond two frequencies" }
      else if ($7 == "idle" && now - $6 > 2 * $4) { health = "LATE"; reason = "last successful run too old" }
      print $1, health, reason > out
    }
  ' "$LAB_ROOT/policy/automatic-actions.csv" || fail "automatic action health evaluation failed"

  awk -F',' -v OFS=',' -v now=240 -v out="$LAB_ROOT/output/queue-health.csv" '
    BEGIN { print "queue_id,health,reason" > out }
    NR == 1 { next }
    {
      health = "OK"; reason = "within policy"
      if ($6 == "pending" && now > $5 && $7 >= 3) { health = "ESCALATE"; reason = "overdue with repeated retries" }
      else if ($6 == "pending" && now > $5) { health = "LATE"; reason = "past due minute" }
      else if ($6 == "rejected") { health = "REJECTED_AS_DESIGNED"; reason = "routing policy rejected input" }
      print $1, health, reason > out
    }
  ' "$LAB_ROOT/input/queue.csv" || fail "queue health evaluation failed"

  awk -F',' -v OFS=',' -v suppliers="$LAB_ROOT/refs/suppliers.csv" -v budgets="$LAB_ROOT/refs/budgets.csv" -v out="$LAB_ROOT/output/contract-license-controls.csv" '
    BEGIN {
      while ((getline line < suppliers) > 0) { if (++sn == 1) continue; split(line, f, ","); supplier[f[1]] = f[3] }
      close(suppliers)
      while ((getline line < budgets) > 0) { if (++bn == 1) continue; split(line, f, ","); budget_amount[f[1]] = f[5] }
      close(budgets)
      print "object_code,object_type,control,result,detail" > out
    }
    FILENAME ~ /contracts.csv$/ && NR == 1 { next }
    FILENAME ~ /contracts.csv$/ {
      result = (($3 in supplier) && supplier[$3] == "yes" && ($4 in budget_amount) && $6 >= $5 && $7 + 0 > 0 && $8 + 0 > 0 ? "PASS" : "FAIL")
      print $1, "contract", "references-and-dates", result, "supplier=" $3 ";budget=" $4 > out
      committed[$4] += $7; next
    }
    FILENAME ~ /licenses.csv$/ && NR == 1 { next }
    FILENAME ~ /licenses.csv$/ {
      result = (($3 in supplier) && ($4 in budget_amount) && $5 + 0 >= 0 && $6 + 0 >= 0 && $8 + 0 > 0 ? "PASS" : "FAIL")
      detail = ($6 + 0 > $5 + 0 ? "OVERASSIGNED" : "WITHIN_SEATS")
      print $1, "license", "references-and-seats", result, detail > out
      committed[$4] += $8
    }
    END {
      for (b in budget_amount) {
        pct = (budget_amount[b] > 0 ? committed[b] * 100 / budget_amount[b] : 0)
        result = (pct <= 100 ? "PASS" : "FAIL")
        printf "%s,budget,commitment,%s,%.2f%%\n", b, result, pct > out
      }
    }
  ' "$LAB_ROOT/input/contracts.csv" "$LAB_ROOT/input/licenses.csv" || fail "contract and license controls failed"

  {
    printf 'object_code,object_type,end_date,days_remaining,alert\n'
    tail -n +2 "$LAB_ROOT/input/contracts.csv" | while IFS=',' read -r code name supplier budget start_date end_date annual_cost notice status
    do
      end_epoch=$(date -u -d "$end_date" +%s); today_epoch=$(date -u -d '2026-08-04' +%s)
      days=$(( (end_epoch - today_epoch) / 86400 ))
      if [ "$days" -le "$notice" ]; then alert=RENEWAL_DUE; else alert=OK; fi
      printf '%s,contract,%s,%s,%s\n' "$code" "$end_date" "$days" "$alert"
    done
    tail -n +2 "$LAB_ROOT/input/licenses.csv" | while IFS=',' read -r code name supplier budget seats_owned seats_assigned end_date annual_cost
    do
      end_epoch=$(date -u -d "$end_date" +%s); today_epoch=$(date -u -d '2026-08-04' +%s)
      days=$(( (end_epoch - today_epoch) / 86400 ))
      if [ "$days" -le 90 ]; then alert=RENEWAL_DUE; else alert=OK; fi
      printf '%s,license,%s,%s,%s\n' "$code" "$end_date" "$days" "$alert"
    done
  } > "$LAB_ROOT/output/renewal-alerts.csv"

  awk -F',' -v OFS=',' -v out="$LAB_ROOT/output/dashboard-kpis.csv" '
    NR == 1 { next }
    { count++; tta += $5 - $4; ttr += $6 - $4; if ($8 == "yes") reopened++; satisfaction += $9 }
    END {
      avg_tta = tta / count; avg_ttr = ttr / count; reopen_rate = reopened * 100 / count; avg_sat = satisfaction / count
      print "kpi_code,value,target,result" > out
      print "KPI_VOLUME",count,6,(count == 6 ? "PASS" : "FAIL") > out
      printf "KPI_TTA,%.2f,30,%s\n",avg_tta,(avg_tta <= 30 ? "PASS" : "FAIL") > out
      printf "KPI_TTR,%.2f,180,%s\n",avg_ttr,(avg_ttr <= 180 ? "PASS" : "FAIL") > out
      printf "KPI_REOPEN,%.2f,10,%s\n",reopen_rate,(reopen_rate <= 10 ? "PASS" : "FAIL") > out
      printf "KPI_SAT,%.2f,4,%s\n",avg_sat,(avg_sat >= 4 ? "PASS" : "FAIL") > out
    }
  ' "$LAB_ROOT/input/ticket-metrics.csv" || fail "dashboard KPI calculation failed"

  {
    printf '# Rapport opérationnel automatisation et reporting\n\n'
    printf -- '- tests de règles : %s\n' "$(csv_rows "$LAB_ROOT/output/rule-test-results.csv")"
    printf -- '- emails évalués : %s\n' "$(csv_rows "$LAB_ROOT/output/mail-routing-results.csv")"
    printf -- '- événements notification : %s\n' "$(csv_rows "$LAB_ROOT/output/notification-queue-results.csv")"
    printf -- '- actions automatiques : %s\n' "$(csv_rows "$LAB_ROOT/output/automatic-action-health.csv")"
    printf -- '- contrats et licences contrôlés : %s\n' "$(awk -F',' 'NR>1 && ($2=="contract" || $2=="license") {c++} END{print c+0}' "$LAB_ROOT/output/contract-license-controls.csv")"
    printf '\nLe laboratoire produit des décisions et indicateurs hors ligne. Il ne contacte aucune instance GLPI, boîte mail ou serveur SMTP.\n'
  } > "$LAB_ROOT/evidence/operations-report.md"

  (
    cd "$LAB_ROOT"
    sha256sum refs/*.csv policy/*.csv input/*.csv > evidence/source-checksums-after.sha256
    sha256sum output/*.csv evidence/operations-report.md > evidence/output-checksums.sha256
  )
  diff -u "$LAB_ROOT/evidence/source-checksums-before.sha256" "$LAB_ROOT/evidence/source-checksums-after.sha256" > "$LAB_ROOT/evidence/source-immutability.diff" || fail "source fixtures changed during run"

  printf 'Automation, queues, contracts, licenses and dashboard evaluation completed.\n'
}

validate_reference() {
  require_marker
  for file in "$LAB_ROOT/output/rule-test-results.csv" "$LAB_ROOT/output/mail-routing-results.csv" "$LAB_ROOT/output/notification-queue-results.csv" "$LAB_ROOT/output/automatic-action-health.csv" "$LAB_ROOT/output/queue-health.csv" "$LAB_ROOT/output/contract-license-controls.csv" "$LAB_ROOT/output/renewal-alerts.csv" "$LAB_ROOT/output/dashboard-kpis.csv" "$LAB_ROOT/evidence/operations-report.md" "$LAB_ROOT/evidence/source-checksums-after.sha256" "$LAB_ROOT/evidence/output-checksums.sha256" "$LAB_ROOT/evidence/source-immutability.diff"
  do [ -f "$file" ] || fail "missing output: $file"; done

  [ "$(csv_rows "$LAB_ROOT/output/rule-test-results.csv")" -eq 4 ] || fail "expected 4 rule tests"
  [ "$(awk -F',' 'NR>1 && $6=="PASS"{c++} END{print c+0}' "$LAB_ROOT/output/rule-test-results.csv")" -eq 4 ] || fail "business rule test failure"
  grep -Fq 'TEST-001,RULE_NET_SUBJECT,INCIDENT_NETWORK,INFRA,P3,PASS' "$LAB_ROOT/output/rule-test-results.csv" || fail "network rule result missing"
  grep -Fq 'TEST-004,RULE_FALLBACK,INCIDENT_WORKSTATION,SUPPORT_N1,P4,PASS' "$LAB_ROOT/output/rule-test-results.csv" || fail "fallback rule result missing"
  [ "$(csv_rows "$LAB_ROOT/output/mail-routing-results.csv")" -eq 5 ] || fail "expected 5 mail routing results"
  grep -Fq 'MAIL-003,REJECT_AUTOREPLY,,PASS' "$LAB_ROOT/output/mail-routing-results.csv" || fail "autoresponder rejection missing"
  grep -Fq 'MAIL-004,REJECT_UNKNOWN_DOMAIN,,PASS' "$LAB_ROOT/output/mail-routing-results.csv" || fail "unknown domain rejection missing"
  grep -Fq 'MAIL-005,ADD_FOLLOWUP,ORLEANS,PASS' "$LAB_ROOT/output/mail-routing-results.csv" || fail "followup routing missing"
  [ "$(awk -F',' 'NR>1 && $5=="PASS"{c++} END{print c+0}' "$LAB_ROOT/output/notification-queue-results.csv")" -eq 4 ] || fail "notification timing failure"
  grep -Fq 'watcher,STUCK,running beyond two frequencies' "$LAB_ROOT/output/automatic-action-health.csv" || fail "stuck action not detected"
  grep -Fq 'Q-005,ESCALATE,overdue with repeated retries' "$LAB_ROOT/output/queue-health.csv" || fail "queue escalation missing"
  grep -Fq 'LIC-CAD,license,references-and-seats,PASS,OVERASSIGNED' "$LAB_ROOT/output/contract-license-controls.csv" || fail "license overassignment missing"
  grep -Fq 'CTR-001,contract,2026-09-15,42,RENEWAL_DUE' "$LAB_ROOT/output/renewal-alerts.csv" || fail "contract renewal alert missing"
  grep -Fq 'KPI_REOPEN,16.67,10,FAIL' "$LAB_ROOT/output/dashboard-kpis.csv" || fail "reopen KPI failure missing"
  grep -Fq 'KPI_SAT,3.83,4,FAIL' "$LAB_ROOT/output/dashboard-kpis.csv" || fail "satisfaction KPI failure missing"
  [ ! -s "$LAB_ROOT/evidence/source-immutability.diff" ] || fail "source immutability diff is not empty"
  (cd "$LAB_ROOT" && sha256sum -c evidence/source-checksums-after.sha256 >/dev/null && sha256sum -c evidence/output-checksums.sha256 >/dev/null) || fail "checksum verification failed"
  ! grep -RniE --exclude='*.sh' --exclude='*-checksums-*' '(password[[:space:]]*=|token[[:space:]]*=|private[_-]?key|https?://[^/[:space:]]+@)' "$LAB_ROOT" >/dev/null || fail "credential-like value detected"
  grep -Fq 'ne contacte aucune instance GLPI' "$LAB_ROOT/evidence/operations-report.md" || fail "proof boundary missing"
  printf 'Validation successful: rules, collectors, notifications, queues, contracts, licenses and KPIs are correct.\n'
}

reset_lab() { require_marker; rm -rf "$LAB_ROOT"; printf 'GLPI automation and reporting laboratory removed: %s\n' "$LAB_ROOT"; }

resolve_safe_root
case "$ACTION" in
  setup) setup_lab ;;
  status) show_status ;;
  run) run_reference ;;
  validate) validate_reference ;;
  reset) reset_lab ;;
  *) fail "unknown action: $ACTION" ;;
esac
