require_relative "test_helper"

class DetectorTest < Minitest::Test
  include AdrTestHelpers

  NUMBERED = <<~MD
    # 0001 — PocketBase backend

    ## Status

    Accepted

    ## Context

    Need a backend.

    ## Decision

    PocketBase.

    ## Consequences

    Single binary.

    ## Alternatives considered

    Rails — too heavy.
  MD

  DATED = <<~MD
    # JSX conversion pivot

    **Date:** 2024-12-15
    **Status:** Accepted

    ## Context

    Conversion stalled.

    ## Decision

    Pivot to JSX.
  MD

  TOPIC = <<~MD
    # bin/lint-fix

    Status: Confirmed
    Decided: 2026-02-01

    ## Decision

    One lint entry point.

    ## Why

    Consistency across repos.
  MD

  MONOLITHIC = <<~MD
    # Decision log

    ## ADR-001: Use SQLite

    Status: Accepted

    ### Context

    Need storage.

    ### Decision

    SQLite.

    ## ADR-002: Drop SQLite

    Status: Accepted

    ### Decision

    Postgres instead.
  MD

  PROSE = <<~MD
    # Gaps and decisions (LOCKED)

    Long narrative preamble.

    Decision 26: Single entry point

    We route everything through one command.

    Decision 27: No config file

    Defaults only.
  MD

  UNRECOGNIZED = "# Meeting notes\n\nWe talked about stuff.\n"

  MULTI_STATUS_NO_HEADINGS = <<~MD
    # DECISIONS

    2026-01-05 — Hosting
    Status: Confirmed
    We host on X.

    2026-02-10 — Pricing
    Status: Deferred
    Revisit in Q3.
  MD

  def fixture_project
    Dir.mktmpdir do |root|
      decisions = File.join(root, "docs", "decisions")
      adr = File.join(root, "docs", "adr")
      FileUtils.mkdir_p(decisions)
      FileUtils.mkdir_p(adr)
      File.write(File.join(adr, "0001-pocketbase-backend.md"), NUMBERED)
      File.write(File.join(adr, "README.md"), "index")
      File.write(File.join(decisions, "2024-12-15-jsx-pivot.md"), DATED)
      File.write(File.join(decisions, "bin-lint-fix.md"), TOPIC)
      File.write(File.join(decisions, "decision-log.md"), MONOLITHIC)
      File.write(File.join(decisions, "gaps-and-decisions.md"), PROSE)
      File.write(File.join(decisions, "notes.md"), UNRECOGNIZED)
      File.write(File.join(root, "DECISIONS.md"), MULTI_STATUS_NO_HEADINGS)
      yield root, Adr::Detector.new(root: root).units
    end
  end

  def shapes_by_source(units)
    units.group_by(&:source_path).transform_values { |us| us.map(&:shape).uniq }
  end

  def test_classifies_each_surveyed_shape
    fixture_project do |_root, units|
      shapes = shapes_by_source(units)
      assert_equal [:numbered_per_file], shapes["docs/adr/0001-pocketbase-backend.md"]
      assert_equal [:dated_single_file], shapes["docs/decisions/2024-12-15-jsx-pivot.md"]
      assert_equal [:topic_single_file], shapes["docs/decisions/bin-lint-fix.md"]
      assert_equal [:monolithic], shapes["docs/decisions/decision-log.md"]
      assert_equal [:prose_embedded], shapes["docs/decisions/gaps-and-decisions.md"]
      assert_equal [:unrecognized], shapes["docs/decisions/notes.md"]
    end
  end

  def test_monolithic_units_are_enumerated_per_heading
    fixture_project do |_root, units|
      mono = units.select { |u| u.source_path == "docs/decisions/decision-log.md" }
      assert_equal 2, mono.size
      assert_equal ["Use SQLite", "Drop SQLite"], mono.map(&:title)
      assert_includes mono.first.body, "SQLite."
      refute_includes mono.first.body, "Postgres"
    end
  end

  def test_prose_embedded_units_are_enumerated
    fixture_project do |_root, units|
      prose = units.select { |u| u.source_path == "docs/decisions/gaps-and-decisions.md" }
      assert_equal ["Single entry point", "No config file"], prose.map(&:title)
    end
  end

  def test_multi_decision_file_without_unit_headings_is_unrecognized
    fixture_project do |_root, units|
      assert_equal [:unrecognized], shapes_by_source(units)["DECISIONS.md"]
    end
  end

  def test_index_and_already_migrated_files_are_excluded
    with_project("0001-a.md" => sample_adr) do |root|
      File.write(File.join(root, "docs", "adr", "README.md"), "index")
      assert_empty Adr::Detector.new(root: root).units
    end
  end
end
