#!/usr/bin/env ruby
# frozen_string_literal: true

require 'optparse'
require 'taskbook/io'

options = { format: 'json', output_format: 'json', min_priority: 1 }
parser = OptionParser.new do |p|
  p.banner = 'Usage: taskbook [filter|stats|export] [options]'
  p.on('--input PATH', 'Input file (default: stdin)') { |v| options[:input] = v }
  p.on('--format FORMAT', %w[json csv]) { |v| options[:format] = v }
  p.on('--output-format FORMAT', %w[json csv]) { |v| options[:output_format] = v }
  p.on('--output PATH', 'Create output; existing paths are rejected') { |v| options[:output] = v }
  p.on('--min-priority N', Integer) { |v| options[:min_priority] = v }
  p.on('--tag TAG') { |v| options[:tag] = v }
  p.on('--status STATUS', %w[todo done]) { |v| options[:status] = { 'todo' => :todo, 'done' => :done }.fetch(v) }
  p.on('-h', '--help') { puts p; exit 0 }
end

begin
  command = ARGV.first&.start_with?('-') ? 'filter' : (ARGV.shift || 'filter')
  raise ArgumentError, 'unknown command' unless %w[filter stats export].include?(command)
  parser.parse!(ARGV)
  raise ArgumentError, 'unexpected arguments' unless ARGV.empty?
  tasks = if options[:input]
            File.open(options[:input], 'rb') { |file| Taskbook::IO.read(file, format: options[:format]) }
          else
            Taskbook::IO.read($stdin, format: options[:format])
          end
  tasks = Taskbook.filter(tasks, min_priority: options[:min_priority], tag: options[:tag], status: options[:status])
  output = command == 'stats' ? JSON.generate(Taskbook.summary(tasks)) + "\n" : Taskbook::IO.dump(tasks, format: options[:output_format])
  if options[:output]
    File.open(options[:output], File::WRONLY | File::CREAT | File::EXCL, 0o600) { |file| file.write(output) }
  else
    $stdout.write(output)
  end
rescue OptionParser::ParseError, ArgumentError => error
  warn "taskbook: #{error.message}"
  exit 2
rescue SystemCallError, IOError
  warn 'taskbook: I/O operation failed'
  exit 3
end
