require_relative "test_helper"

class BoardResolverTest < Minitest::Test
  include BacklogTestHelpers

  def setup
    @client = FakePlankaClient.new
    ensurer = Backlog::BoardEnsurer.new(client: @client, human_user_id: "human-1")
    @board = ensurer.ensure("llf-schema", project_name: "Dev").board
    @writes = []
  end

  def resolver_with(config)
    @config = config
    Backlog::BoardResolver.new(
      client: @client,
      read_config: -> { @config },
      write_config: ->(contents) { @writes << contents }
    )
  end

  def config_with_cache(id = @board.id)
    "# repo config\ntracker=planka:llf-schema\nboard_id=#{id}\nversion=3\n"
  end

  def test_cache_hit_uses_boards_get_and_skips_name_listing
    @client.projects.define_singleton_method(:list) { raise "projects.list must not be called on a cache hit" }
    resolver = resolver_with(config_with_cache)

    board = resolver.board_for("llf-schema")

    assert_equal @board.id, board.id
    assert_empty @writes
  end

  def test_cache_miss_resolves_by_name_and_writes_board_id_preserving_comments
    resolver = resolver_with("# repo config\ntracker=planka:llf-schema\nversion=3\n")

    board = resolver.board_for("llf-schema")

    assert_equal @board.id, board.id
    assert_equal 1, @writes.size
    assert_equal "# repo config\ntracker=planka:llf-schema\nversion=3\nboard_id=#{@board.id}\n",
                 @writes.last
  end

  def test_stale_id_404_falls_back_to_name_lookup_and_rewrites_cache
    resolver = resolver_with(config_with_cache("no-such-id"))

    board = resolver.board_for("llf-schema")

    assert_equal @board.id, board.id
    assert_includes @writes.last, "board_id=#{@board.id}\n"
    assert_includes @writes.last, "# repo config"
  end

  def test_renamed_board_name_mismatch_falls_back_and_rewrites_cache
    stale = @board
    @client.boards.update(stale.id, name: "something-else")
    current = @client.boards.create(stale.project_id, name: "llf-schema", position: 2)
    resolver = resolver_with(config_with_cache(stale.id))

    board = resolver.board_for("llf-schema")

    assert_equal current.id, board.id
    assert_includes @writes.last, "board_id=#{current.id}\n"
  end

  def test_non_planka_tracker_ignores_board_id_and_never_writes
    resolver = resolver_with("tracker=forgejo:jared/cc-os\nboard_id=bogus-id\n")

    board = resolver.board_for("llf-schema")

    assert_equal @board.id, board.id
    assert_empty @writes
  end

  def test_board_id_for_different_planka_board_name_is_ignored
    resolver = resolver_with("tracker=planka:other-board\nboard_id=bogus-id\n")

    board = resolver.board_for("llf-schema")

    assert_equal @board.id, board.id
    assert_empty @writes # tracker doesn't match this board name; no cache write either
  end

  def test_unreadable_config_degrades_to_name_lookup
    resolver = Backlog::BoardResolver.new(
      client: @client,
      read_config: -> { raise Errno::EACCES, "config" },
      write_config: ->(contents) { @writes << contents }
    )

    board = resolver.board_for("llf-schema")

    assert_equal @board.id, board.id
    assert_empty @writes
  end

  def test_unwritable_config_never_fails_the_command
    resolver = Backlog::BoardResolver.new(
      client: @client,
      read_config: -> { "tracker=planka:llf-schema\n" },
      write_config: ->(_) { raise Errno::EACCES, "config" }
    )

    board = resolver.board_for("llf-schema")

    assert_equal @board.id, board.id
  end

  def test_matching_cached_id_is_not_rewritten
    resolver = resolver_with(config_with_cache)
    resolver.board_for("llf-schema")

    assert_empty @writes
  end

  def test_unknown_board_still_raises
    resolver = resolver_with(nil)
    error = assert_raises(RuntimeError) { resolver.board_for("nope") }
    assert_match(/no board named "nope"/, error.message)
  end

  def test_cards_add_through_resolver_writes_cache_once
    resolver = resolver_with("tracker=planka:llf-schema\n")
    cards = Backlog::Cards.new(client: @client, board_resolver: resolver)

    card = cards.add(board_name: "llf-schema", title: "Cache me")

    assert_equal "Cache me", card.name
    assert_equal 1, @writes.size
    assert_includes @writes.last, "board_id=#{@board.id}\n"
  end
end
