module Backlog
  # The parsed contents of a repo's `.cc-os/config`. The file format is
  # '#'-commented `key=value` lines, no spaces around `=` (ADR-026/#23) —
  # the contract is owned by os-status (plugins/os-status/hooks/state.py).
  # Reads tolerate legacy `key = value` spacing and legacy `key: value`
  # YAML lines from earlier os-backlog versions; #merge always re-emits
  # every key in the normalized `key=value` form, matching os-status's
  # write_config_value. Never touches the filesystem itself — callers read
  # the file and pass its contents (or nil, if absent) in.
  class Config
    def initialize(contents)
      @data = {}
      contents.to_s.each_line do |line|
        line = line.strip
        next if line.empty? || line.start_with?("#") || line == "---"

        if line.include?("=")
          key, value = line.split("=", 2)
        elsif line.include?(": ")
          key, value = line.split(": ", 2)
        else
          next
        end
        @data[key.strip] = value.strip
      end
    end

    # @return [String, nil] the tracker key (e.g. "forgejo:owner/repo"), if configured
    def tracker
      @data["tracker"]
    end

    # @return [String, nil] the cached Planka board id, if present (legacy;
    #   Planka is retired per ADR-0042 — kept only so old .cc-os/config
    #   files with this key still parse without error).
    def board_id
      @data["board_id"]
    end

    def tracker_configured? = !tracker.nil?

    # @return [Hash] a copy of the parsed config data
    def to_h = @data.dup

    # Return new key=value contents with `key` set to `value`, preserving
    # every other key already present in `contents` (legacy YAML-style
    # lines are rewritten to key=value). Pure — does not touch the
    # filesystem; callers read/write the file themselves.
    #
    # @param contents [String, nil] existing raw `.cc-os/config` contents
    # @param key [String, Symbol] key to set
    # @param value [Object] value to set it to
    # @return [String] the updated key=value contents
    def self.merge(contents, key, value)
      data = new(contents).to_h
      data[key.to_s] = value.to_s
      data.map { |k, v| "#{k}=#{v}\n" }.join
    end

    # Like .merge but comment/format-preserving: every non-key line
    # (comments, blanks) is left byte-for-byte untouched; existing
    # key=value lines are re-emitted in the normalized no-spaces form; the
    # key is replaced in place or appended if absent. Mirrors os-status's
    # write_config_value (plugins/os-status/hooks/state.py) — the shared
    # .cc-os/config contract owner. Pure — no filesystem.
    #
    # @param contents [String, nil] existing raw `.cc-os/config` contents
    # @param key [String, Symbol] key to set
    # @param value [Object] value to set it to
    # @return [String] the updated contents
    def self.set(contents, key, value)
      key = key.to_s
      found = false
      out = contents.to_s.split("\n").map do |line|
        stripped = line.strip
        next line if stripped.empty? || stripped.start_with?("#") || !stripped.include?("=")

        k, v = stripped.split("=", 2)
        if k.strip == key
          found = true
          "#{key}=#{value}"
        else
          "#{k.strip}=#{v.strip}"
        end
      end
      out << "#{key}=#{value}" unless found
      "#{out.join("\n")}\n"
    end
  end
end
