# frozen_string_literal: true

# Provides methods to create new cart items, based on an existing Order
class Cart::CreateCartItemService
  def initialize(order)
    raise Cart::AnonymousError, I18n.t('cart_validation.select_user') if order.statistic_profile.nil? || order.operator_profile.nil?

    @order = order
    @customer = order.user
    @operator = order.operator_profile.user
  end

  def create(item)
    key = item.keys.filter { |k| %w[subscription reservation prepaid_pack free_extension].include?(k) }.first
    case key
    when 'subscription', :subscription
      subscription = create_subscription(item.require(:subscription).permit!)
      update_reservations(subscription)
      subscription
    when 'reservation', :reservation
      create_reservation(item.require(:reservation).permit!)
    when 'prepaid_pack', :prepaid_pack
      create_prepaid_pack(item.require(:prepaid_pack).permit!)
    when 'free_extension', :free_extension
      create_free_extension(item.require(:free_extension).permit!)
    else
      raise NotImplementedError, "unknown item type #{item.keys.first}"
    end
  end

  private

  def create_subscription(cart_item)
    CartItem::Subscription.new(
      plan: Plan.find(cart_item[:plan_id]),
      customer_profile: @customer.invoicing_profile,
      start_at: cart_item[:start_at]
    )
  end

  def update_reservations(new_subscription)
    @order.order_items
          .where(orderable_type: %w[CartItem::MachineReservation CartItem::SpaceReservation CartItem::TrainingReservation])
          .find_each do |reserv|
      reserv.update(plan: new_subscription.plan, new_subscription: true)
    end
  end

  def create_reservation(cart_item)
    plan_info = subscription_info
    reservable = cart_item[:reservable_type]&.constantize&.find(cart_item[:reservable_id])
    case reservable
    when Machine
      CartItem::MachineReservation.new(customer_profile: @customer.invoicing_profile,
                                       operator_profile: @operator.invoicing_profile,
                                       reservable: reservable,
                                       cart_item_reservation_slots_attributes: cart_item[:slots_reservations_attributes],
                                       plan: plan_info[:subscription]&.plan,
                                       new_subscription: plan_info[:new_subscription])
    when Training
      CartItem::TrainingReservation.new(customer_profile: @customer.invoicing_profile,
                                        operator_profile: @operator.invoicing_profile,
                                        reservable: reservable,
                                        cart_item_reservation_slots_attributes: cart_item[:slots_reservations_attributes],
                                        plan: plan_info[:subscription]&.plan,
                                        new_subscription: plan_info[:new_subscription])
    when Event
      CartItem::EventReservation.new(customer_profile: @customer.invoicing_profile,
                                     operator_profile: @operator.invoicing_profile,
                                     event: reservable,
                                     cart_item_reservation_slots_attributes: cart_item[:slots_reservations_attributes],
                                     normal_tickets: cart_item[:nb_reserve_places],
                                     cart_item_event_reservation_tickets_attributes: cart_item[:tickets_attributes] || {})
    when Space
      CartItem::SpaceReservation.new(customer_profile: @customer.invoicing_profile,
                                     operator_profile: @operator.invoicing_profile,
                                     reservable: reservable,
                                     cart_item_reservation_slots_attributes: cart_item[:slots_reservations_attributes],
                                     plan: plan_info[:subscription]&.plan,
                                     new_subscription: plan_info[:new_subscription])
    else
      raise NotImplementedError, "unknown reservable type #{reservable}"
    end
  end

  def create_prepaid_pack(cart_item)
    CartItem::PrepaidPack.new(
      prepaid_pack: PrepaidPack.find(cart_item[:id]),
      customer_profile: @customer.invoicing_profile
    )
  end

  def create_free_extension(cart_item)
    plan_info = subscription_info
    CartItem::FreeExtension.new(
      customer_profile: @customer.invoicing_profile,
      subscription: plan_info[:subscription],
      new_expiration_date: cart_item[:end_at]
    )
  end

  def subscription_info
    cart_subscription = @order.order_items.find_by(orderable_type: 'CartItem::Subscription')
    if cart_subscription
      { subscription: cart_subscription, new_subscription: true }
    elsif @customer.subscribed_plan
      { subscription: @customer.subscription, new_subscription: false } unless @customer.subscription.expired_at < Time.current
    else
      { subscription: nil, new_subscription: false }
    end
  end
end
