require "English"

module OnePass
  # OnePass Application
  class Application
    CONFIG_PATH = '~/.one_pass'.freeze

    def initialize(vault_path = nil)
      @vault_path = get_vault vault_path
      @vault = OpVault.new @vault_path

      check_for_dependencies
      prompter = OnePass::Password.new(vault_path: @vault_path)
      password_loop prompter
    ensure
      prompter && prompter.done
    end

    def check_for_dependencies
      unless installed? 'pinentry --version'
        puts 'Please install the `pinentry` program.'
        puts '  on macOS, we recommend using Homebrew: `brew install pinentry`.'
        exit 127
      end
    end

    def password_loop(prompter)
      error_message = nil
      loop do
        password = prompter.prompt error_message
        exit if password.nil? # cancelled
        begin
          @vault.unlock password && @vault.load_items
          break
        rescue => error
          error_message = error.message
        end
      end
    end

    def get_vault(vault_path = nil)
      return vault_path if vault_path
      path = File.expand_path CONFIG_PATH
      raise 'Config file missing, please log in' unless File.exist? path

      config = File.read path
      raise 'Config file error' unless config.start_with? 'path='
      config[5..-1].strip
    end

    def show(query, reply_type)
      item = @vault.find(/#{query}/i).first
      data = @vault.item_overview item
      unless %i( uuid url title ).include? reply_type
        data.merge!(@vault.item_detail(item))
      end

      case reply_type
      when %i( uuid url title )
        data[reply_type.to_s]
      when :username
        data['fields'].find({}) { |field| field['designation'] == 'username' }['value']
      when :password
        data['fields'].find({}) { |field| field['designation'] == 'password' }['value']
      else
        data
      end
    end

    def search(query)
      @vault.find(/#{query}/i).collect do |item|
        data = (@vault.item_overview item).merge(@vault.item_detail(item))
        {
          uuid: data['uuid'],
          title: data['title'],
          username: data['fields'].find({}) do |field|
            field['designation'] == 'username'
          end['value']
        }
      end
    end

    def installed?(program)
      `#{program}`
      result = $CHILD_STATUS
      result.exitstatus != 127
    end

    def self.save(vault_path = nil)
      new vault_path # if succeeds, path & pw is good
      path = File.expand_path CONFIG_PATH
      File.open path, File::CREAT | File::TRUNC | File::RDWR do |file|
        file.write "path=#{File.expand_path vault_path}\n"
      end
    end

    def self.forget
      path = File.expand_path CONFIG_PATH
      File.delete path if File.exist? path
    end
  end
end