# frozen_string_literal: true

module ForemanAnsible
  module Api
    module V2
      # Extends the hostgroups controller to support playing ansible roles
      module HostgroupsControllerExtensions
        extend ActiveSupport::Concern
        include ForemanTasks::Triggers
        include ::ForemanAnsible::Concerns::JobInvocationHelper
        include ::ForemanAnsible::Concerns::ApiCommon

        # Included blocks shouldn't be bound by length, as otherwise concerns
        # cannot extend the method properly.
        # rubocop:disable Rails/LexicallyScopedActionFilter
        included do
          before_action :find_ansible_roles, :only => [:assign_ansible_roles]
          before_action :find_hostgroup_ansible_role, :only => [:add_ansible_role, :remove_ansible_role]

          api :POST, '/hostgroups/:id/play_roles',
              N_('Runs all Ansible roles on a hostgroup')
          param :id, :identifier, :required => true

          def play_roles
            find_resource
            composer = job_composer(:ansible_run_host, @hostgroup.hosts)
            process_response composer.trigger!, composer.job_invocation
          end

          api :POST, '/hostgroups/multiple_play_roles',
              N_('Runs all Ansible roles on hostgroups')
          param :hostgroup_ids, Array, N_('IDs of hostgroups to play roles on'),
                :required => true

          def multiple_play_roles
            find_multiple
            composer = job_composer(:ansible_run_host,
                                    @hostgroups.map(&:host_ids).flatten.uniq)
            process_response composer.trigger!, composer.job_invocation
          end

          api :GET, '/hostgroups/:id/ansible_roles',
              N_('List all Ansible roles for a hostgroup')
          param :id, :identifier, :required => true

          def ansible_roles
            find_resource
            return unless @hostgroup

            @inherited_ansible_roles = @hostgroup.inherited_ansible_roles
            @directly_assigned_roles = @hostgroup.ansible_roles
            @ansible_roles = (
              @directly_assigned_roles + @inherited_ansible_roles
            ).uniq
          end

          api :POST, '/hostgroups/:id/assign_ansible_roles',
              N_('Assigns Ansible roles to a hostgroup')
          param :id, :identifier, :required => true
          param :ansible_role_ids, Array,
                N_('Ansible roles to assign to a hostgroup'),
                :required => true

          def assign_ansible_roles
            find_resource
            process_response @hostgroup.update(:ansible_roles => @ansible_roles)
          end

          api :PUT, '/hostgroups/:id/ansible_roles/:ansible_role_id',
              N_('Directly add an Ansible role to a hostgroup')
          param :id, :identifier, :required => true
          param :ansible_role_id, :identifier,
                N_('Ansible role to add to a hostgroup'),
                :required => true

          def add_ansible_role
            process_response @hostgroup.ansible_roles << @ansible_role
          rescue ActiveRecord::RecordInvalid => e
            render_exception(e, :status => :unprocessable_entity)
          end

          api :DELETE, '/hostgroups/:id/ansible_roles/:ansible_role_id',
              N_('Remove directly assigned Ansible role from a hostgroup')
          param :id, :identifier, :required => true
          param :ansible_role_id, :identifier,
                N_('Ansible role to remove from a hostgroup'),
                :required => true

          def remove_ansible_role
            process_response @hostgroup.ansible_roles.delete(@ansible_role)
          end
        end
        # rubocop:enable Rails/LexicallyScopedActionFilter

        private

        def find_multiple
          hostgroup_ids = params.fetch(:hostgroup_ids, [])
          hostgroup_names = params.fetch(:hostgroup_names, [])

          @hostgroups = []
          hostgroup_ids.uniq.each do |hostgroup_id|
            @hostgroups.append(Hostgroup.find(hostgroup_id))
          end
          hostgroup_names.uniq.each do |hostgroup_name|
            @hostgroups.append(Hostgroup.find_by(:name => hostgroup_name))
          end
        end

        def action_permission
          case params[:action]
          when 'play_roles', 'multiple_play_roles', 'ansible_roles',
               'assign_ansible_roles'
            :view
          when 'add_ansible_role', 'remove_ansible_role'
            :edit
          else
            super
          end
        end
      end
    end
  end
end