module Billing
  class AdminCompedSubscription
    class Error < StandardError; end

    VALID_PLANS = %w[premium_light premium_full].freeze

    def self.grant(club:, plan_slug:, reason:, admin:)
      new(club: club, plan_slug: plan_slug, reason: reason, admin: admin).grant
    end

    def self.revoke(club:, admin:)
      new(club: club, admin: admin).revoke
    end

    def initialize(club:, plan_slug: nil, reason: nil, admin: nil)
      @club = club
      @plan_slug = plan_slug.to_s.presence
      @reason = reason.to_s.strip.presence
      @admin = admin
    end

    def grant
      raise Error, "Piano non valido" unless @plan_slug.in?(VALID_PLANS)

      release_stripe_schedule!

      AssignPlan.call(
        club: @club,
        plan_slug: @plan_slug,
        status: "active",
        stripe_attrs: comped_attrs.merge(
          pending_plan_id: nil,
          pending_billing_interval: nil,
          stripe_schedule_id: nil,
          cancel_at_period_end: false
        )
      )
    end

    def revoke
      sub = @club.subscription
      raise Error, "Nessun abbonamento omaggio attivo" unless sub&.admin_comped?

      if sub.stripe_subscription_id.present? && MatchLiveTv.stripe_enabled?
        stripe_sub = ::Stripe::Subscription.retrieve(sub.stripe_subscription_id)
        if stripe_sub.status.in?(%w[active trialing past_due])
          Billing::Stripe::CheckoutSync.from_subscription(stripe_sub, club: @club)
          clear_comped_flags!(sub.reload)
          return sub
        end
      end

      AssignPlan.call(
        club: @club,
        plan_slug: "free",
        status: "active",
        stripe_attrs: {
          admin_comped: false,
          admin_comped_reason: nil,
          admin_comped_at: nil,
          admin_comped_by_id: nil,
          pending_plan_id: nil,
          pending_billing_interval: nil,
          stripe_schedule_id: nil
        }
      )
    end

    private

    def comped_attrs
      {
        admin_comped: true,
        admin_comped_reason: @reason,
        admin_comped_at: Time.current,
        admin_comped_by_id: @admin&.id
      }
    end

    def clear_comped_flags!(sub)
      sub.update!(
        admin_comped: false,
        admin_comped_reason: nil,
        admin_comped_at: nil,
        admin_comped_by_id: nil
      )
    end

    def release_stripe_schedule!
      sub = @club.subscription
      return if sub.blank? || sub.stripe_schedule_id.blank?
      return unless MatchLiveTv.stripe_enabled?

      ::Stripe::SubscriptionSchedule.release(sub.stripe_schedule_id)
    rescue ::Stripe::InvalidRequestError
      nil
    ensure
      sub&.update!(stripe_schedule_id: nil, pending_plan_id: nil, pending_billing_interval: nil)
    end
  end
end
