# frozen_string_literal: true

module Spree
  module Stock
    class AvailabilityValidator < ActiveModel::Validator
      def validate(line_item)
        # OFN specific check for in-memory :skip_stock_check attribute
        return if line_item.skip_stock_check

        quantity_to_validate = line_item.quantity - quantity_in_shipment(line_item)
        return if quantity_to_validate < 1

        validate_quantity(line_item, quantity_to_validate)
      end

      private

      # This is an adapted version of a fix to the inventory_units not being considered here.
      # See #3090 for details.
      # This can be removed after upgrading to Spree 2.4.
      def quantity_in_shipment(line_item)
        shipment = line_item_shipment(line_item)
        return 0 unless shipment

        units = shipment.inventory_units_for(line_item.variant)
        units.count
      end

      def line_item_shipment(line_item)
        return line_item.target_shipment if line_item.target_shipment

        line_item.order.shipments.first if line_item.order&.shipments&.any?
      end

      # Overrides Spree v2.0.4 validate method version to:
      #   - scope variants to hub and thus acivate variant overrides
      #   - use calculated quantity instead of the line_item.quantity
      #   - rely on Variant.can_supply? instead of Stock::Quantified.can_supply?
      #       so that it works correctly for variant overrides
      def validate_quantity(line_item, quantity)
        line_item.scoper.scope(line_item.variant)

        add_out_of_stock_error(line_item) unless line_item.variant.can_supply? quantity
      end

      def add_out_of_stock_error(line_item)
        variant = line_item.variant
        display_name = variant.name.to_s
        display_name += %{(#{variant.options_text})} if variant.options_text.present?
        line_item.errors.add(:quantity, Spree.t(:out_of_stock,
                                                scope: :order_populator,
                                                item: display_name.inspect))
      end
    end
  end
end
