require 'zip'

class ReportsController < ApplicationController
  before_action :authenticate_user!

  layout "report"

  def user_list
    @members = report_collection("Member")

    report_responder('Member', current_organization, @members)
  end

  def post_list
    @post_type = (params[:type] || "offer").capitalize.constantize
    @posts = report_collection(@post_type)

    report_responder('Post', current_organization, @posts, @post_type)
  end

  def transfer_list
    @transfers = report_collection('Transfer')

    report_responder('Transfer', current_organization, @transfers)
  end

  def download_all
    filename = "#{current_organization.name.parameterize}_#{Date.today}.zip"
    temp_file = Tempfile.new(filename)

    begin
      Zip::File.open(temp_file.path, Zip::File::CREATE) do |zipfile|
        %w(Member Transfer Inquiry Offer).each do |report_class|
          add_csv_to_zip(report_class, zipfile)
        end
      end
      zip_data = File.read(temp_file.path)
      send_data(zip_data, type: 'application/zip', disposition: 'attachment', filename: filename)
    rescue Errno::ENOENT
      redirect_to download_all_report_path
    ensure
      temp_file.close
      temp_file.unlink
    end
  end

  private

  def report_responder(report_class, *args)
    respond_to do |format|
      format.html
      format.csv { download_report("Csv::#{report_class}", *args) }
      format.pdf { download_report("Pdf::#{report_class}", *args) }
    end
  end

  def download_report(report_class, *args)
    report = get_report(report_class, *args)
    send_data report.run, filename: report.name, type: report.mime_type
  end

  def get_report(report_class, *args)
    "Report::#{report_class}".constantize.new(*args)
  end

  def report_collection(report_class)
    case report_class.to_s
    when 'Member'
      current_organization.members.active.includes(:user).order('members.member_uid')
    when 'Transfer'
      current_organization.all_transfers_with_accounts
    when 'Inquiry', 'Offer'
      report_class = report_class.constantize if report_class.is_a?(String)

      current_organization.posts.of_active_members.active.
        merge(report_class.all).
        includes(:user, :category).
        group_by(&:category).
        sort_by { |category, _| category.try(:name).to_s }
    end
  end

  def add_csv_to_zip(report_class, zip)
    collection = report_collection(report_class)

    report = if report_class.in? %w(Inquiry Offer)
      get_report("Csv::Post", current_organization, collection, report_class.constantize)
    else
      get_report("Csv::#{report_class}", current_organization, collection)
    end

    file = Tempfile.new
    file.write(report.run)
    file.rewind

    zip.add("#{report_class.pluralize}_#{Date.today}.csv", file.path)
  end
end
