# frozen_string_literal: true

class VoucherAdjustmentsService
  def initialize(order)
    @order = order
  end

  # The tax part of the voucher is stored as explained below:
  # * tax included in price: included_tax field of the voucher adjustment
  # * tax exckuded from price: as an extra voucher adjustment, with label starting by "Tax "
  #
  def update
    return if @order.nil?

    # Find open Voucher Adjustment
    return if @order.voucher_adjustments.empty?

    # We only support one voucher per order right now, we could just loop on voucher_adjustments
    adjustment = @order.voucher_adjustments.first

    # Calculate value
    voucher = adjustment.originator
    amount = voucher.compute_amount(@order)

    # It is quite possible to have an order with both tax included in and tax excluded from price.
    # We should be able to caculate the relevant amount apply the current calculation.
    #
    # For now we just assume it is either all tax included in price or all tax excluded from price.
    if @order.additional_tax_total.positive?
      handle_tax_excluded_from_price(voucher)
    elsif @order.included_tax_total.positive?
      handle_tax_included_in_price(amount, voucher)
    else
      adjustment.amount = amount
      adjustment.save
    end
  end

  def voucher_included_tax
    return 0.0 if @order.voucher_adjustments.empty?

    # We only support one voucher per order for now
    @order.voucher_adjustments.first.included_tax
  end

  def voucher_excluded_tax
    return 0.0 if @order.voucher_adjustments.voucher_tax.empty?

    @order.voucher_adjustments.voucher_tax.first.amount
  end

  private

  def handle_tax_excluded_from_price(voucher)
    voucher_rate = voucher.rate(@order)
    adjustment = @order.voucher_adjustments.first

    # Adding the voucher tax part
    tax_amount = voucher_rate * @order.additional_tax_total

    update_tax_adjustment_for(adjustment, tax_amount)

    # Update the adjustment amount
    adjustment_amount = voucher_rate * (@order.pre_discount_total - @order.additional_tax_total)

    adjustment.update_columns(
      amount: adjustment_amount,
      updated_at: Time.zone.now
    )
  end

  def update_tax_adjustment_for(adjustment, tax_amount)
    adjustment_attributes = {
      originator: adjustment.originator,
      order: @order,
      label: "Tax #{adjustment.label}",
      mandatory: false,
      state: 'open',
      tax_category: nil,
      included_tax: 0
    }

    # Update the amount if tax adjustment already exist, create if not
    tax_adjustment = @order.adjustments.find_or_initialize_by(adjustment_attributes)
    tax_adjustment.amount = tax_amount

    # Add metada so we know which voucher adjustment is Tax related
    tax_adjustment.metadata ||= AdjustmentMetadata.new(
      enterprise: adjustment.originator.enterprise,
      fee_name: "Tax",
      fee_type: "Voucher"
    )

    tax_adjustment.save
  end

  def handle_tax_included_in_price(amount, voucher)
    included_tax = voucher.rate(@order) * @order.included_tax_total

    # Update Adjustment
    adjustment = @order.voucher_adjustments.first

    return unless amount != adjustment.amount || included_tax != 0

    adjustment.update_columns(
      amount:,
      included_tax:,
      updated_at: Time.zone.now
    )
  end
end
