#!/bin/bash
# Over the hard cap fails; over the soft budget only warns, see AGENTS.md "File budget".
set -u

soft_rust=250; hard_rust=400
soft_qml=250;  hard_qml=400
soft_js=200;   hard_js=300

# Recorded debts and scoped release exceptions retain exact per-file ceilings; global limits stay unchanged.
known_over_cap="shelf/Model.js 669
shelf/Panel.qml 430
shelf/ShelfCard.qml 443
shelf/ShelfService.qml 481
src/backend/copyfile.rs 730
src/backend/copyfile_tests.rs 607
src/backend/durable.rs 790
src/backend/durable_tests.rs 1305
src/backend/fsinforeq.rs 407
src/backend/jump_tests.rs 487
src/backend/renamecompat.rs 762
src/backend/gvfslist.rs 560
src/backend/imagesize.rs 473
src/backend/iomount.rs 606
src/backend/localsend.rs 405
src/backend/menu_actions.rs 641
src/backend/menu_registry.rs 563
src/backend/meta.rs 575
src/backend/metareq.rs 416
src/backend/movebatch.rs 474
src/backend/movebatch_tests.rs 752
src/backend/opsdispatch.rs 2204
src/backend/opsreq.rs 560
src/backend/opsreq/tests.rs 484
src/backend/permissions.rs 719
src/backend/run.rs 719
src/backend/ops.rs 427
src/backend/thumbs.rs 460
src/backend/dirsizeworker.rs 574
src/backend/watch.rs 533
src/backend/thumbreq.rs 418
src/backend/undo.rs 606
src/backend/undo_tests.rs 423
src/backend/undoshare.rs 403
src/backend/undoshare_tests.rs 533
src/backend/collide_replace_tests.rs 487
src/backend/proto.rs 378
src/backend/thumbworker.rs 953
src/backend/trashbrowse.rs 779
src/backend/trashdelete.rs 938
src/clip/watch_end_tests.rs 406
src/gui.rs 501
src/tui/actions.rs 1067
src/tui/input.rs 449
src/tui/model.rs 1247
src/tui/render.rs 889
src/uischema.rs 499
src/uistate.rs 674
src/uistore.rs 540
src/vulkan.rs 728
tests/js/columns.js 666
tests/js/drag.js 469
tests/js/devices.js 303
tests/js/previewswap.js 408
tests/js/mdstructure.js 626
tests/js/keymap.js 309
tests/js/focus.js 745
tests/js/mounts.js 262
tests/js/menu.js 515
tests/js/nav.js 362
tests/picker-grid.qml 450
tests/picker-hunt.qml 445
tests/js/network.js 306
tests/js/ops.js 511
tests/js/slowclick.js 308
tests/js/settings.js 352
tests/js/tap.js 333
tests/js/uistate.js 370
tests/js/watch.js 540
tests/js/xwwatch.js 310
tests/js/tabs.js 686
tests/columnrow-geom.qml 409
tests/columnscost.qml 416
tests/columnsfolder.qml 399
tests/quicklook-firstframe.qml 438
tests/markdown-render.qml 795
tests/markdown-linearity.qml 679
tests/markdown-preview-state.qml 469
tests/markdown-tables.qml 401
tests/quicklook-firstframe.js 214
tests/preview-settle-live.qml 457
tests/preview-decode.qml 507
tests/js/status.js 354
tests/rename-grid-bottom.qml 424
tests/rename-grid-bottom.js 305
tests/ring-bounds.qml 639
tests/sidebar-flows.qml 401
tests/touchpad.qml 747
tests/xwsettings-tabs.qml 444
ui/Backend.qml 472
ui/ChromeBar.qml 472
ui/ColumnsArea.qml 491
ui/ContextMenu.qml 739
ui/ConvertDialog.qml 435
ui/GridArea.qml 420
ui/Ipc.qml 883
ui/KeymapSheet.qml 549
ui/List.qml 437
tests/touchpad-edge.qml 438
ui/FastScrollHandler.qml 529
ui/FigureService.qml 405
ui/NetworkDialog.qml 447
ui/NetworkForm.qml 406
ui/NetworkMounts.qml 849
ui/OpenWithDialog.qml 608
ui/Pane.qml 1043
ui/PaneMenuActions.qml 467
ui/PaneWire.qml 586
ui/PermissionsDialog.qml 674
ui/PickerWindow.qml 779
ui/Preview.qml 669
ui/PreviewColumn.qml 583
ui/DeviceMounts.qml 496
ui/PreviewMarkdown.qml 623
ui/Row.qml 482
ui/SettingsPanel.qml 543
ui/SettingsRow.qml 409
ui/Sidebar.qml 669
ui/StatusBar.qml 456
ui/Theme.qml 433
ui/TrashView.qml 466
ui/ViewState.qml 536
ui/WindowBody.qml 651
ui/js/Anchor.js 406
ui/js/Devices.js 366
ui/js/Filter.js 257
ui/js/Focus.js 435
ui/js/Keymap.js 355
ui/js/Nav.js 308
ui/js/Markdown.js 155
ui/js/MdBlocks.js 444
ui/js/MdDocument.js 341
ui/js/MdLeaf.js 316
ui/js/MdInline.js 295
ui/js/Menu.js 454
ui/js/Drag.js 342
ui/js/Ops.js 426
ui/js/Picker.js 328
ui/js/Settings.js 456
ui/js/Tabs.js 719
ui/js/UiState.js 447
ui/TabBar.qml 632
ui/boot/fleatab.qml 50"

status=0

budget_for() {
  case "$1" in
    *.rs)  echo "$soft_rust $hard_rust" ;;
    *.qml) echo "$soft_qml $hard_qml" ;;
    *.js)  echo "$soft_js $hard_js" ;;
    *)     echo "" ;;
  esac
}

while IFS= read -r file; do
  # Pinned vendor bundles are excluded as generated output; the generated Keymap.js keeps its recorded ceiling.
  case "$file" in
    ui/vendor/*) continue ;;
  esac
  budgets=$(budget_for "$file")
  [ -z "$budgets" ] && continue
  soft=${budgets% *}
  hard=${budgets#* }
  lines=$(wc -l < "$file")
  if [ "$lines" -gt "$hard" ]; then
    # Sample input: ui/Preview.qml 724, an exact per-file ceiling from known_over_cap.
    recorded=$(printf '%s\n' "$known_over_cap" | awk -v f="$file" '$1 == f { print $2 }')
    if [ -n "$recorded" ]; then
      if [ "$lines" -gt "$recorded" ]; then
        echo "GREW      $file: $lines lines, recorded $recorded, cap $hard"
        status=1
      else
        echo "known     $file: $lines lines, recorded $recorded, cap $hard"
      fi
      continue
    fi
    echo "OVER CAP  $file: $lines lines, cap $hard"
    status=1
  elif [ "$lines" -gt "$soft" ]; then
    echo "over soft $file: $lines lines, budget $soft, split it"
  fi
done < <(find src ui shelf tests -type f \( -name '*.rs' -o -name '*.qml' -o -name '*.js' \) 2>/dev/null)

exit $status
