# frozen_string_literal: true

# Provides helper methods for Subscription actions
class Subscriptions::Subscribe
  attr_accessor :user_id, :operator_profile_id

  def initialize(operator_profile_id, user_id = nil)
    @user_id = user_id
    @operator_profile_id = operator_profile_id
  end

  ##
  # @param subscription {Subscription}
  # @param payment_details {Hash} as generated by Price.compute
  # @param intent_id {String} from stripe
  # @param schedule {Boolean}
  # @param payment_method {String} only for schedules
  ##
  def pay_and_save(subscription, payment_details: nil, intent_id: nil, schedule: false, payment_method: nil)
    return false if user_id.nil?

    user = User.find(user_id)
    subscription.statistic_profile_id = StatisticProfile.find_by(user_id: user_id).id

    ActiveRecord::Base.transaction do
      subscription.init_save
      raise InvalidSubscriptionError unless subscription&.persisted?

      payment = if schedule
                  generate_schedule(subscription: subscription,
                                    total: payment_details[:before_coupon],
                                    operator_profile_id: operator_profile_id,
                                    user: user,
                                    payment_method: payment_method,
                                    coupon: payment_details[:coupon],
                                    setup_intent_id: intent_id)
                else
                  generate_invoice(subscription, operator_profile_id, payment_details, intent_id)
                end
      WalletService.debit_user_wallet(payment, user, subscription)
      payment.save
      payment.post_save(intent_id)
    end
    true
  end

  def extend_subscription(subscription, new_expiration_date, free_days)
    return subscription.free_extend(new_expiration_date, @operator_profile_id) if free_days

    new_sub = Subscription.create(
      plan_id: subscription.plan_id,
      statistic_profile_id: subscription.statistic_profile_id,
      expiration_date: new_expiration_date
    )
    if new_sub.save
      schedule = subscription.original_payment_schedule
      details = Price.compute(true, new_sub.user, nil, [], plan_id: subscription.plan_id)
      payment = if schedule
                  generate_schedule(subscription: new_sub,
                                    total: details[:before_coupon],
                                    operator_profile_id: operator_profile_id,
                                    user: new_sub.user,
                                    payment_method: schedule.payment_method,
                                    setup_intent_id: schedule.stp_setup_intent_id)
                else
                  generate_invoice(subscription, operator_profile_id, details)
                end
      payment.save
      payment.post_save(schedule&.stp_setup_intent_id)
      UsersCredits::Manager.new(user: new_sub.user).reset_credits
      return new_sub
    end
    false
  end

  private

  ##
  # Generate the invoice for the given subscription
  ##
  def generate_schedule(subscription: nil, total: nil, operator_profile_id: nil, user: nil, payment_method: nil, coupon: nil,
                        setup_intent_id: nil)
    operator = InvoicingProfile.find(operator_profile_id)&.user

    PaymentScheduleService.new.create(
      subscription,
      total,
      coupon: coupon,
      operator: operator,
      payment_method: payment_method,
      user: user,
      setup_intent_id: setup_intent_id
    )
  end

  ##
  # Generate the invoice for the given subscription
  ##
  def generate_invoice(subscription, operator_profile_id, payment_details, payment_intent_id = nil)
    InvoicesService.create(
      payment_details,
      operator_profile_id,
      subscription: subscription,
      payment_intent_id: payment_intent_id
    )
  end

end
