#!/usr/bin/ruby

require 'utils'
include Utils
require 'tins/xt'
include Tins::GO
require 'search_ui'
include SearchUI

def edit_files(*paths, pick: false, wait: true)
  editor = Utils::Editor.new
  if pick
    if paths.size > 1
      path = complete(prompt: 'Pick? ') do |p|
        paths.grep /#{p}/
      end
    else
      path = paths.first
    end
    editor.edit(path.strip)
  else
    editor.wait = wait
    editor.edit(*paths)
  end
end

def usage
  puts <<-EOT
Usage: #{File.basename($0)} [OPTS] [PATTERN] [PATHS]

PATTERN is a pattern expression which is find the files. PATHS are the
directory and file paths that are searched.

Options are

  -pX         interpret PATTERN argument as X=r for regexp or X=f for fuzzy
  -r          reset the search index
  -c          disable color output
  -e          open the matching files with edit command
  -E          pick one file to edit
  -a CSET     use only character set CSET from PATTERN
  -iX         use case insensitive matches with X=y (default) or not with X=n
  -I SUFFIX   only include files with suffix SUFFIX during finding
  -d          match also directories
  -D          list all search leaf directories
  -v          be verbose
  -n NUMBER   the first NUMBER of matches is returned
  -s          search by interactively inputting PATTERN
  -h          display this help

Version is #{File.basename($0)} #{Utils::VERSION}.
  EOT
  exit 1
end

args = go 'n:I:i:a:p:creEvdsDh', defaults: { ?a => '\\w' }
args[?h] and usage

Term::ANSIColor.coloring = (STDIN.tty? && ENV['TERM'] !~ /dumb/) && !args[?c]
STDOUT.sync = true
config = Utils::ConfigFile.new
config.configure_from_paths
args[?b] ||= config.discover.binary
args[?n] ||= config.discover.max_matches

if args[?s]
  pattern = ''
else
  pattern = ARGV.shift || ''
end
roots = (ARGV.empty? ? [ Dir.pwd ] : ARGV).map { |f| File.expand_path(f) }

finder = -> * {
  Finder.new(
    :pattern => pattern,
    :args    => args,
    :roots   => roots,
    :config  => config
  )
}

case
when args[?s]
  f = nil
  pattern = pattern.dup
  args[?n] = Term::ANSIColor.terminal_lines - 1
  path = nil
  found = Search.new(
    match: -> answer {
      pattern.replace answer
      f = finder.()
      matches = f.search.output
      matches.first(Tins::Terminal.lines - 1)
    },
    query: -> _answer, matches, selector {
      matches.each_with_index.map { |l, i| (i == selector ? '> ' : '  ') + l }.join(?\n)
    },
    found: -> _answer, matches, selector {
      if f
        path = f.paths[selector]
      end
    },
    output: STDERR
  ).start
  if found
    if args[?e]
      edit_files found, wait: false
    else
      found and puts found
    end
    exit 0
  else
    exit 1
  end
when args[?E]
  edit_files *finder.().paths, pick: true
when args[?e]
  edit_files *finder.().search.paths
when args[?D]
  args[?d] = true
  paths = finder.().load_paths.select { |p| File.directory?(p) }.reverse
  leaf_dirs = []
  until paths.empty?
    path = paths.shift
    unless leaf_dirs.any? { |ld| ld.start_with?(path) }
      leaf_dirs.push path
    end
  end
  puts leaf_dirs
when pattern.empty? && args[?r]
  finder.()
  exit
when pattern.empty?
  usage
else
  puts finder.().search.output
end