class Admin::Accounting::InvoicesController < Admin::Accounting::Controller
  include DateRangeHelper

  def index
    data = invoices
      .by_family(params[:family_id])
      .by_status(params[:status])
      .by_paid(params[:paid]&.to_bool)

    render_success :ok, json: data.map { |i| invoice_props(i) }
  end

  def show
    render_success :ok, json: invoice_props(invoice)
  end

  def create
    invoice = family.accounting_invoices.build(invoice_params)
    invoice.charges = charges

    if invoice.save
      render_success :ok
    else
      render_error :unprocessible_entity, errors: invoice
    end
  end

  def update
    if invoice.update(invoice_params)
      render_success :ok
    else
      render_error :unprocessable_entity
    end
  end

  def destroy
    if invoice.destroy
      render_success :ok
    else
      render_error :unprocessable_entity
    end
  end

  def attach
    invoice.transaction_charges = (invoice.charges + charge).uniq
    if invoice.save
      render_success :ok, message: 'Charge added to invoice.'
    else
      render_error :unprocessable_entity
    end
  end

  def detach
    invoice.transaction_charges = invoice.charges - charge
    if invoice.save
      render_success :ok, message: 'Charge removed from invoice.'
    else
      render_error :unprocessable_entity
    end
  end

  def batch_create
    invoices = []

    charges.group_by(&:family).each do |family, charges|
      invoice = family.accounting_invoices.build(invoice_params)
      invoice.charges = charges
      invoices << invoice
    end

    if transactional_save(invoices)
      render_success :ok, message: "#{invoices.count} invoices created"
    else
      render_error :unprocessable_entity, errors: invoices.first
    end
  end

  def batch_update
    to_update = invoices.where(id: params[:ids]).each { |i| i.status = params[:status] }
    count = to_update.count
    action = params[:status] == 'shared' ? 'shared' : 'un-shared'

    if transactional_save(to_update)
      render_success :ok, message: "#{count} invoices #{action}."
    else
      render_error :unprocessable_entity
    end
  end

  def batch_delete
    to_delete = invoices.where(id: params[:ids])
    count = to_delete.count

    if transactional_destroy(to_delete)
      render_success :ok, message: "#{count} transactions deleted."
    else
      render_error :unprocessable_entity
    end
  end

  def pdf
    Reporting::Accounting::InvoicesJob.perform_async(
      current_school.id,
      current_user.id,
      invoice_ids: params[:ids]
    )
  end

  private
    def invoices
      current_school.accounting_invoices
    end

    def invoice
      @invoice ||= invoices.find_by(id: params[:id])
    end

    def family
      @family ||= current_school.families.find_by(id: params[:family_id])
    end

    def set_tracking_number
      return {} if action_name == 'update'

      @tracking_number ||= current_school.accounting_invoices.last_generated_tracking_number
      @tracking_number += 1

      { tracking_number: @tracking_number }
    end

    def charges
      @charges ||= current_school.accounting_increases
        .left_joins(:invoice_charge)
        .includes(:family, :subcategories)
        .with_families(params[:family_id] || params[:family_ids])
        .with_date_range(date_range(params[:dates]))
        .without_void(true)
        .with_categories(params[:category_ids])
        .with_unattached_charges
        .charge
    end

    def charge
      @charge ||= current_school.accounting_increases.charge.where(id: params[:charge_id])
    end

    def invoice_params
      params.permit(:status, :posted_on, :due_date).merge(set_tracking_number)
    end

    def invoice_props(invoice)
      {
        id: invoice.id,
        family_name: invoice.family.name,
        family_id: invoice.family.id,
        tracking_number: invoice.tracking_number,
        posted_on: invoice.posted_on,
        due_date: invoice.due_date,
        status: invoice.decorate.status,
        total: invoice.decorate.total,
        paid: invoice.decorate.paid,
        balance: invoice.decorate.balance
      }
    end
end
