class BaseBatchesController < ApplicationController
  before_action :set_batch, except: %i[ index new create ]
  before_action :setup_csv_fields, only: %i[ map_fields set_mapping ]

  REQUIRED_FIELDS = %w[first_name line_1 city state postal_code country].freeze
  PREVIEW_ROWS = 3

  # GET /batches/1 or /batches/1.json
  def show
    authorize @batch
  end

  # GET /batches/1/edit
  def edit
    authorize @batch
  end

  # PATCH/PUT /batches/1 or /batches/1.json
  def update
    authorize @batch
    respond_to do |format|
      if @batch.update(batch_params)
        format.html { redirect_to @batch, notice: "Batch was successfully updated." }
        format.json { render :show, status: :ok, location: @batch }
      else
        format.html { render :edit, status: :unprocessable_entity }
        format.json { render json: @batch.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /batches/1 or /batches/1.json
  def destroy
    authorize @batch
    @batch.destroy!

    respond_to do |format|
      format.html { redirect_to batches_path, status: :see_other, notice: "Batch was successfully destroyed." }
      format.json { head :no_content }
    end
  end

  def map_fields
    authorize @batch, :map_fields?
  end

  def set_mapping
    authorize @batch, :set_mapping?
    mapping = mapping_params.to_h

    # Invert the mapping to get from CSV columns to address fields
    inverted_mapping = mapping.invert

    # Validate required fields
    missing_fields = REQUIRED_FIELDS.reject { |field| inverted_mapping[field].present? }

    if missing_fields.any?
      flash.now[:error] = "Please map the following required fields: #{missing_fields.join(", ")}"
      render :map_fields, status: :unprocessable_entity
      return
    end

    if @batch.update!(field_mapping: inverted_mapping)
      begin
        @batch.run_map!
      rescue StandardError => e
        Rails.logger.warn(e)
        event_id = Sentry.capture_exception(e)&.event_id
        redirect_to send("#{@batch.class.name.split("::").first.downcase}_batch_path", @batch), flash: { alert: "error mapping fields! #{e.message} (error: #{event_id})" }
        return
      end
      redirect_to send("process_confirm_#{@batch.class.name.split("::").first.downcase}_batch_path", @batch), notice: "Field mapping saved. Please review and process your batch."
    else
      flash.now[:error] = "failed to save field mapping. #{@batch.errors.full_messages.join(", ")}"
      render :map_fields, status: :unprocessable_entity
    end
  end

  private

  def set_batch
    @batch = Batch.find(params[:id])
  end

  def setup_csv_fields
    csv_rows = CSV.parse(@batch.csv_data)
    @csv_headers = csv_rows.first
    @csv_preview = csv_rows[1..PREVIEW_ROWS] || []

    # Get fields based on batch type
    @address_fields = if @batch.is_a?(Letter::Batch)
        # For letter batches, include address fields and rubber_stamps
        (Address.column_names - ["id", "created_at", "updated_at", "batch_id"]) +
          ["rubber_stamps"]
      else
        # For other batches, just include address fields
        (Address.column_names - ["id", "created_at", "updated_at"])
      end
  end

  def mapping_params
    params.require(:mapping).permit!
  end
end
