module Billing
  module Stripe
    # Allinea piano locale quando scatta un downgrade programmato (o dopo sync Stripe).
    class ApplyPendingPlan
      def self.call(club:)
        new(club: club).call
      end

      def initialize(club:)
        @club = club
        @sub = club.subscription
      end

      def call
        return false unless @sub&.pending_plan_id.present?

        pending_slug = @sub.pending_plan.slug
        interval = @sub.pending_billing_interval.presence || @sub.billing_interval

        if @sub.stripe_subscription_id.present?
          stripe_sub = ::Stripe::Subscription.retrieve(@sub.stripe_subscription_id)
          current_price_id = stripe_sub.items.data.first.price.id
          expected_price_id = PriceCatalog.price_id(plan_slug: pending_slug, interval: interval)
          return false unless current_price_id == expected_price_id

          inferred = PriceCatalog.infer_from_price_id(current_price_id)
          if inferred
            pending_slug, interval = inferred
          end
          period_start, period_end = SubscriptionPeriod.times(stripe_sub)
          Billing::AssignPlan.call(
            club: @club,
            plan_slug: pending_slug,
            status: map_status(stripe_sub.status),
            stripe_attrs: {
              stripe_customer_id: stripe_sub.customer,
              stripe_subscription_id: stripe_sub.id,
              current_period_start: period_start,
              current_period_end: period_end,
              cancel_at_period_end: stripe_sub.cancel_at_period_end,
              billing_interval: interval,
              pending_plan_id: nil,
              pending_billing_interval: nil,
              stripe_schedule_id: nil
            }
          )
        else
          Billing::AssignPlan.call(
            club: @club,
            plan_slug: pending_slug,
            stripe_attrs: {
              billing_interval: interval,
              pending_plan_id: nil,
              pending_billing_interval: nil,
              stripe_schedule_id: nil
            }
          )
        end

        true
      end

      private

      def map_status(stripe_status)
        case stripe_status
        when "trialing" then "trialing"
        when "active" then "active"
        when "past_due", "unpaid" then "past_due"
        when "canceled", "incomplete_expired" then "canceled"
        else "incomplete"
        end
      end
    end
  end
end
