class WorkflowInstancesController < ApplicationController
  before_action :set_record, only: [:show, :edit, :update, :destroy, :reset]
  before_action :set_collection, only: [:collection_edit, :collection_update, :uncategorize]
  delegate :record_class, :record_batch_class, to: :class
  alias_method :workflow_instance_class, :record_class

  respond_to :html, :csv

  def index
    authorize! :read, record_class
    set_records_for_index
    respond_to do |format|
      format.html do
        @records = @records.page(params[:page]).per(params[:per_page]).decorate
      end
      format.csv { respond_with @records, record_class: record_class, include_notes: params[:include_notes] }
    end
  end

  def show
    authorize! :read, @record
    @record = @record.decorate
    respond_with(@record)
  end

  def collection_edit
    authorize! :read, record_class # not update, since this read can have multiple update authorizations
    redirect_to record_class and return unless @collection.any?
    if params[:reveal].present?
      render layout: false # popup
    end
  end

  # This is a custom reporting action where an extra filter
  # is applied to the full index scope.
  # reports
  def with_bas_correction
    authorize! :read, record_class
    set_records_for_index
    @records = @records.where(data_corrected_by_bas_data: true).decorate
    respond_to do |format|
      format.html { render action: :selection }
      format.csv { respond_with @records, record_class: record_class, include_notes: params[:include_notes] }
    end
  end

  # reports
  def with_incomplete_bas_records
    authorize! :read, record_class
    set_records_for_index
    @records = @records.with_incomplete_bas_records.decorate
    respond_to do |format|
      format.html do
        redirect_to :back, notice: "There are no incompletely enriched DSLAMs" and return unless @records.any?
        render action: :selection
      end
      format.csv { respond_with @records, record_class: record_class, include_notes: params[:include_notes] }
    end
  end

  def collection_update
    authorize! :update, record_class
    if @collection.update params[:collection]
      redirect_to polymorphic_path([:selection, record_class],  ids: @collection.ids)
    else
      render "collection_edit"
    end
  end

  def reset
    authorize! :reset, @record
    @record.reset!
    redirect_to @record
  end

  # POST /records/selection input=EAP/123; ...ETC....
  def selection
    authorize! :read, record_class unless record_class == WorkflowInstance
    respond_to do |format|
      format.html do
        @records = find_records_by_ids_or_input decorate: true
      end
      format.csv do
        @records = find_records_by_ids_or_input
        respond_with @records, record_class: record_class, include_notes: params[:include_notes]
      end
    end
  end

  #def edit
  #  authorize! :edit, @record
  #  #@record = @record.decorate
  #  @collection = record_class.collection.new([@record])
  #  render template: 'workflow_instances/collection_edit'
  #  #respond_with(@record)
  #end

  #def update
  #  authorize! :update, @record
  #  @record.update(record_params)
  #  respond_with(@record)
  #end

  #def destroy
  #  authorize! :destroy, @record
  #  @record.destroy
  #  respond_with(@record)
  #end

  private

  def set_records_for_index
    @q = records_scope.search(query)
    @q.sorts = "state asc" if @q.sorts.empty?
    @records = @q.result.including_relations
  end

  def set_record
    scope = record_class.scope_for(current_user, all: can?(:archive, record_class))
    @record = scope.find(params[:id])
  end

  def set_collection
    if params[:workflow_instance_batch_id].present?
      @workflow_instance_batch = WorkflowInstanceBatch.find(params[:workflow_instance_batch_id])
      @collection = record_class.collection.new(@workflow_instance_batch.workflow_instances)
    else
      @collection = record_class.collection.new(records_scope(all: can?(:read, :archived_records)).includes(:workflow_instance_batch).where(id: ids_param))
    end
  end

  def records_scope(scope_options = {})
    scope_options[:archived] = session[:archived_mode] if can?(:archive, record_class) and not scope_options[:all].present?
    record_class.scope_for(current_user, scope_options)
  end

  # Used for the dslam_name actions
  # The search is used for sorting, not for actual filtering
  def find_records_by_ids_or_input(options = {})
    @q = records_scope(all: can?(:archive, record_class)).search(query)
    @q.sorts = "state asc" if @q.sorts.empty?
    records = apply_record_input_scope.including_relations
    options[:decorate] ? records.decorate : records
  end

  # Apply scope to query by means of given ids or eap input
  def apply_record_input_scope
    return @q.result.where(id: ids_param) if ids_param.present? # use ids param if supplied
    return @q.result.where(workflow_instance_batch_id: params[:workflow_instance_batch_id]) if params[:workflow_instance_batch_id].present?
    input = WorkflowInstanceInputScrubber.new( params[:input] )
    selection = @q.result.where dslam_name: input.dslam_names
    params[:ids] = selection.pluck(:id)
    selection
  end

  def query
    params[:q]
  end

  class << self
    def record_class
      return @record_class if @record_class
      parts = controller_path.split('/').map(&:classify)
      parts.pop until klass = parts.join('::').safe_constantize
      @record_class = klass
    end

    def record_batch_class
      return @record_batch_class if @record_batch_class
      @record_batch_class = record_class.try(:batch_class)
    end
  end
  helper_method :record_class
  helper_method :record_batch_class
end
