module Backlog
  # Pure decision for the triage-trigger SessionStart hook (card
  # 1818330518584820864): given the label arrays already sitting on a
  # board's Backlog-column cards, does the hook need to instruct dispatch
  # of the card-triage agent? Network/board-fetch stays in the hook
  # script (hooks/triage_check.rb) — this class only classifies +
  # composes the note text, so the decision is unit-testable without
  # Planka.
  #
  # "Unlabeled" mirrors card-triage's own definition (agents/card-triage.md):
  # a card is raw if it is missing a priority label (P0-P3) OR an
  # autonomy label (hitl/semi/afk-ready) — not just totally bare.
  class TriageCheck
    PRIORITY_LABELS = %w[P0 P1 P2 P3].freeze
    AUTONOMY_LABELS = %w[hitl semi afk-ready].freeze

    # Which board should this session's triage check inspect? Mirrors the
    # CLI's config semantics (the session cwd's own .cc-os/config wins —
    # umbrella subdir configs override the repo root's), falling back to
    # the root config, then to the path heuristic. Honors both the
    # explicit `board` key and `tracker=planka:<board>` (via
    # Config#planka_board). Pure: the hook script reads the files and
    # passes contents (or nil) in.
    #
    # @param cwd [String] the session's working directory
    # @param root [String] the enclosing git toplevel (== cwd outside umbrellas)
    # @param cwd_config [String, nil] contents of <cwd>/.cc-os/config
    # @param root_config [String, nil] contents of <root>/.cc-os/config
    # @return [String, nil] board name, or nil (don't guess) when nothing
    #   is configured and the path heuristic doesn't recognize the path
    def self.board_name_for(cwd:, root:, cwd_config:, root_config:)
      config_home = cwd_config ? cwd : root
      config = Config.new(cwd_config || root_config)
      return config.planka_board if config.planka_board
      return nil unless Resolver.project_for(config_home)

      File.basename(config_home)
    end

    # @param labels [Array<String>] the label names on one card
    # @return [Boolean]
    def self.needs_triage?(labels)
      (labels & PRIORITY_LABELS).empty? || (labels & AUTONOMY_LABELS).empty?
    end

    # @param backlog_cards_labels [Array<Array<String>>] label arrays,
    #   one per card currently in the board's Backlog list
    # @return [Array<Array<String>>] the subset needing triage
    def self.unlabeled(backlog_cards_labels)
      backlog_cards_labels.select { |labels| needs_triage?(labels) }
    end

    # @param board_name [String]
    # @param backlog_cards_labels [Array<Array<String>>]
    # @return [String, nil] the SessionStart additionalContext note, or
    #   nil when there is nothing to triage
    def self.note_for(board_name, backlog_cards_labels)
      count = unlabeled(backlog_cards_labels).size
      return nil if count.zero?

      card_word = count == 1 ? "card" : "cards"
      "[os-backlog] #{count} unlabeled Backlog #{card_word} on board #{board_name} -> " \
        "dispatch the card-triage agent now (model: haiku, run in background) to label " \
        "them. Labeling is this project's job for its own board (a parent umbrella may " \
        "also label its child boards) — never label cards on a board that belongs to a " \
        "different project."
    end
  end
end
