module Adr
  # The docs/adr/ directory of one project. Scans files, derives the next ID
  # from directory contents (never the index), reads and writes records.
  class Repository
    INDEX_FILENAME = "README.md"

    Entry = Struct.new(:path, :record)

    def initialize(root:)
      @root = root
    end

    attr_reader :root

    def dir        = File.join(root, "docs", "adr")
    def index_path = File.join(dir, INDEX_FILENAME)

    def exists?
      Dir.exist?(dir) && File.exist?(index_path)
    end

    def adr_paths
      Dir.glob(File.join(dir, "[0-9][0-9][0-9][0-9]-*.md")).sort
    end

    # Only files in the os-adr format count as entries; legacy frontmatter-less
    # files sharing docs/adr/ (pre-migration sources) are skipped, not errors.
    def entries
      adr_paths.filter_map do |path|
        Entry.new(path, Record.parse(File.read(path)))
      rescue Record::ParseError, Psych::SyntaxError
        nil
      end
    end

    def next_id
      max = adr_paths.map { |path| File.basename(path)[0, 4].to_i }.max || 0
      format("%04d", max + 1)
    end

    def find(id)
      entries.find { |entry| entry.record.id == id }
    end

    def write(record)
      path = File.join(dir, "#{record.id}-#{Adr.slugify(record.title)}.md")
      File.write(path, record.to_markdown)
      path
    end

    def write_entry(entry)
      File.write(entry.path, entry.record.to_markdown)
    end
  end
end
