require "singleton"

module T
  class RCFile
    include Singleton
    attr_reader :path

    FILE_NAME = ".trc".freeze

    def initialize
      @path = File.join(File.expand_path("~"), FILE_NAME)
      @data = load_file
    end

    def [](username)
      profiles[find(username)]
    end

    def find(username)
      possibilities = Array(find_case_insensitive_match(username) || find_case_insensitive_possibilities(username))
      raise(ArgumentError.new("Username #{username} is #{possibilities.empty? ? 'not found.' : "ambiguous, matching #{possibilities.join(', ')}"}")) unless possibilities.size == 1

      possibilities.first
    end

    def find_case_insensitive_match(username)
      profiles.keys.detect { |u| username.casecmp(u).zero? }
    end

    def find_case_insensitive_possibilities(username)
      profiles.keys.select { |u| username.casecmp(u[0, username.length]).zero? }
    end

    def []=(username, profile)
      profiles[username] ||= {}
      profiles[username].merge!(profile)
      write
    end

    def configuration
      @data["configuration"]
    end

    def active_consumer_key
      profiles[active_profile[0]][active_profile[1]]["consumer_key"] if active_profile?
    end

    def active_consumer_secret
      profiles[active_profile[0]][active_profile[1]]["consumer_secret"] if active_profile?
    end

    def active_profile
      configuration["default_profile"]
    end

    def active_profile=(profile)
      configuration["default_profile"] = [profile["username"], profile["consumer_key"]]
      write
    end

    def active_secret
      profiles[active_profile[0]][active_profile[1]]["secret"] if active_profile?
    end

    def active_token
      profiles[active_profile[0]][active_profile[1]]["token"] if active_profile?
    end

    def delete
      FileUtils.rm_f(@path)
    end

    def empty?
      @data == default_structure
    end

    def load_file
      require "yaml"
      YAML.load_file(@path)
    rescue Errno::ENOENT
      default_structure
    end

    def path=(path)
      @path = path
      @data = load_file
    end

    def profiles
      @data["profiles"]
    end

    def reset
      send(:initialize)
    end

    def delete_profile(profile)
      profiles.delete(profile)
      write
    end

    def delete_key(profile, key)
      profiles[profile].delete(key)
      write
    end

  private

    def active_profile?
      active_profile && profiles[active_profile[0]] && profiles[active_profile[0]][active_profile[1]]
    end

    def default_structure
      {"configuration" => {}, "profiles" => {}}
    end

    def write
      require "yaml"
      File.open(@path, File::RDWR | File::TRUNC | File::CREAT, 0o0600) do |rcfile|
        rcfile.write @data.to_yaml
      end
    end
  end
end
