# @@changelog @@changes
require 'tty-markdown'

MARKDOWN_THEME = {
  em: %i[white dark],
  header: %i[cyan bold],
  hr: :yellow,
  link: %i[bright_cyan underline],
  list: :yellow,
  strong: %i[yellow bold],
  table: :yellow,
  quote: :yellow,
  image: :bright_black,
  note: :yellow,
  comment: :bright_black
}.deep_freeze

module Doing
  # changes command methods
  class ChangesCommand
    CHANGE_RX = /^(?:(?:(?:[<>=]+|p(?:rior)|b(?:efore)|o(?:lder)|s(?:ince)|a(?:fter)|n(?:ewer))? *[0-9.*?]{1,10} *)+|(?:[\d.]+ *(?:-|to)+ *[0-9.]{1,10}))$/

    def add_options(cmd)
      cmd.desc 'Display all versions'
      cmd.switch %i[a all], default_value: false, negatable: false

      cmd.desc %(Look up a specific version. Specify versions as "MAJ.MIN.PATCH", MIN
               and PATCH are optional. Use > or < to see all changes since or prior
               to a version. Wildcards (*?) accepted unless using < or >.)
      cmd.arg_name 'VERSION'
      cmd.flag %i[l lookup], must_match: CHANGE_RX

      cmd.desc %(Show changelogs matching search terms (uses pattern-based searching).
               Add slashes to search with regular expressions, e.g. `--search "/output.*flag/"`)
      cmd.flag %i[s search]

      cmd.desc 'Sort order (asc/desc)'
      cmd.arg_name 'ORDER'
      cmd.flag %i[sort], must_match: REGEX_SORT_ORDER, default_value: :desc, type: OrderSymbol

      cmd.desc 'Only output changes, no version numbers, headers, or dates'
      cmd.switch %i[C changes], default_value: false, negatable: false

      cmd.desc 'Include (CHANGE|NEW|IMPROVED|FIXED) prefix on each line'
      cmd.switch %i[p prefix]

      cmd.desc 'Only show changes of type(s), comma-separated'
      cmd.arg_name 'TYPES'
      cmd.flag %i[only], default_value: 'changed,new,improved,fixed'

      cmd.desc 'Output raw Markdown'
      cmd.switch %i[m md markdown], default_value: false, negatable: false

      cmd.desc 'Force rendered output'
      cmd.switch %i[render], default_value: false, negatable: false

      cmd.desc 'Open changelog in interactive viewer'
      cmd.switch %i[i interactive], default_value: false, negatable: false
    end

    def add_examples(cmd)
      cmd.example 'doing changes', desc: 'View changes in the current version'
      cmd.example 'doing changes --all', desc: 'See the entire changelog'
      cmd.example 'doing changes --lookup 2.0.21', desc: 'See changes from version 2.0.21'
      cmd.example 'doing changes --lookup "> 2.1"', desc: 'See all changes since 2.1.0'
      cmd.example 'doing changes --search "tags +bool"', desc: 'See all changes containing "tags" and "bool"'
      cmd.example 'doing changes -l "> 2.1" -s "pattern"', desc: 'Lookup and search can be combined'
    end
  end
end

desc 'List recent changes in Doing'
long_desc %(Display a formatted list of changes in recent versions.

            Without flags, displays only the most recent version.
            Use --lookup or --all for history.)
command %i[changes changelog] do |c|
  cmd = Doing::ChangesCommand.new
  cmd.add_options(c)
  cmd.add_examples(c)

  c.action do |_global_options, options, _args|
    only = options[:only].split(/ *, */).map(&:normalize_change_type)
    cl = Doing::Changes.new(lookup: options[:lookup],
                            search: options[:search],
                            changes: options[:changes],
                            prefix: options[:prefix],
                            sort: options[:sort],
                            only: only)

    if options[:interactive]
      cl.interactive
    else
      content = if options[:all] || options[:search] || options[:lookup]
                  cl.to_s
                else
                  cl.latest
                end

      parsed = if (options[:markdown] || !$stdout.isatty) && !options[:render]
                 content
               else
                 TTY::Markdown.parse(content, width: 80, theme: MARKDOWN_THEME, symbols: { override: { bullet: '•' } })
               end

      Doing::Pager.paginate = true
      Doing::Pager.page parsed
    end
  end
end