require 'input_reader'
require 'rails/generators'

# Extra require so generator can be used in rake task
require 'right_on/generators/right_migration_generator'

module RightOn
  class RightsManager
    class << self

      def controllers
        controllers_path = File.join("#{Rails.root}",'app','controllers')
        controllers_suffix = '_controller.rb'
        controllers_files = File.join(controllers_path, '**', '*' + controllers_suffix)
        Dir[controllers_files].map do |f|
          [File.dirname(f)[(controllers_path.length + 1)..-1],
            File.basename(f,controllers_suffix)].compact.join('/')
        end
      end


      def missing_rights
        rights = Right.all.map(&:controller)
        controllers.reject { |c| rights.include?(c) }
      end


      def add_right(options = {})
        options = parse_right_options(options)
        add_and_run_right_migration(options)
        add_right_fixture(options)
        puts "Added right #{options[:name]}"
        add_right if options[:unattended].blank? && InputReader.get_boolean(:prompt => "Add another right?(Y/N)")
      end


      def add_right_record(options = {})
        unless Right.find_by_name(options[:name])
          Right.create(options.slice(:controller, :action, :name, :roles))
        end
      end


      # Converts options from {:key => 'value', :key2 => 'value2', :blank => ''}
      # to "--key=value --key2=value2" (Notice how blank is not included)
      def build_unix_options(options = {})
        options.select{|k,v| v.present?}.map do |key, value|
          "--#{key}=#{value}"
        end
      end


      def add_right_migration(options = {})
        migration_options = options.slice(:controller, :action, :right)
        puts options.inspect
        puts "#{options[:name]} #{build_unix_options(migration_options)}"
        migration_file = Rails::Generators.invoke("right_on:right_migration",
          [options[:name]] + build_unix_options(migration_options)
        )
        raise "Could not generate migration" unless migration_file.present?
        migration_file.first
      end


      def add_and_run_right_migration(options = {})
        migration_file = add_right_migration(options)
        ENV['VERSION'] = File.basename(migration_file).split('_').first
        Rake::Task['db:migrate:up'].invoke
        ENV.delete 'VERSION'
        true
      end


      def add_right_fixture(options = {})
        right_roles_yaml_path = File.join("#{Rails.root}",'db','fixtures','rights_roles.yml')
        right_roles = YAML::load_file(right_roles_yaml_path)

        group = options[:group].presence || options[:controller]

        right_roles['rights'][group] ||= []
        right_roles['rights'][group].delete(options[:controller])

        right = right_roles['rights'][group].find do |right|
          right.is_a?(Hash) && right.keys.include?(options[:controller])
        end

        if options[:action].present?
          right ||= (right_roles['rights'][group] << {}).last
          right[options[:controller]] ||= []
          right[options[:controller]] << options[:action] unless right[options[:controller]].include?(options[:action])
        elsif !right
          right_roles['rights'][group] << options[:controller]
        end

        options[:bootstrap_roles].each do |role_title|
          (right_roles['roles'][role_title] || []) << [options[:controller].presence,options[:action].presence].compact.join("#")
        end

        File.open(right_roles_yaml_path, "w") do |f|
          f.write(right_roles.to_yaml)
        end

        true
      end


      private

      def parse_right_options(options = {})
        parsed_options = {}

        parsed_options[:controller] = options[:controller].presence ||
          InputReader.select_item(missing_rights, :prompt => "Right:", :allow_blank => true) ||
          InputReader.get_string(:allow_blank => false, :prompt => "Controller:")

        parsed_options[:action] = options[:action].presence ||
          InputReader.get_string(:allow_blank => true, :prompt => "Action:")

        parsed_options[:name] = options[:name].presence ||
          InputReader.get_string(:allow_blank => true, :prompt => "Name:") ||
          [parsed_options[:controller].presence, parsed_options[:action].presence].compact.join('#')

        parsed_options[:group] = options[:group].presence ||
          InputReader.get_string(:allow_blank => true, :prompt => "Group:")

        parsed_options[:right] = options[:right].presence ||
          InputReader.select_item(Right.all, :selection_attribute => :name, :allow_blank => true, :prompt => "Assign new right to anyone with right:").name

        right_roles_yaml_path = File.join("#{Rails.root}",'db','fixtures','rights_roles.yml')
        right_roles = YAML::load_file(right_roles_yaml_path)
        bootstrap_roles = right_roles['roles'].keys
        parsed_options[:bootstrap_roles] = options[:bootstrap_role].presence ||
          InputReader.select_items(bootstrap_roles, :allow_blank => true, :prompt => "Assign to which bootstrap roles:")

        parsed_options
      end

    end
  end
end
