class Pdf::Accounting::TransactionReportService < Pdf::NewApplicationService
  include DateRangeHelper

  def initialize(school, params)
    @school = school
    @dates = params['dates']
    @category_ids = params['category_ids']
    @types = params['types']
    @statement_type = params['statement_type']&.to_sym
  end

  private
    def header
      content = ActionController::Base.new.render_to_string(
        partial: 'pdf/headers/school_info.html.haml',
        locals: {
          school: @school,
          side_content_partial: 'pdf/accounting/transaction_report_header',
          side_content: formated_dates
        }
      )
      { content: content, spacing: 25 }
    end

    def body
      ActionController::Base.new.render_to_string(
        partial: 'pdf/accounting/transaction_report.html.haml',
        locals: set_local_variables
      )
    end

    def set_local_variables
      {}.tap do |props|
        props[:statement_type] = @statement_type
        props[:details] = details if [:details, :both].include?(@statement_type)

        if [:summary, :both].include?(@statement_type)
          props[:amounts] = summary
          props[:types] = @types
          props[:totals] = @totals
        end
      end
    end

    def summary
      @totals = { charges: 0, credits: 0, payments: 0, transfer_in: 0, transfer_out: 0 }

      query = transaction_details
        .merge(Accounting::Subcategory.ordered)
        .group_by { |t| t.subcategory.decorate.title }

      keys = query.keys
      keys.map do |key|
        response = { title: key }

        if @types.include?('charge')
          charges = query[key].select do |charge|
            charge.accounting_transaction.action == 'charge'
          end.sum(&:amount)
          @totals[:charges] += charges
          response[:charges] = charges
        end

        if @types.include?('credit')
          credits = query[key].select do |credit|
            credit.accounting_transaction.action == 'credit'
          end.sum(&:amount)
          @totals[:credits] += credits
          response[:credits] = credits
        end

        if @types.include?('payment')
          payments = query[key].select do |payment|
            payment.accounting_transaction.action == 'payment'
          end.sum(&:amount)
          @totals[:payments] += payments
          response[:payments] = payments
        end

        if @types.include?('transfer')
          transfer_in = query[key].select do |transfer|
            transfer.accounting_transaction.action == 'transfer' &&
              !transfer.accounting_transaction.increase?
          end.sum(&:amount)

          @totals[:transfer_in] += transfer_in
          response[:transfer_in] = transfer_in

          transfer_out = query[key].select do |transfer|
            transfer.accounting_transaction.action == 'transfer' &&
              transfer.accounting_transaction.increase?
          end.sum(&:amount)

          @totals[:transfer_out] += transfer_out
          response[:transfer_out] = transfer_out
        end

        response
      end
    end

    def details
      query = transaction_details
        .includes(:student, accounting_transaction: [:family, :payment_detail])
        .merge(Accounting::Transaction.ordered)

      query.map do |detail|
        transaction = detail.accounting_transaction.decorate

        {}.tap do |props|
          props[:date] = transaction.posted_date
          props[:category_memo] = "#{detail.subcategory.decorate.title} - #{transaction.memo}"

          unless transaction.increase? || !transaction.payment?
            props[:payment_details] = transaction.payment_with_currency
          end

          props[:student] = detail.student&.full_name(:reverse)
          props[:family] = transaction.family.name
          props[:amount] = detail.decorate.currency_with_symbol
        end
      end
    end

    def transaction_details
      @school.accounting_transaction_details
        .includes(:accounting_transaction, subcategory: :category)
        .without_void(true)
        .with_subcategory(@category_ids)
        .with_date_range(date_range(@dates))
        .by_actions(@types)
    end

    def subcategories
      @school.accounting_subcategories
    end

    def formated_dates
      dates = @dates.split(',')
      { start: dates.first.to_date, end: dates.last.to_date }
    end
end
